<?php /** * Danltn | http://danltn.com/ * MSN: msn@danltn.com * Email: daniel@neville.tk * Started: 19/6/2008 16:01 (UK) * Tested: No * PHP 4/5: 5 * No warranty is given to code used */ /** * PingFM_Wrapper * * @package PingFM_Wrappers * @url http://danltn.com * @desc Package which allows easy interaction with the Ping.fm service * @author Daniel Neville * @copyright 2008 * @version 0.2b * @access public * @license GPL */ class PingFM_Wrapper { /** Your API */ public $dev_api; /** Users API */ public $user_api; /** Actual reply code */ public $reply; /** XML parsed with SimpleXML */ public $xml; /** Details array returned, this is what you should use */ public $details; /** Acceptable methods for API usage **/ static public $methods = array( 'validate', 'services', 'triggers', 'latest', 'message', 'tpost', 'post' ); /** Acceptable methods to use if we're using the post method **/ static public $post_methods = array( 'blog', 'microblog', 'status' ); /** All the URLs for different services **/ const VALIDATE_URL = 'http://api.ping.fm/v1/user.validate'; const SERVICES_URL = 'http://api.ping.fm/v1/user.services'; const TRIGGERS_URL = 'http://api.ping.fm/v1/user.triggers'; const MESSAGE_URL = 'http://api.ping.fm/v1/user.message'; const LATEST_URL = 'http://api.ping.fm/v1/user.latest'; const TPOST_URL = 'http://api.ping.fm/v1/user.tpost'; const POST_URL = 'http://api.ping.fm/v1/user.post'; /** * PingFM_Wrapper::__construct() * * @param mixed $dev_api Your developer API * @param mixed $user_api The users API * @param bool $check Should we run checks to make sure all the extensions are loaded? * @return void */ public function __construct( $dev_api = null, $user_api = null, $check = true ) { /** Construct class, runs on initialization **/ if ( $check ) { /** If the check parametre is set **/ if ( !extension_loaded('curl') /** Is the cURL extension loaded? **/ ) { throw new Exception( 'You don\'t have cURL loaded.' ); /** If not, throw an exception **/ } if ( !extension_loaded('SimpleXML') /** Is the SimpleXML extension loaded? **/ ) { throw new Exception( 'You don\'t have the SimpleXML lib loaded.' ); /** If not, throw an exception **/ } } /** if $dev_api and $user_api aren't the default values of null, set them in the class. **/ if ( !is_null($dev_api) ) $this->dev_api = $dev_api; if ( !is_null($user_api) ) $this->user_api = $user_api; } /** * PingFM_Wrapper::act() * * @param string $method What we're carrying, this is taken care of with the PingFM_Functions extension * @param mixed $extra_post_fields Any extra fields required, these are taken care of with the PingFM_Functions extension * @return bool $status Whether the action completed successfully or not */ public function act( $method = '', $extra_post_fields = array( /** You'll need to fill this in if you're using a method that needs more that just the API codes */ ) ) { if ( !in_array($method, self::$methods) ) throw new Exception( 'The selected method: ' . $method . ' is not supported by Ping.fm' ); /** Throw an error if the method isn't supported */ $extra_post_fields = $this->_check_fields( $method, $extra_post_fields ); /** Check all the fields are correct, if they're not fix them if we can. Otherwise we'll throw an exception (see method _check_fields() for more details.) */ $post = array_merge( array('api_key' => $this->dev_api, 'user_app_key' => $this->user_api), $extra_post_fields ); /** Merge the APIs with any extra post fields */ $ch = curl_init(); /** Start a cURL instance called $ch */ curl_setopt( $ch, CURLOPT_POST, true ); /** We will be sending POST fields, tell cURL that we are */ curl_setopt( $ch, CURLOPT_POSTFIELDS, $post ); /** Attach the POST fields themselves */ curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true ); /** Don't output to the browser */ curl_setopt( $ch, CURLOPT_URL, constant('self::' . strtoupper($method) . '_URL') ); /** What URL should we post to? */ $this->reply = curl_exec( $ch ); /** Get the raw reply, set it to $this->reply for access */ curl_close( $ch ); /** Free up the resources */ $this->_parse_reply( $method ); /** Parse it, see method below */ return ( $this->xml->attributes()->status == 'OK' or $this->xml->attributes()->status == '' ) ? true : false; /** Sometimes it glitches and a status isn't returned, if this happens, or it equals 'OK', return true. Else return false. */ } /** * PingFM_Wrapper::_parse_reply() * * @param string $method What method are we parsing for. * @return bool true Always true upon success */ protected function _parse_reply( $method ) { if ( !$this->reply ) throw new Exception( 'Raw reply could not be found.' ); $this->xml = $xml = simplexml_load_string( $this->reply ); /** Parse the raw reply, set it to XML for access from within this function, and to $this->xml if the programmer wants to access it later */ if ( $xml->attributes()->status == 'FAIL' ) throw new Exception( $this->xml->message ); $details['transaction'] = ( string )$xml->transaction; switch ( $method ): case 'validate': case 'post': case 'tpost': /** Nothing to do! - All it returns is the method and the transaction ID. */ break; /** End validate, post, tpost */ case 'services': $details['number_of_services'] = ( int )count( $xml->services->service ); if ( $details['number_of_services'] > 0 ) { foreach ( $xml->services->service as $service ) { $name = ( string )$service->attributes()->id; $details['services'][$name]['name'] = ( string )$service->attributes()->name; $method = ( string )$service->methods; $methods = ( strstr($method, ',') ) ? explode( ',', $method ) : $method; if ( is_array($methods) ) { foreach ( $methods as $method ) { $details['services'][$name]['methods'][] = ( string )$method; } } else if ( is_string($methods) ) { $details['services'][$name]['methods'][] = ( string )$method; } $details['services'][$name]['number_of_methods'] = count( $details['services'][$name]['methods'] ); } } break; /** End services */ case 'triggers': $details['number_of_triggers'] = ( int )count( $xml->triggers->trigger ); if ( $details['number_of_triggers'] > 0 ) { foreach ( $xml->triggers->trigger as $trigger ) { $name = ( string )$trigger->attributes()->id; $details['triggers'][$name]['name'] = ( string )$trigger->attributes()->id; $details['triggers'][$name]['method'] = ( string )$trigger->attributes()->method; $details['triggers'][$name]['number_of_affected_services'] = count( $trigger->services->service ); if ( $details['triggers'][$name]['number_of_affected_services'] > 0 ) { foreach ( $trigger->services->service as $service ) { $id = ( string )$service->attributes()->id; $details['triggers'][$name]['services'][$id] = ( string )$service->attributes()->name; } } } } break; /** End triggers */ case 'latest': $details['number_of_messages_returned'] = ( int )count( $xml->messages->message ); if ( $details['number_of_messages_returned'] > 0 ) { foreach ( $xml->messages->message as $message ) { $id = ( string )$message->attributes()->id; $details['messages'][$id]['id'] = ( string )$id; $details['messages'][$id]['method'] = ( string )$message->attributes()->method; $details['messages'][$id]['date']['unix'] = ( string )$message->date->attributes()->unix; $details['messages'][$id]['date']['rfc'] = ( string )$message->date->attributes()->rfc; $details['messages'][$id]['body'] = base64_decode( (string )$message->content->body ); $details['messages'][$id]['number_of_services'] = ( int )count( $message->services->service ); if ( $details['messages'][$id]['number_of_services'] > 0 ) { foreach ( $message->services->service as $service ) { $sid = ( string )$service->attributes()->id; $details['messages'][$id]['services'][$sid] = ( string )$service->attributes()->name; } } } } break; /** End latest */ case 'message': $message = $xml->message; $details['id'] = ( string )$message->attributes()->id; $details['method'] = ( string )$message->attributes()->method; $details['date']['unix'] = ( string )$message->date->attributes()->unix; $details['date']['rfc'] = ( string )$message->date->attributes()->rfc; $details['body'] = base64_decode( (string )$message->content->body ); $details['number_of_services'] = ( int )count( $message->services->service ); if ( $details['number_of_services'] > 0 ) { foreach ( $message->services->service as $service ) { $sid = ( string )$service->attributes()->id; $details['services'][$sid] = ( string )$service->attributes()->name; } } break; /** End message */ endswitch; $this->details = $details; return true; } /** * PingFM_Wrapper::_check_fields() * * @param string $method This is used within the class, no need to use this. * @param string $fields This is used within the class, no need to use this. * @return array $fields Fixed fields */ protected function _check_fields( $method, $fields ) { if ( in_array($method, array('validate', 'services', 'triggers')) ) return array(); /** These don't require extra post fields */ switch ( $method ): case 'latest': /** Start latest */ if ( !empty($fields['limit']) ) /** It's optional, only enforce it if it's an non-empty value */ { $fields['limit'] = intval( $fields['limit'] ); /** Has to be an integer */ if ( $fields['limit'] < 0 ) /** If it's less than 0 (aka Invalid)... */ { $fields['limit'] = 25; /** Set it to the default: 25 */ } } if ( !empty($fields['order']) ) /** As above */ { $fields['order'] = strtoupper( $fields['order'] ); /** It takes ASC or DESC values, make it uppercase just in case */ if ( $fields['order'] != 'ASC' and $fields['order'] != 'DESC' ) /** If it's not one of the acceptable values */ { $fields['order'] = 'DESC'; /** Then set it to the default */ } } break; /** End latest */ case 'message': /** Start message */ if ( empty($fields['message_id']) ) throw new Exception( 'No message_id specified.' ); /** If (the required field) message_id is not set, throw an exception */ else /** Otherwise... check if it's good to go */ { $fields['message_id'] = intval( $fields['message_id'] ); /** It like totally has to be an integer */ if ( $fields['message_id'] < 0 ) throw new Exception( 'message_id is an invalid negative value.' ); /** If it's less than 0, throw an exception */ } break; /** End message */ case 'post': /** Start post */ if ( empty($fields['post_method']) ) throw new Exception( 'post_method is not set.' ); /** If post_method is not set, or it is not an acceptable value. Throw an error showing acceptable values */ $fields['post_method'] = strtolower( $fields['post_method'] ); /** Make it lower */ if ( !in_array($fields['post_method'], self::$post_methods) ) throw new Exception( 'post_method is not an acceptable value: ' . implode(', ', $this->$post_methods) ); if ( empty($fields['body']) ) throw new Exception( 'No body set' ); if ( $fields['post_method'] == 'status' ) /** If it's a status */ { $fields['body'] = substr( strip_tags($fields['body']), 0, 200 ); /** Max 200 chars, tags are stripped - Reflected in above code */ if ( isset($fields['title']) ) unset( $fields['title'] ); /** It's a status, so we don't need the title, remove it */ } /** End status */ if ( $fields['post_method'] == 'blog' ) /** If it's a blog */ { if ( empty($fields['title']) ) throw new Exception( 'A title is required for blogging.' ); /** 'blog' option requires a title to be set. */ $fields['title'] = strip_tags( $fields['title'] ); /** Can't have tags in the title itself */ } /** End blog */ if ( $fields['post_method'] == 'microblog' ) { /** If it's a microblog */ $fields['body'] = substr( strip_tags($fields['body']), 0, 140 ); /** Max 140 chars, tags are stripped - Reflected in above code */ if ( isset($fields['title']) ) unset( $fields['title'] ); /** It's a microblog, so we don't need the title, remove it */ } /** End microblog */ if ( is_array($fields['service']) ) /** If it's an array */ { $fields['service'] = array_map( 'trim', $fields['service'] ); /** Remove all excess spaces */ $fields['service'] = implode( ',', $fields['service'] ); /** And implode with comma */ } elseif ( is_string($fields['service']) ) /** If it's a string */ { if ( strlen($fields['service']) < 1 ) /** If it's a zero length string... */ { unset( $fields['service'] ); /** Then we don't want it - it's optional */ } } if ( $fields['debug'] ) $fields['debug'] = 1; /** If debug is equal to true, set it to 1 so we don't post data */ else unset( $fields['debug'] ); /** Otherwise it's optional... unset it */ break; /** End message */ case 'tpost': /** Start tpost */ if ( empty($fields['trigger']) ) throw new Exception( 'No trigger set.' ); /** You have to set a trigger, otherwise throw an exception */ if ( empty($fields['body']) ) throw new Exception( 'No body set.' ); /** You have to set a body, otherwise throw an exception */ if ( $fields['debug'] ) $fields['debug'] = 1; /** If debug is equal to true, set it to 1 so we don't post data */ else unset( $fields['debug'] ); /** Otherwise it's optional... unset it */ break; /** End tpost */ endswitch; return $fields; } } /** * PingFM_Functions * * @package PingFM_Wrappers * @url http://danltn.com * @desc Set of methods which allow easy access to the Wrapper class * @author Daniel Neville * @copyright 2008 * @version 0.2b * @access public * @license GPL */ class PingFM_Functions extends PingFM_Wrapper { /** * PingFM_Functions::__construct() * * @param mixed $dev_api * @param mixed $user_api * @param bool $check * @return void */ public function __construct( $dev_api = null, $user_api = null, $check = true ) { parent::__construct( $dev_api, $user_api, $check ); } /** * PingFM_Functions::validate() * * @return bool $success Whether it ran successfully or not */ public function validate() { return $this->act( 'validate' ); } /** * PingFM_Functions::services() * * @return bool $success Whether it ran successfully or not */ public function services() { return $this->act( 'services' ); } /** * PingFM_Functions::triggers() * * @return bool $success Whether it ran successfully or not */ public function triggers() { return $this->act( 'triggers' ); } /** * PingFM_Functions::latest() * * @param integer $limit How many records should we return * @param string $order What order (ASC or DESC) * @return bool $success Whether it ran successfully or not */ public function latest( $limit = 25, $order = 'ASC' ) { return $this->act( 'latest', array('limit' => $limit, 'order' => $order) ); } /** * PingFM_Functions::message() * * @param integer $id What message to return information about * @return bool $success Whether it ran successfully or not */ public function message( $id ) { return $this->act( 'message', array('message_id' => $id) ); } /** * PingFM_Functions::post() * * @param string $post_method What post method are we using? * @param string $body Body of the post request * @param string $title Title (optional but required for blog) * @param mixed $service Service to affect (optional) * @param integer $debug Should we actually post, or is this just testing (1 for testing) * @return bool $success Whether it ran successfully or not */ public function post( $post_method, $body, $title = '', $service = array(''), $debug = 0 ) { return $this->act( 'post', array('body' => $body, 'post_method' => $post_method, 'title' => $title, 'service' => $service, 'debug' => $debug) ); } /** * PingFM_Functions::tpost() * * @param string $trigger What trigger shall will use * @param string $body Body of the post request * @param string $title Title (optional but required for blog) * @param integer $debug Should we actually post, or is this just testing (1 for testing) * @return bool $success Whether it ran successfully or not */ public function tpost( $trigger, $body, $title = '', $debug = 0 ) { return $this->act( 'tpost', array('trigger' => $trigger, 'body' => $body, 'title' => $title, 'debug' => $debug) ); } } ?>