Services_Twitter
[ class tree: Services_Twitter ] [ index: Services_Twitter ] [ all elements ]

Source for file Twitter.php

Documentation is available at Twitter.php

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * An interface for Twitter's REST API and Search API.
  7.  *
  8.  * PHP version 5.1.0+
  9.  *
  10.  * @category  Services
  11.  * @package   Services_Twitter
  12.  * @author    Joe Stump <joe@joestump.net>
  13.  * @author    David Jean Louis <izimobil@gmail.com>
  14.  * @author    Bill Shupp <shupp@php.net>
  15.  * @copyright 1997-2008 Joe Stump <joe@joestump.net>
  16.  * @license   http://www.opensource.org/licenses/bsd-license.php New BSD License
  17.  * @version   SVN: $Id: Twitter.php 40 2009-01-07 12:40:35Z izimobil $
  18.  * @link      http://twitter.com
  19.  * @link      http://apiwiki.twitter.com
  20.  * @filesource
  21.  */
  22.  
  23. /**
  24.  * Include HTTP_Request2 class and exception classes.
  25.  */
  26. require_once 'HTTP/Request2.php';
  27. require_once 'Services/Twitter/Exception.php';
  28.  
  29. /**
  30.  * Base class for interacting with Twitter's API.
  31.  *
  32.  * Here's a basic auth example:
  33.  *
  34.  * <code>
  35.  * require_once 'Services/Twitter.php';
  36.  *
  37.  * $username = 'Your_Username';
  38.  * $password = 'Your_Password';
  39.  *
  40.  * try {
  41.  *     $twitter = new Services_Twitter($username, $password);
  42.  *     $msg = $twitter->statuses->update("I'm coding with PEAR right now!");
  43.  *     print_r($msg);
  44.  * } catch (Services_Twitter_Exception $e) {
  45.  *     echo $e->getMessage();
  46.  * }
  47.  *
  48.  * </code>
  49.  *
  50.  * Here's an OAuth example:
  51.  *
  52.  * <code>
  53.  * require_once 'Services/Twitter.php';
  54.  * require_once 'HTTP/OAuth/Consumer.php';
  55.  *
  56.  *
  57.  * try {
  58.  *     $twitter = new Services_Twitter();
  59.  *     $oauth   = new HTTP_OAuth_Consumer('consumer_key',
  60.  *                                        'consumer_secret',
  61.  *                                        'auth_token',
  62.  *                                        'token_secret');
  63.  *     $twitter->setOAuth($oauth);
  64.  *
  65.  *     $msg = $twitter->statuses->update("I'm coding with PEAR right now!");
  66.  *     print_r($msg);
  67.  * } catch (Services_Twitter_Exception $e) {
  68.  *     echo $e->getMessage();
  69.  * }
  70.  *
  71.  * </code>
  72.  * @category Services
  73.  * @package  Services_Twitter
  74.  * @author   Joe Stump <joe@joestump.net>
  75.  * @author   David Jean Louis <izimobil@gmail.com>
  76.  * @license  http://www.opensource.org/licenses/bsd-license.php New BSD License
  77.  * @link     http://twitter.com
  78.  * @link     http://apiwiki.twitter.com
  79.  */
  80. {
  81.     // constants {{{
  82.  
  83.     /**#@+
  84.      * Exception codes constants defined by this package.
  85.      *
  86.      * @global integer ERROR_UNKNOWN  An unknown error occurred
  87.      * @global integer ERROR_ENDPOINT Bad endpoint
  88.      * @global integer ERROR_PARAMS   Bad endpoint parameters
  89.      */
  90.     const ERROR_UNKNOWN  = 1;
  91.     const ERROR_ENDPOINT = 2;
  92.     const ERROR_PARAMS   = 3;
  93.     /**#@-*/
  94.  
  95.     /**#@+
  96.      * Twitter API output parsing options
  97.      *
  98.      * @global string OUTPUT_XML  The response is expected to be XML
  99.      * @global string OUTPUT_JSON The response is expected to be JSON
  100.      */
  101.     const OUTPUT_XML  = 'xml';
  102.     const OUTPUT_JSON = 'json';
  103.     /**#@-*/
  104.  
  105.     // }}}
  106.     // properties {{{
  107.  
  108.     /**
  109.      * Public URI of Twitter's API
  110.      *
  111.      * @var string $uri 
  112.      */
  113.     public static $uri 'http://twitter.com';
  114.  
  115.     /**
  116.      * Public URI of Twitter's Search API
  117.      *
  118.      * @var string $uri 
  119.      */
  120.     public static $searchUri 'http://search.twitter.com';
  121.  
  122.     /**
  123.      * Username of Twitter user
  124.      *
  125.      * @var string $user Twitter username
  126.      * @see Services_Twitter::__construct()
  127.      */
  128.     protected $user = '';
  129.  
  130.     /**
  131.      * Password of Twitter user
  132.      *
  133.      * @var string $pass User's password for Twitter
  134.      * @see Services_Twitter::__construct()
  135.      */
  136.     protected $pass = '';
  137.  
  138.     /**
  139.      * Optional instance of HTTP_OAuth_Consumer
  140.      * 
  141.      * @var HTTP_OAuth_Consumer $oauth 
  142.      * @see HTTP_OAuth_Consumer
  143.      */
  144.     protected $oauth = null;
  145.  
  146.     /**
  147.      * Options for HTTP requests and misc.
  148.      *
  149.      * Available options are:
  150.      * - format: the desired output format: json (default) or xml,
  151.      * - raw_format: if set to true, the configured format is returned "as is",
  152.      * - source: you can set this if you have registered a twitter source
  153.      *   {@see http://twitter.com/help/request_source}, your source will be
  154.      *   passed with each POST request,
  155.      * - use_ssl: whether to send all requests over ssl or not. If set to true, the
  156.      *   script will replace the http:// URL scheme with https://,
  157.      * - validate: if set to true the class will validate api xml file against
  158.      *   the RelaxNG file (you should not need this unless you are hacking
  159.      *   Services_Twitter...).
  160.      *
  161.      * These options can be set either by passing them directly to the
  162.      * constructor as an array (3rd parameter), or by using the setOption() or
  163.      * setOptions() methods.
  164.      *
  165.      * @var array $options 
  166.      * @see Services_Twitter::__construct()
  167.      * @see Services_Twitter::setOption()
  168.      * @see Services_Twitter::setOptions()
  169.      */
  170.     protected $options = array(
  171.         'format'     => self::OUTPUT_JSON,
  172.         'raw_format' => false,
  173.         'source'     => 'pearservicestwitter',
  174.         'use_ssl'    => false,
  175.         'validate'   => false,
  176.     );
  177.  
  178.     /**
  179.      * The HTTP_Request2 instance, you can customize the request if you want to
  180.      * (proxy, auth etc...) with the get/setRequest() methods.
  181.      *
  182.      * @var HTTP_Request2 $request 
  183.      * @see Services_Twitter::getRequest()
  184.      * @see Services_Twitter::setRequest()
  185.      */
  186.     protected $request = null;
  187.  
  188.     /**
  189.      * The Twitter API mapping array, used internally to retrieve infos about
  190.      * the API categories, endpoints, parameters, etc...
  191.      *
  192.      * The mapping is constructed with the api.xml file present in the
  193.      * Services_Twitter data directory.
  194.      *
  195.      * @var array $api Twitter api array
  196.      * @see Services_Twitter::__construct()
  197.      * @see Services_Twitter::prepareRequest()
  198.      */
  199.     protected $api = array();
  200.  
  201.     /**
  202.      * Used internally by the __get() and __call() methods to identify the
  203.      * current call.
  204.      *
  205.      * @var string $currentCategory 
  206.      * @see Services_Twitter::__get()
  207.      * @see Services_Twitter::__call()
  208.      */
  209.     protected $currentCategory = null;
  210.  
  211.     // }}}
  212.     // __construct() {{{
  213.  
  214.     /**
  215.      * Constructor.
  216.      *
  217.      * @param string $user    Twitter username
  218.      * @param string $pass    Twitter password
  219.      * @param array  $options An array of options
  220.      *
  221.      * @return void 
  222.      */
  223.     public function __construct($user = null$pass = null$options = array())
  224.     {
  225.         // set properties and options
  226.         $this->user = $user;
  227.         $this->pass = $pass;
  228.         $this->setOptions($options);
  229.  
  230.         // load the XML API definition
  231.         $this->loadAPI();
  232.     }
  233.  
  234.     // }}}
  235.     // __get() {{{
  236.  
  237.     /**
  238.      * Get interceptor, if the requested property is "options", it just return
  239.      * the options array, otherwise, if the property matches a valid API
  240.      * category it return an instance of this class.
  241.      *
  242.      * @param string $property The property of the call
  243.      *
  244.      * @return mixed 
  245.      */
  246.     public function __get($property)
  247.     {
  248.         if ($this->currentCategory === null{
  249.             if (isset($this->api[$property])) {
  250.                 $this->currentCategory = $property;
  251.                 return $this;
  252.             }
  253.         else {
  254.             $this->currentCategory = null;
  255.         }
  256.         throw new Services_Twitter_Exception(
  257.             'Unsupported endpoint ' $property,
  258.             self::ERROR_ENDPOINT
  259.         );
  260.     }
  261.  
  262.     // }}}
  263.     // __call() {{{
  264.  
  265.     /**
  266.      * Overloaded call for API passthrough.
  267.      * 
  268.      * @param string $endpoint API endpoint being called
  269.      * @param array  $args     $args[0] is an array of GET/POST arguments
  270.      * 
  271.      * @return object Instance of SimpleXMLElement
  272.      */
  273.     public function __call($endpointarray $args = array())
  274.     {
  275.         if ($this->currentCategory !== null{
  276.             if (!isset($this->api[$this->currentCategory][$endpoint])) {
  277.                 throw new Services_Twitter_Exception(
  278.                     'Unsupported endpoint ' 
  279.                     . $this->currentCategory . '/' $endpoint,
  280.                     self::ERROR_ENDPOINT
  281.                 );
  282.             }
  283.             // case of a classic "category->endpoint()" call
  284.             $ep $this->api[$this->currentCategory][$endpoint]
  285.         else if (isset($this->api[$endpoint][$endpoint])) {
  286.             // case of a "root" endpoint call, the method is the name of the 
  287.             // category (ex: $twitter->direct_messages())
  288.             $ep $this->api[$endpoint][$endpoint];
  289.         else {
  290.             throw new Services_Twitter_Exception(
  291.                 'Unsupported endpoint ' $endpoint,
  292.                 self::ERROR_ENDPOINT
  293.             );
  294.         }
  295.  
  296.         // check that endpoint is available in the configured format
  297.         $formats explode(','(string)$ep->formats);
  298.         if (!in_array($this->getOption('format')$formats)) {
  299.             throw new Services_Twitter_Exception(
  300.                 'Endpoint ' $endpoint ' does not support '
  301.                 . $this->getOption('format'' format',
  302.                 self::ERROR_ENDPOINT
  303.             );
  304.         }
  305.  
  306.         // we must reset the current category to null for future calls.
  307.         $cat                   $this->currentCategory;
  308.         $this->currentCategory = null;
  309.  
  310.         // prepare the request
  311.         list($uri$method$params$files
  312.             $this->prepareRequest($ep$args$cat);
  313.  
  314.         // we can now send our request
  315.         if ($this->oauth instanceof HTTP_OAuth_Consumer{
  316.             $resp $this->sendOAuthRequest($uri$method$params$files);
  317.         else {
  318.             $resp $this->sendRequest($uri$method$params$files);
  319.         }
  320.         $body $resp->getBody();
  321.  
  322.         // check for errors
  323.         if (substr($resp->getStatus()01!= '2'{
  324.             $error $this->decodeBody($body);
  325.             if (isset($error->error)) {
  326.                 $message = (string) $error->error;
  327.             else {
  328.                 $message $resp->getReasonPhrase();
  329.             }
  330.             throw new Services_Twitter_Exception(
  331.                 $message,
  332.                 $resp->getStatus(),
  333.                 $uri,
  334.                 $resp
  335.             );
  336.         }
  337.  
  338.         if ($this->getOption('raw_format')) {
  339.             return $body;
  340.         }
  341.         return $this->decodeBody($body);
  342.     }
  343.  
  344.     // }}}
  345.     // sendOAuthRequest() {{{
  346.  
  347.     /**
  348.      * Sends a request using OAuth instead of basic auth
  349.      * 
  350.      * @param string $uri    The full URI of the endpoint
  351.      * @param string $method GET or POST
  352.      * @param array $params  Array of additional parameter
  353.      * @param array $files   Array of files to upload
  354.      * 
  355.      * @throws Services_Twitter_Exception on failure
  356.      * @return HTTP_Request2_Response 
  357.      * @see prepareRequest()
  358.      */
  359.     protected function sendOAuthRequest($uri$method$params$files)
  360.     {
  361.         include_once 'HTTP/OAuth/Consumer/Request.php';
  362.         try {
  363.             $request = clone $this->getRequest();
  364.  
  365.             if ($method == 'POST'{
  366.                 foreach ($files as $key => $val{
  367.                     $request->addUpload($key$val);
  368.                 }
  369.             }
  370.  
  371.             // Use the same instance of HTTP_Request2
  372.             $consumerRequest = new HTTP_OAuth_Consumer_Request;
  373.             $consumerRequest->accept($request);
  374.             $this->oauth->accept($consumerRequest);
  375.  
  376.             $response $this->oauth->sendRequest($uri$params$method);
  377.         catch (HTTP_Request2_Exception $exc{
  378.             throw new Services_Twitter_Exception(
  379.                 $exc->getMessage(),
  380.                 $exc// the original exception cause
  381.                 $uri
  382.             );
  383.         }
  384.         return $response;
  385.     }
  386.  
  387.     // }}}
  388.     // setOption() {{{
  389.  
  390.     /**
  391.      * Set an option in {@link Services_Twitter::$options}
  392.      *
  393.      * If a function exists named _set$option (e.g. _setUserAgent()) then that
  394.      * method will be used instead. Otherwise, the value is set directly into
  395.      * the options array.
  396.      *
  397.      * @param string $option Name of option
  398.      * @param mixed  $value  Value of option
  399.      *
  400.      * @return void 
  401.      * @see Services_Twitter::$options
  402.      */
  403.     public function setOption($option$value)
  404.     {
  405.         $func '_set' ucfirst($option);
  406.         if (method_exists($this$func)) {
  407.             $this->$func($value);
  408.         else {
  409.             $this->options[$option$value;
  410.         }
  411.     }
  412.  
  413.     /**
  414.      * Sets an instance of HTTP_OAuth_Consumer
  415.      * 
  416.      * @param HTTP_OAuth_Consumer $oauth Object containing OAuth credentials
  417.      * 
  418.      * @see $oauth
  419.      * @see $sendOAuthRequest
  420.      * @return void 
  421.      */
  422.     public function setOAuth(HTTP_OAuth_Consumer $oauth)
  423.     {
  424.         $this->oauth = $oauth;
  425.     }
  426.  
  427.     // }}}
  428.     // getOption() {{{
  429.  
  430.     /**
  431.      * Get an option from {@link Services_Twitter::$options}
  432.      *
  433.      * @param string $option Name of option
  434.      *
  435.      * @return mixed 
  436.      * @see Services_Twitter::$options
  437.      */
  438.     public function getOption($option)
  439.     {
  440.         if (isset($this->options[$option])) {
  441.             return $this->options[$option];
  442.         }
  443.         return null;
  444.     }
  445.  
  446.     // }}}
  447.     // setOptions() {{{
  448.  
  449.     /**
  450.      * Set a number of options at once in {@link Services_Twitter::$options}
  451.      *
  452.      * @param array $options Associative array of options name/value
  453.      *
  454.      * @return void 
  455.      * @see Services_Twitter::$options
  456.      * @see Services_Twitter::setOption()
  457.      */
  458.     public function setOptions(array $options)
  459.     {
  460.         foreach ($options as $option => $value{
  461.             $this->setOption($option$value);
  462.         }
  463.     }
  464.  
  465.     // }}}
  466.     // getOptions() {{{
  467.  
  468.     /**
  469.      * Return the Services_Twitter options array.
  470.      *
  471.      * @return array 
  472.      * @see Services_Twitter::$options
  473.      */
  474.     public function getOptions()
  475.     {
  476.         return $this->options;
  477.     }
  478.  
  479.     // }}}
  480.     // getRequest() {{{
  481.     
  482.     /**
  483.      * Returns the HTTP_Request2 instance.
  484.      * 
  485.      * @return HTTP_Request2 The request
  486.      */
  487.     public function getRequest()
  488.     {
  489.         if ($this->request === null{
  490.             $this->request = new HTTP_Request2();
  491.         }
  492.         if ($this->getOption('use_ssl')) {
  493.             // XXX ssl won't work with ssl_verify_peer set to true, which is 
  494.             // the default in HTTP_Request2
  495.             $this->request->setConfig('ssl_verify_peer'false);
  496.         }
  497.         return $this->request;
  498.     }
  499.     
  500.     // }}}
  501.     // setRequest() {{{
  502.     
  503.     /**
  504.      * Sets the HTTP_Request2 instance.
  505.      * 
  506.      * @param HTTP_Request2 $request The request to set
  507.      *
  508.      * @return void 
  509.      */
  510.     public function setRequest(HTTP_Request2 $request)
  511.     {
  512.         $this->request = $request;
  513.     }
  514.     
  515.     // }}}
  516.     // decodeBody() {{{
  517.  
  518.     /**
  519.      * Decode the response body according to the configured format.
  520.      *
  521.      * @param string $body The response body to decode
  522.      *
  523.      * @return mixed 
  524.      */
  525.     protected function decodeBody($body)
  526.     {
  527.  
  528.         if ($this->getOption('format'== Services_Twitter::OUTPUT_XML{
  529.             $result simplexml_load_string($body);
  530.             $isbool ((string)$result == 'true' || (string)$result == 'false');
  531.         else 
  532.             // default to Services_Twitter::OUTPUT_JSON
  533.             $result json_decode($body);
  534.             $isbool ($result == 'true' || $result == 'false');
  535.         }
  536.         // special case where the API returns true/false strings
  537.         if ($isbool{
  538.             return (string)$result == 'true';
  539.         }
  540.         return $result;
  541.     }
  542.  
  543.     // }}}
  544.     // loadAPI() {{{
  545.  
  546.     /**
  547.      * Loads the XML API definition.
  548.      *
  549.      * @return void 
  550.      */
  551.     protected function loadAPI()
  552.     {
  553.         // initialize xml mapping
  554.         $p is_dir('@data_dir@'
  555.             ? array('@data_dir@''Services_Twitter''data')
  556.             : array(dirname(__FILE__)'..''data');
  557.         $d implode(DIRECTORY_SEPARATOR$p. DIRECTORY_SEPARATOR;
  558.         if ($this->getOption('validate'&& class_exists('DomDocument')) {
  559.             // this should be done only when testing
  560.             $doc = new DomDocument();
  561.             $doc->load($d 'api.xml');
  562.             $doc->relaxNGValidate($d 'api.rng');
  563.         }
  564.         $xmlApi simplexml_load_file($d 'api.xml');
  565.         foreach ($xmlApi->category as $category{
  566.             $catName             = (string)$category['name'];
  567.             $this->api[$catName= array();
  568.             foreach ($category->endpoint as $endpoint{
  569.                 $this->api[$catName][(string)$endpoint['name']] $endpoint;
  570.             }
  571.         }
  572.     }
  573.  
  574.     // }}}
  575.     // prepareRequest() {{{
  576.  
  577.     /**
  578.      * Prepare the request before it is sent.
  579.      *
  580.      * @param SimpleXMLElement $endpoint API endpoint xml node
  581.      * @param array            $args     API endpoint arguments
  582.      * @param string           $cat      The current category
  583.      *
  584.      * @throws Services_Twitter_Exception
  585.      * @return array The array of arguments to pass to in the request
  586.      */
  587.     protected function prepareRequest($endpointarray $args = array()$cat = null)
  588.     {
  589.         $params = array();
  590.         $files  = array();
  591.  
  592.         // check if we have is a search or trends call, in this case the base 
  593.         // uri is different
  594.         if ($cat == 'search' || (string)$endpoint['name'== 'search' ||
  595.             $cat == 'trends' || (string)$endpoint['name'== 'trends'{
  596.             $uri = self::$searchUri;
  597.         else {
  598.             $uri = self::$uri;
  599.         }
  600.  
  601.         // ssl requested
  602.         if ($this->getOption('use_ssl')) {
  603.             $uri str_replace('http://''https://'$uri);
  604.         }
  605.  
  606.         // build the uri path
  607.         $path '/';
  608.         if ($cat !== null{
  609.             $path .= $cat '/';
  610.         }
  611.         $method = (string)$endpoint['method'];
  612.         $path  .= (string)$endpoint['name'];
  613.  
  614.         // check if we have a POST method and a registered source to pass
  615.         $source $this->getOption('source');
  616.         if ($method == 'POST' && $source !== null{
  617.             $params['source'$source;
  618.         }
  619.         
  620.         // check arguments requirements
  621.         $minargs = isset($endpoint['min_args'])
  622.             ? (int)$endpoint['min_args']
  623.             : count($endpoint->xpath('param[@required="true" or @required="1"]'));
  624.         if (!$minargs && (isset($args[0]&& !is_array($args[0]))) {
  625.             throw new Services_Twitter_Exception(
  626.                 $path ' expects an array as unique parameter',
  627.                 self::ERROR_PARAMS,
  628.                 $path
  629.             );
  630.         }
  631.         if ($minargs && (!isset($args[0]|| 
  632.             is_array($args[0]&& $minargs count($args[0]))) {
  633.             throw new Services_Twitter_Exception(
  634.                 'Not enough arguments for ' $path,
  635.                 self::ERROR_PARAMS,
  636.                 $path
  637.             );
  638.         }
  639.         $needargs $minargs;
  640.  
  641.         // now process arguments according to their definition in the xml 
  642.         // mapping
  643.         foreach ($endpoint->param as $param{
  644.             $pName      = (string)$param['name'];
  645.             $pType      = (string)$param['type'];
  646.             $pMaxLength = (int)$param['max_length'];
  647.             $pMaxLength $pMaxLength > 0 ? $pMaxLength : null;
  648.             $pReq       = (string)$param['required'== 'true' || $needargs;
  649.             if ($pReq && !is_array($args[0])) {
  650.                 $arg array_shift($args);
  651.                 $needargs--;
  652.             else if (isset($args[0][$pName])) {
  653.                 $arg $args[0][$pName];
  654.                 $needargs--;
  655.             else {
  656.                 continue;
  657.             }
  658.             try {
  659.                 $this->validateArg($pName$arg$pType$pMaxLength);
  660.             catch (Exception $exc{
  661.                 throw new Services_Twitter_Exception(
  662.                     $path ': ' $exc->getMessage(),
  663.                     self::ERROR_PARAMS,
  664.                     $path
  665.                 );
  666.             }
  667.             if ($pName == 'id'{
  668.                 $path .= '/' $arg;
  669.             else {
  670.                 if ($pType == 'string' && !$this->isUtf8($arg)) {
  671.                     // iso-8859-1 string that we must convert to unicode
  672.                     $arg utf8_encode($arg);
  673.                 }
  674.                 if ($pType == 'image'{
  675.                     // we have a file upload
  676.                     $files[$pName$arg;
  677.                 else {
  678.                     $params[$pName$arg;
  679.                 }
  680.             }
  681.         }
  682.         $uri .= $path '.' $this->getOption('format');
  683.         return array($uri$method$params$files);
  684.     }
  685.  
  686.     // }}}
  687.     // sendRequest() {{{
  688.  
  689.     /**
  690.      * Send a request to the Twitter API.
  691.      *
  692.      * @param string $uri    The full URI to the API endpoint
  693.      * @param array  $method The HTTP request method (GET or POST)
  694.      * @param array  $args   The API endpoint arguments if any
  695.      * @param array  $files  The API endpoint file uploads if any
  696.      *
  697.      * @throws Services_Twitter_Exception
  698.      * @return object Instance of SimpleXMLElement
  699.      */
  700.     protected function sendRequest($uri$method 'GET'array $args = array(),
  701.         array $files = array())
  702.     {
  703.         try {
  704.             $request = clone $this->getRequest();
  705.             $request->setMethod($method);
  706.             if ($method == 'POST'{
  707.                 foreach ($args as $key => $val{
  708.                     $request->addPostParameter($key$val);
  709.                 }
  710.                 foreach ($files as $key => $val{
  711.                     $request->addUpload($key$val);
  712.                 }
  713.             else {
  714.                 $prefix '?';
  715.                 foreach ($args as $key => $val{
  716.                     $uri   .= $prefix $key '=' urlencode($val);
  717.                     $prefix '&';
  718.                 }
  719.             }
  720.             $request->setUrl($uri);
  721.             if ($this->user !== null && $this->pass !== null{
  722.                 $request->setAuth($this->user$this->pass);
  723.             }
  724.             $response $request->send();
  725.         catch (HTTP_Request2_Exception $exc{
  726.             throw new Services_Twitter_Exception(
  727.                 $exc->getMessage(),
  728.                 $exc// the original exception cause
  729.                 $uri
  730.             );
  731.         }
  732.         return $response;
  733.     }
  734.  
  735.     // }}}
  736.     // validateArg() {{{
  737.  
  738.     /**
  739.      * Check the validity of an argument (required, max length, type...).
  740.      *
  741.      * @param array $name      The argument name
  742.      * @param array &$val      The argument value, passed by reference
  743.      * @param array $type      The argument type
  744.      * @param array $maxLength The argument maximum length (optional)
  745.      *
  746.      * @throws Services_Twitter_Exception
  747.      * @return void 
  748.      */
  749.     protected function validateArg($name&$val$type$maxLength = null)
  750.     {
  751.         // check length if necessary
  752.         if ($maxLength !== null && strlen($val$maxLength{
  753.             throw new Exception(
  754.                 $name ' must not exceed ' $maxLength ' chars',
  755.                 self::ERROR_PARAMS
  756.             );
  757.         }
  758.  
  759.         // type checks
  760.         $msg = null;
  761.         switch ($type{
  762.         case 'boolean':
  763.             if (!is_bool($val)) {
  764.                 $msg $name ' must be a boolean';
  765.             }
  766.             // we modify the value by reference
  767.             $val $val 'true' 'false';
  768.             break;
  769.         case 'integer':
  770.             if (!is_numeric($val)) {
  771.                 $msg $name ' must be an integer';
  772.             }
  773.             break;
  774.         case 'string':
  775.             if (!is_string($val)) {
  776.                 $msg $name ' must be a string';
  777.             }
  778.             break;
  779.         case 'date':
  780.             if (is_numeric($val)) {
  781.                 // we have a timestamp
  782.                 $val date('Y-m-d'$val);
  783.             else {
  784.                 $rx '/^\d{4}\-\d{2}\-\d{2}$/';
  785.                 if (!preg_match($rx$val)) {
  786.                     $msg $name ' should be formatted YYYY-MM-DD';
  787.                 }
  788.             }
  789.             break;
  790.         case 'id_or_screenname':
  791.             if (!preg_match('/^[a-z0-9_]+$/'$val)) {
  792.                 $msg $name ' must be a valid id or screen name';
  793.             }
  794.             break;
  795.         case 'device':
  796.             $devices = array('none''sms''im');
  797.             if (!in_array($val$devices)) {
  798.                 $msg $name ' must be one of the following: ' 
  799.                      . implode(', '$devices);
  800.             }
  801.             break;
  802.         case 'iso-639-1':
  803.             if (strlen($val!= 2{
  804.                 $msg $name ' must be a valid iso-639-1 language code';
  805.             }
  806.             break;
  807.         case 'geocode':
  808.             if (!preg_match('/^([-\d\.]+,){2}([-\d\.]+(km|mi)$)/'$val)) {
  809.                 $msg $name ' must be "latitide,longitude,radius(km or mi)"';
  810.             }
  811.             break;
  812.         case 'color':
  813.             if (!preg_match('/^([0-9a-f]{1,2}){3}$/i'$val)) {
  814.                 $msg $name ' must be an hexadecimal color code (eg. fff)';
  815.             }
  816.             break;
  817.         case 'image':
  818.             if (!file_exists($val|| !is_readable($val)) {
  819.                 $msg $name ' must be a valid image path';
  820.             }
  821.             // XXX we don't check the image type for now...
  822.             break;
  823.         }
  824.         if ($msg !== null{
  825.             throw new Services_Twitter_Exception($msgself::ERROR_PARAMS);
  826.         }
  827.     }
  828.  
  829.     // }}}
  830.     // isUtf8() {{{
  831.  
  832.     /**
  833.      * Check if the given string is a UTF-8 string or an iso-8859-1 one.
  834.      *
  835.      * @param string $str The string to check
  836.      *
  837.      * @return boolean Wether the string is unicode or not
  838.      */
  839.     protected function isUtf8($str)
  840.     {
  841.         return (bool)preg_match('%^(?:
  842.               [\x09\x0A\x0D\x20-\x7E]            # ASCII
  843.             | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
  844.             |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
  845.             | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
  846.             |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
  847.             |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
  848.             | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
  849.             |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
  850.         )*$%xs'$str);
  851.     }
  852.  
  853.     // }}}
  854. }

Documentation generated on Mon, 11 Mar 2019 15:34:40 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.