Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added initial release with methods for get(), getAll() and getAllLang…

…uages(). Includes tests and README documentation.
  • Loading branch information...
commit c5b4fbfc4d7851d7e66d493285b52ec01210dec3 1 parent ef11978
@benjaminpearson authored
View
103 README
@@ -0,0 +1,103 @@
+Snipplr API PHP Library
+
+A small library that allows interaction with Snipplr's API. Designed to be used in PHP projects or as a CakePHP vendor. When using this library its highly recommended that you cache your results, visit CakePHP Cache page: http://book.cakephp.org/view/767/Cache-write
+
+QUIRKS
+----------------------------------------------------------------------------------------
+1. In getAll method: Multiple tags don't seem to work in the Snipplr API. Only the last tag will be used.
+2. In getAll method: Limit of 0 or 1 appears to return all snippets (ie, not limited)
+
+
+USAGE
+----------------------------------------------------------------------------------------
+
+CakePHP:
+App::import('Vendor', 'SnipplrCore', array('file' => 'snipplr-api-php'.DS.'snipplr.core.php'));
+$SnipplrCore = new SnipplrCore();
+$snippet = $SnipplrCore->get('18153');
+$snippets = $SnipplrCore->getAll();
+$languages = $SnipplrCore->getAllLanguages();
+
+PHP:
+require_once "snipplr-api-php".DIRECTORY_SEPARATOR."snipplr.core.php";
+$SnipplrCore = new SnipplrCore();
+$snippet = $SnipplrCore->get('18153');
+$snippets = $SnipplrCore->getAll();
+$languages = $SnipplrCore->getAllLanguages();
+
+
+OUTPUT
+----------------------------------------------------------------------------------------
+
+Method Call: get('18153');
+Example Output:
+ Array
+ (
+ [id] => 18153
+ [user_id] => 11806
+ [username] => benjaminpearson
+ [title] => CakePHP highlight active menu item for page
+ [language] => Other
+ [comment] =>
+ [created] => 2009-08-11 00:35:14
+ [updated] => 2009-11-14 15:56:18
+ [source] => <ul>
+ <li class="<?php if($this->viewVars['page'] == 'home') { echo 'active'; } ?>"><?php echo $html->link('Home', '/') ?></li>
+ </ul>
+ [tags] => Array
+ (
+ [0] => textmate
+ [1] => cakephp
+ )
+ [snipplr_url] => http://snipplr.com/view/18153/cakephp-highlight-active-menu-item-for-page
+ )
+
+
+Method Call: getAll();
+Example Output:
+ Array
+ (
+ [0] => Array
+ (
+ [id] => 22696
+ [title] => Sinatra Ajax Layout
+ [updated] => Array
+ (
+ [datetime] => 20091107T07:47:12
+ [timezone] => -05:00 EST
+ )
+ [private] => 0
+ [favourite] => 0
+ )
+
+ [1] => Array
+ (
+ [id] => 22385
+ [title] => jQuery Log Function
+ [updated] => Array
+ (
+ [datetime] => 20091103T08:12:37
+ [timezone] => -05:00 EST
+ )
+ [private] => 0
+ [favourite] => 0
+ )
+ ..etc
+ )
+
+Method Call: getAllLanguages();
+Example Output:
+ Array
+ (
+ [0] => Array
+ (
+ [slug] => actionscript
+ [name] => ActionScript
+ )
+ [1] => Array
+ (
+ [slug] => actionscript-3
+ [name] => ActionScript 3
+ )
+ ...etc
+ )
View
77 helpers/snipplr.response.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * A Response Helper that manipulates the response XML into formatted arrays for ease of use.
+ * The responses received from Snipplr follow a set structure. Each method attempts to format
+ * this structure for use in your application. If a response doesn't match the structure
+ * defined, an error is assumed. If Snipplr changes the output of their responses in future updates,
+ * this file will also need to be updated.
+ */
+
+class SnipplrResponse
+{
+ function processSnippetGetResponse($response) {
+ $formatted = array();
+
+ // if response is in correct array structure then process it, else return empty array
+ if(isset($response['params']['param']['value']['struct']['member'])) {
+ $item = $response['params']['param']['value']['struct']['member'];
+ $formatted = array(
+ 'id' => $item[0]['value']['string'],
+ 'user_id' => $item[1]['value']['string'],
+ 'username' => $item[2]['value']['string'],
+ 'title' => $item[3]['value']['string'],
+ 'language' => $item[4]['value']['string'],
+ 'comment' => $item[5]['value']['string'],
+ 'created' => $item[6]['value']['string'],
+ 'updated' => $item[7]['value']['string'],
+ 'source' => $item[8]['value']['string'],
+ 'tags' => explode(" ", trim($item[9]['value']['string'])),
+ 'snipplr_url' => $item[10]['value']['string']
+ );
+ }
+
+ return $formatted;
+ }
+
+ function processSnippetListResponse($response) {
+ $formatted = array();
+
+ // if response is in correct array structure then process it, else return empty array
+ if(isset($response['params']['param']['value']['array']['data']['value'])) {
+ foreach($response['params']['param']['value']['array']['data']['value'] as $item) {
+ $item = $item['struct']['member'];
+
+ $datetime = new DateTime($item[2]['value']['struct']['member'][0]['value']['dateTime.iso8601']);
+
+ $formatted[] = array(
+ 'id' => $item[0]['value']['string'],
+ 'title' => $item[1]['value']['string'],
+ 'updated' => array(
+ 'datetime' => $datetime->format('Y-m-d h:m:s'),
+ 'timezone' => $item[2]['value']['struct']['member'][1]['value']['string'],
+ ),
+ 'private' => $item[3]['value']['boolean'],
+ 'favourite' => $item[4]['value']['boolean'],
+ );
+ }
+ }
+
+ return $formatted;
+ }
+
+ function processLanguagesListResponse($response) {
+ $formatted = array();
+ // if response is in correct array structure then process it, else return empty array
+ if(isset($response['params']['param']['value']['struct']['member'])) {
+ foreach($response['params']['param']['value']['struct']['member'] as $item) {
+ $formatted[] = array(
+ 'slug' => $item['name'],
+ 'name' => $item['value']['string']
+ );
+ }
+ }
+
+ return $formatted;
+ }
+}
+?>
View
91 helpers/snipplr.rest.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * A REST Helper that prepares and sends data to API URLs.
+ * Snipplr only uses POST requests which require XML structured data to be sent to them.
+ *
+ */
+
+require_once('snipplr.xml.php');
+require_once('snipplr.response.php');
+
+class SnipplrRest
+{
+ var $api_key;
+ var $url = 'http://snipplr.com/xml-rpc.php';
+ var $SnipplrXML;
+ var $SnipplrResponse;
+
+ function SnipplrRest($api_key) {
+ $this->api_key = $api_key;
+ $this->SnipplrXML = new SnipplrXML();
+ $this->SnipplrResponse = new SnipplrResponse();
+ }
+
+ // Snipplr API only uses post calls. This manages the steps involved.
+ function post($method, $params = array()) {
+ try {
+ $xml = $this->_constructXML($method, $params);
+ $response = $this->_httpPost($this->url, $xml);
+ return $this->_processResponse($method, $response);
+ } catch (Exception $e) {
+ return null;
+ }
+ }
+
+ // Contructs an XML object in the format required by Snipplr
+ function _constructXML($method, $params = array()) {
+ // list of methods that require an api key
+ $api_key_required_methods = array('snippet.list');
+
+ // set the methodName for xml query
+ $xml_data['methodName'] = $method;
+
+ // if method requires api key then add it
+ if(in_array($method, $api_key_required_methods)) {
+ $xml_data['params']['param'][] = array(
+ 'key' => "api_key",
+ 'value' => $this->api_key
+ );
+ }
+
+ // add all other specified params
+ foreach($params as $key => $value) {
+ $xml_data['params']['param'][] = array(
+ 'key' => $key,
+ 'value' => $value
+ );
+ }
+
+ return $this->SnipplrXML->toXML($xml_data, 'methodCall');
+ }
+
+ // Makes a generic http post request
+ function _httpPost($url, $data) {
+ $c = curl_init();
+ curl_setopt($c, CURLOPT_URL, $url);
+ curl_setopt($c, CURLOPT_POST, 1);
+ curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true);
+ curl_setopt($c, CURLOPT_POSTFIELDS, $data);
+ curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
+ $output = curl_exec($c);
+ curl_close($c);
+ return $output;
+ }
+
+ // Processes the xml
+ function _processResponse($method, $response) {
+ $raw = $this->SnipplrXML->toArray($response);
+
+ switch($method) {
+ case 'snippet.get':
+ return $this->SnipplrResponse->processSnippetGetResponse($raw);
+ case 'snippet.list':
+ return $this->SnipplrResponse->processSnippetListResponse($raw);
+ case 'languages.list':
+ return $this->SnipplrResponse->processLanguagesListResponse($raw);
+ default:
+ return null;
+ }
+ }
+}
+?>
View
117 helpers/snipplr.xml.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ * An XML Helper that allows conversion between arrays and XML objects.
+ * This version isn't specific for Snipplr and can be transported to other applications by changing
+ * the classname and appropriate static class name calls in the code. "SnipplrXML" is used as a pseudo namespace.
+ *
+ * Originating Source: http://snipplr.com/view/3491/convert-php-array-to-xml-or-simple-xml-object-if-you-wish/
+ */
+class SnipplrXML
+{
+ /**
+ * The main function for converting to an XML document.
+ * Pass in a multi dimensional array and this recursively loops through and builds up an XML document.
+ *
+ * @param array $data
+ * @param string $rootNodeName - what you want the root node to be - defaults to data.
+ * @param SimpleXMLElement $xml - should only be used recursively
+ * @return string XML
+ */
+ public static function toXML($data, $rootNodeName = 'ResultSet', &$xml = null) {
+ // turn off compatibility mode as simple xml throws a wobbly if you don't.
+ if(ini_get('zend.ze1_compatibility_mode') == 1) {
+ ini_set('zend.ze1_compatibility_mode', 0);
+ }
+
+ if(is_null($xml)) {
+ $xml = simplexml_load_string("<?xml version='1.0' encoding='utf-8'?><$rootNodeName/>");
+ }
+
+ // loop through the data passed in.
+ foreach($data as $key => $value) {
+ // no numeric keys in our xml please!
+ $numeric = 0;
+ if(is_numeric($key)) {
+ $numeric = 1;
+ $key = $rootNodeName;
+ }
+
+ // delete any char not allowed in XML element names
+ $key = preg_replace('/[^a-z0-9\-\_\.\:]/i', '', $key);
+
+ // if there is another array found recrusively call this function
+ if(is_array($value)) {
+ $node = SnipplrXML::isAssoc($value) || $numeric ? $xml->addChild($key) : $xml;
+
+ // recrusive call.
+ if($numeric) {
+ $key = 'anon';
+ }
+ SnipplrXML::toXml($value, $key, $node);
+ } else {
+ // add single node.
+ $value = htmlentities($value);
+ $xml->addChild($key, $value);
+ }
+ }
+
+ // pass back as XML
+ return $xml->asXML();
+ }
+
+
+ /**
+ * Convert an XML document to a multi dimensional array
+ * Pass in an XML document (or SimpleXMLElement object) and this recrusively loops through and builds a representative array
+ *
+ * @param string $xml - XML document - can optionally be a SimpleXMLElement object
+ * @return array ARRAY
+ */
+ public static function toArray( $xml ) {
+ if(is_string($xml)) {
+ $xml = new SimpleXMLElement( $xml );
+ }
+
+ $children = $xml->children();
+
+ if(!$children) {
+ return (string) $xml;
+ }
+
+ $arr = array();
+ $adjusted = array(); // used to determine if a node has been converted to an array of nodes
+ foreach($children as $key => $node) {
+ $node = SnipplrXML::toArray($node);
+
+ // support for 'anon' non-associative arrays
+ if($key == 'anon') {
+ $key = count($arr);
+ }
+
+ // if the node is already set, put it into an array
+ if(isset($arr[$key])) {
+ if(isset($adjusted[$key]) && $adjusted[$key] == false) {
+ $first_value = $arr[$key];
+ $arr[$key] = array();
+ $arr[$key][] = $first_value;
+ $adjusted[$key] = true;
+ }
+
+ if(!is_array($arr[$key]) || (isset($arr[$key][0]) && $arr[$key][0] == null)) {
+ $arr[$key] = array( $arr[$key] );
+ }
+ $arr[$key][] = $node;
+ } else {
+ $arr[$key] = $node;
+ $adjusted[$key] = false;
+ }
+ }
+ return $arr;
+ }
+
+ // determine if a variable is an associative array
+ public static function isAssoc( $array ) {
+ return (is_array($array) && 0 !== count(array_diff_key($array, array_keys(array_keys($array)))));
+ }
+}
+?>
View
11 snipplr.config.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * Configuration for Snipplr
+ * SnipplrCore can be instantiated with a passed api_key or it will default to the one below.
+ * Initially this used Configure::write() method but that coupled it with CakePHP. Using defined
+ * constants should allow for it to work outside the CakePHP framework.
+ */
+
+define('SNIPPLR_API_KEY', 'yourapikeyhere');
+
+?>
View
88 snipplr.core.php
@@ -0,0 +1,88 @@
+<?php
+/**
+ * This is the mothership file. Create an instance of this and you'll have access to the API methods defined below.
+ * Add new API methods as they become available. Each method contains documentation about the params and return values.
+ */
+
+require_once('helpers'.DIRECTORY_SEPARATOR.'snipplr.rest.php');
+require_once('snipplr.config.php');
+
+class SnipplrCore
+{
+ var $SnipplrRest;
+
+ function SnipplrCore($api_key = SNIPPLR_API_KEY) {
+ $this->SnipplrRest = new SnipplrRest($api_key);
+ }
+
+ /*
+ Gets a single snippet with more detail than a "getAll" call.
+
+ Returns
+ - id
+ - user_id
+ - username
+ - title
+ - language
+ - comment
+ - created
+ - updated
+ - source
+ - tags (space delimited list of the snippet’s tags)
+ - snipplr_url
+
+ Params
+ snippet_id (required) The ID of the snippet to fetch. An error message will be returned if the ID is invalid.
+ */
+ function get($snippet_id) {
+ $snippet = $this->SnipplrRest->post('snippet.get', compact('snippet_id'));
+ return $snippet;
+ }
+
+ /*
+ Gets all snippets owned by the user or marked as favorites of the user. Note: It doesn't search all
+ of the snippets on Snipplr.
+
+ Returns and array of snippets with following fields
+ - id
+ - title
+ - updated['datetime']
+ - updated['timezone']
+ - private (boolean)
+ - favorite (boolean)
+
+ Params:
+ options['tags'] (optional) NOTE: Multiple tags don't seem to work in the Snipplr API. Only the last tag will be used.
+ A space delimited list of tags (keywords) to filter the results by.
+ Returns snippets which contain at least one of the keywords in the snippet’s
+ title or that match one of the snippet’s tags.
+ options['sort'] (optional) Can be one of these three values: “title”, “date”, “random”.
+ options['limit'] (optional) The number of snippets to return. A limit of 0 or 1 appears to return unlimited snippets.
+
+ */
+ function getAll($options = array()) {
+ // Multiple tags don't seem to work in the Snipplr API. Only the last tag will be used.
+ $tags = isset($options['tags']) ? $options['tags'] : "";
+ $sort = isset($options['sort']) ? $options['sort'] : "date";
+ $limit = isset($options['limit']) ? $options['limit'] : "";
+
+ $snippets = $this->SnipplrRest->post('snippet.list', compact('tags','sort','limit'));
+ return $snippets;
+ }
+
+ /*
+ Gets all languages that Snipplr uses.
+
+ Returns and array of languages with following fields
+ - slug This id can be used when adding snippets
+ - name The more human meaningful name of the language
+
+ Params: -
+
+ */
+ function getAllLanguages() {
+ $snippets = $this->SnipplrRest->post('languages.list');
+ return $snippets;
+ }
+}
+?>
View
72 tests/snipplr.core.cakemate.test.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Tests for snipplr.core.php
+ * This test case is specific for CakePHP and requires CakeMate (Textmate plugin) in order to be run.
+ * It allows you to easily debug the output of method calls and also validate that you config settings
+ * are valid and working correctly.
+ *
+ * CakeMate URL: http://mark-story.com/posts/view/running-cakephp-unit-tests-with-textmate
+ */
+
+require_once('..'.DIRECTORY_SEPARATOR.'snipplr.core.php');
+
+class SnipplrCoreTest extends UnitTestCase {
+ var $SnipplrCore;
+
+
+ function setup() {
+ $this->SnipplrCore = new SnipplrCore();
+ }
+
+ function testGet() {
+ $snippet = $this->SnipplrCore->get("18153");
+ $this->assertTrue(isset($snippet['id']));
+ //debug($snippet);
+ }
+
+ function testGetNotFound() {
+ $snippet = $this->SnipplrCore->get("00000");
+ $this->assertTrue(empty($snippet));
+ //debug($snippet);
+ }
+
+ function testGetAll() {
+ $snippets = $this->SnipplrCore->getAll();
+ $this->assertTrue(isset($snippets[0]['id']));
+ $this->assertTrue(isset($snippets[1]['id']));
+ //debug($snippets);
+ }
+
+ function testGetAllOptionTags() {
+ // Multiple tags don't seem to work in the Snipplr API. Only the last tag will be used.
+ $snippets = $this->SnipplrCore->getAll(array('tags' => 'css'));
+ //debug($snippets);
+ }
+
+ function testGetAllOptionSortTitle() {
+ $snippets = $this->SnipplrCore->getAll(array('sort' => 'title'));
+ // check its in alphabetical order against php sort method
+ $titles = array();
+ foreach($snippets as $snippet) {
+ $titles[] = strtoupper($snippet['title']);
+ }
+ $sort_titles = $titles;
+ sort($sort_titles);
+ $this->assertEqual($titles, $sort_titles);
+ //debug($snippets);
+ }
+
+ function testGetAllOptionLimit() {
+ $snippets = $this->SnipplrCore->getAll(array('limit' => '4'));
+ $this->assertEqual(sizeof($snippets), 4);
+ //debug($snippets);
+ }
+
+ function testGetAllLanguages() {
+ $languages = $this->SnipplrCore->getAllLanguages();
+ $this->assertEqual($languages[0]['slug'], 'actionscript');
+ $this->assertEqual($languages[0]['name'], 'ActionScript');
+ //debug($languages);
+ }
+}
+?>
View
73 tests/snipplr.core.phpunit.test.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Tests for snipplr.core.php
+ * This test case is specific for PHPUnit and requires the phpunit PEAR package.
+ * It allows you to easily debug the output of method calls and also validate that you config settings
+ * are valid and working correctly.
+ *
+ * Command line: phpunit SnipplrCoreTest snipplr.core.phpunit.test.php
+ */
+
+require_once 'PHPUnit'.DIRECTORY_SEPARATOR.'Framework.php';
+require_once '..'.DIRECTORY_SEPARATOR.'snipplr.core.php';
+
+class SnipplrCoreTest extends PHPUnit_Framework_TestCase
+{
+ protected $SnipplrCore = null;
+
+ function setUp() {
+ $this->SnipplrCore = new SnipplrCore();
+ }
+
+ function testGet() {
+ $snippet = $this->SnipplrCore->get("18153");
+ $this->assertTrue(isset($snippet['id']));
+ //print_r($snippet);
+ }
+
+ function testGetNotFound() {
+ $snippet = $this->SnipplrCore->get("00000");
+ $this->assertTrue(empty($snippet));
+ //print_r($snippet);
+ }
+
+ function testGetAll() {
+ $snippets = $this->SnipplrCore->getAll();
+ $this->assertTrue(isset($snippets[0]['id']));
+ $this->assertTrue(isset($snippets[1]['id']));
+ //print_r($snippets);
+ }
+
+ function testGetAllOptionTags() {
+ // Multiple tags don't seem to work in the Snipplr API. Only the last tag will be used.
+ $snippets = $this->SnipplrCore->getAll(array('tags' => 'css'));
+ //print_r($snippets);
+ }
+
+ function testGetAllOptionSortTitle() {
+ $snippets = $this->SnipplrCore->getAll(array('sort' => 'title'));
+ // check its in alphabetical order against php sort method
+ $titles = array();
+ foreach($snippets as $snippet) {
+ $titles[] = strtoupper($snippet['title']);
+ }
+ $sort_titles = $titles;
+ sort($sort_titles);
+ $this->assertEquals($titles, $sort_titles);
+ //print_r($snippets);
+ }
+
+ function testGetAllOptionLimit() {
+ $snippets = $this->SnipplrCore->getAll(array('limit' => '4'));
+ $this->assertEquals(sizeof($snippets), 4);
+ //print_r($snippets);
+ }
+
+ function testGetAllLanguages() {
+ $languages = $this->SnipplrCore->getAllLanguages();
+ $this->assertEquals($languages[0]['slug'], 'actionscript');
+ $this->assertEquals($languages[0]['name'], 'ActionScript');
+ //print_r($languages);
+ }
+}
+?>
Please sign in to comment.
Something went wrong with that request. Please try again.