joris

Twitter Class

Sep 28th, 2012
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 129.80 KB | None | 0 0
  1. <?php
  2.  
  3. /**
  4.  * Twitter class
  5.  *
  6.  * This source file can be used to communicate with Twitter (http://twitter.com)
  7.  *
  8.  * The class is documented in the file itself. If you find any bugs help me out and report them. Reporting can be done by sending an email to php-twitter-bugs[at]verkoyen[dot]eu.
  9.  * If you report a bug, make sure you give me enough information (include your code).
  10.  *
  11.  * Changelog since 2.1.1
  12.  * - code styling
  13.  * - no more converting to integer for the cursor (thx to Jamaica)
  14.  *
  15.  * Changelog since 2.1.0
  16.  * - fixed issue with generation of basestring
  17.  * - added a new method: http://dev.twitter.com/doc/post/:user/:list_id/create_all
  18.  *
  19.  * Changelog since 2.0.3
  20.  * - made a lot of changes to reflect the current API, some of the methods aren't backwards compatible, so be carefull before upgrading
  21.  *
  22.  * Changelog since 2.0.2
  23.  * - tested geo*
  24.  * - implemented accountUpdateProfileImage
  25.  * - implemented accountUpdateProfileBackgroundImage
  26.  * - fixed issue with GET and POST (thx to Luiz Felipe)
  27.  * - added a way to detect open_basedir (thx to Lee Kindness)
  28.  *
  29.  * Changelog since 2.0.1
  30.  * - Fixed some documentation
  31.  * - Added a new method: usersProfileImage
  32.  * - Fixed trendsLocation
  33.  * - Added new GEO-methods: geoSearch, geoSimilarPlaces, geoPlaceCreate (not tested because geo-services were disabled.)
  34.  * - Added legalToS
  35.  * - Added legalPrivacy
  36.  * - Fixed helpTest
  37.  *
  38.  * Changelog since 2.0.0
  39.  * - no more fatal if twitter is over capacity
  40.  * - fix for calculating the header-string (thx to Dextro)
  41.  * - fix for userListsIdStatuses (thx to Josh)
  42.  *
  43.  * License
  44.  * Copyright (c) 2010, Tijs Verkoyen. All rights reserved.
  45.  *
  46.  * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
  47.  *
  48.  * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  49.  * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  50.  * 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
  51.  *
  52.  * This software is provided by the author "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the author be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.
  53.  *
  54.  * @author      Tijs Verkoyen <php-twitter@verkoyen.eu>
  55.  * @version     2.1.2
  56.  *
  57.  * @copyright   Copyright (c) 2010, Tijs Verkoyen. All rights reserved.
  58.  * @license     BSD License
  59.  */
  60. class Twitter
  61. {
  62.     // internal constant to enable/disable debugging
  63.     const DEBUG = false;
  64.  
  65.     // url for the twitter-api
  66.     const API_URL = 'https://api.twitter.com/1';
  67.     const SEARCH_API_URL = 'https://search.twitter.com';
  68.     const SECURE_API_URL = 'https://api.twitter.com';
  69.  
  70.     // port for the twitter-api
  71.     const API_PORT = 443;
  72.     const SEARCH_API_PORT = 443;
  73.     const SECURE_API_PORT = 443;
  74.  
  75.     // current version
  76.     const VERSION = '2.1.2';
  77.  
  78.  
  79.     /**
  80.      * A cURL instance
  81.      *
  82.      * @var resource
  83.      */
  84.     private $curl;
  85.  
  86.  
  87.     /**
  88.      * The consumer key
  89.      *
  90.      * @var string
  91.      */
  92.     private $consumerKey;
  93.  
  94.  
  95.     /**
  96.      * The consumer secret
  97.      *
  98.      * @var string
  99.      */
  100.     private $consumerSecret;
  101.  
  102.  
  103.     /**
  104.      * The oAuth-token
  105.      *
  106.      * @var string
  107.      */
  108.     private $oAuthToken = '';
  109.  
  110.  
  111.     /**
  112.      * The oAuth-token-secret
  113.      *
  114.      * @var string
  115.      */
  116.     private $oAuthTokenSecret = '';
  117.  
  118.  
  119.     /**
  120.      * The timeout
  121.      *
  122.      * @var int
  123.      */
  124.     private $timeOut = 60;
  125.  
  126.  
  127.     /**
  128.      * The user agent
  129.      *
  130.      * @var string
  131.      */
  132.     private $userAgent;
  133.  
  134.  
  135. // class methods
  136.     /**
  137.      * Default constructor
  138.      *
  139.      * @return  void
  140.      * @param   string $consumerKey     The consumer key to use.
  141.      * @param   string $consumerSecret  The consumer secret to use.
  142.      */
  143.     public function __construct($consumerKey, $consumerSecret)
  144.     {
  145.         $this->setConsumerKey($consumerKey);
  146.         $this->setConsumerSecret($consumerSecret);
  147.     }
  148.  
  149.  
  150.     /**
  151.      * Default destructor
  152.      *
  153.      * @return  void
  154.      */
  155.     public function __destruct()
  156.     {
  157.         if($this->curl != null) curl_close($this->curl);
  158.     }
  159.  
  160.  
  161.     /**
  162.      * Format the parameters as a querystring
  163.      *
  164.      * @return  string
  165.      * @param   array $parameters   The parameters.
  166.      */
  167.     private function buildQuery(array $parameters)
  168.     {
  169.         // no parameters?
  170.         if(empty($parameters)) return '';
  171.  
  172.         // encode the keys
  173.         $keys = self::urlencode_rfc3986(array_keys($parameters));
  174.  
  175.         // encode the values
  176.         $values = self::urlencode_rfc3986(array_values($parameters));
  177.  
  178.         // reset the parameters
  179.         $parameters = array_combine($keys, $values);
  180.  
  181.         // sort parameters by key
  182.         uksort($parameters, 'strcmp');
  183.  
  184.         // loop parameters
  185.         foreach($parameters as $key => $value)
  186.         {
  187.             // sort by value
  188.             if(is_array($value)) $parameters[$key] = natsort($value);
  189.         }
  190.  
  191.         // process parameters
  192.         foreach($parameters as $key => $value) $chunks[] = $key . '=' . str_replace('%25', '%', $value);
  193.  
  194.         // return
  195.         return implode('&', $chunks);
  196.     }
  197.  
  198.  
  199.     /**
  200.      * All OAuth 1.0 requests use the same basic algorithm for creating a signature base string and a signature.
  201.      * The signature base string is composed of the HTTP method being used, followed by an ampersand ("&") and then the URL-encoded base URL being accessed,
  202.      * complete with path (but not query parameters), followed by an ampersand ("&").
  203.      * Then, you take all query parameters and POST body parameters (when the POST body is of the URL-encoded type, otherwise the POST body is ignored),
  204.      * including the OAuth parameters necessary for negotiation with the request at hand, and sort them in lexicographical order by first parameter name and
  205.      * then parameter value (for duplicate parameters), all the while ensuring that both the key and the value for each parameter are URL encoded in isolation.
  206.      * Instead of using the equals ("=") sign to mark the key/value relationship, you use the URL-encoded form of "%3D". Each parameter is then joined by the
  207.      * URL-escaped ampersand sign, "%26".
  208.      *
  209.      * @return  string
  210.      * @param   string $url         The URL.
  211.      * @param   string $method      The method to use.
  212.      * @param   array $parameters   The parameters.
  213.      */
  214.     private function calculateBaseString($url, $method, array $parameters)
  215.     {
  216.         // redefine
  217.         $url = (string) $url;
  218.         $parameters = (array) $parameters;
  219.  
  220.         // init var
  221.         $pairs = array();
  222.         $chunks = array();
  223.  
  224.         // sort parameters by key
  225.         uksort($parameters, 'strcmp');
  226.  
  227.         // loop parameters
  228.         foreach($parameters as $key => $value)
  229.         {
  230.             // sort by value
  231.             if(is_array($value)) $parameters[$key] = natsort($value);
  232.         }
  233.  
  234.         // process queries
  235.         foreach($parameters as $key => $value)
  236.         {
  237.             // only add if not already in the url
  238.             if(substr_count($url, $key . '=' . $value) == 0) $chunks[] = self::urlencode_rfc3986($key) . '%3D' . self::urlencode_rfc3986($value);
  239.         }
  240.  
  241.         // buils base
  242.         $base = $method . '&';
  243.         $base .= urlencode($url);
  244.         $base .= (substr_count($url, '?')) ? '%26' : '&';
  245.         $base .= implode('%26', $chunks);
  246.         $base = str_replace('%3F', '&', $base);
  247.  
  248.         // return
  249.         return $base;
  250.     }
  251.  
  252.  
  253.     /**
  254.      * Build the Authorization header
  255.      * @later: fix me
  256.      *
  257.      * @return  string
  258.      * @param   array $parameters   The parameters.
  259.      * @param   string $url         The URL.
  260.      */
  261.     private function calculateHeader(array $parameters, $url)
  262.     {
  263.         // redefine
  264.         $url = (string) $url;
  265.  
  266.         // divide into parts
  267.         $parts = parse_url($url);
  268.  
  269.         // init var
  270.         $chunks = array();
  271.  
  272.         // process queries
  273.         foreach($parameters as $key => $value) $chunks[] = str_replace('%25', '%', self::urlencode_rfc3986($key) . '="' . self::urlencode_rfc3986($value) . '"');
  274.  
  275.         // build return
  276.         $return = 'Authorization: OAuth realm="' . $parts['scheme'] . '://' . $parts['host'] . $parts['path'] . '", ';
  277.         $return .= implode(',', $chunks);
  278.  
  279.         // prepend name and OAuth part
  280.         return $return;
  281.     }
  282.  
  283.  
  284.     /**
  285.      * Make an call to the oAuth
  286.      * @todo    refactor me
  287.      *
  288.      * @return  array
  289.      * @param   string $method                  The method.
  290.      * @param   array[optional] $parameters     The parameters.
  291.      */
  292.     private function doOAuthCall($method, array $parameters = null)
  293.     {
  294.         // redefine
  295.         $method = (string) $method;
  296.  
  297.         // append default parameters
  298.         $parameters['oauth_consumer_key'] = $this->getConsumerKey();
  299.         $parameters['oauth_nonce'] = md5(microtime() . rand());
  300.         $parameters['oauth_timestamp'] = time();
  301.         $parameters['oauth_signature_method'] = 'HMAC-SHA1';
  302.         $parameters['oauth_version'] = '1.0';
  303.  
  304.         // calculate the base string
  305.         $base = $this->calculateBaseString(self::SECURE_API_URL . '/oauth/' . $method, 'POST', $parameters);
  306.  
  307.         // add sign into the parameters
  308.         $parameters['oauth_signature'] = $this->hmacsha1($this->getConsumerSecret() . '&' . $this->getOAuthTokenSecret(), $base);
  309.  
  310.         // calculate header
  311.         $header = $this->calculateHeader($parameters, self::SECURE_API_URL . '/oauth/' . $method);
  312.  
  313.         // set options
  314.         $options[CURLOPT_URL] = self::SECURE_API_URL . '/oauth/' . $method;
  315.         $options[CURLOPT_PORT] = self::SECURE_API_PORT;
  316.         $options[CURLOPT_USERAGENT] = $this->getUserAgent();
  317.         if(ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) $options[CURLOPT_FOLLOWLOCATION] = true;
  318.         $options[CURLOPT_RETURNTRANSFER] = true;
  319.         $options[CURLOPT_TIMEOUT] = (int) $this->getTimeOut();
  320.         $options[CURLOPT_SSL_VERIFYPEER] = false;
  321.         $options[CURLOPT_SSL_VERIFYHOST] = false;
  322.         $options[CURLOPT_HTTPHEADER] = array('Expect:');
  323.         $options[CURLOPT_POST] = true;
  324.         $options[CURLOPT_POSTFIELDS] = $this->buildQuery($parameters);
  325.  
  326.         // init
  327.         $this->curl = curl_init();
  328.  
  329.         // set options
  330.         curl_setopt_array($this->curl, $options);
  331.  
  332.         // execute
  333.         $response = curl_exec($this->curl);
  334.         $headers = curl_getinfo($this->curl);
  335.  
  336.         // fetch errors
  337.         $errorNumber = curl_errno($this->curl);
  338.         $errorMessage = curl_error($this->curl);
  339.  
  340.         // error?
  341.         if($errorNumber != '') throw new TwitterException($errorMessage, $errorNumber);
  342.  
  343.         // init var
  344.         $return = array();
  345.  
  346.         // parse the string
  347.         parse_str($response, $return);
  348.  
  349.         // return
  350.         return $return;
  351.     }
  352.  
  353.  
  354.     /**
  355.      * Make the call
  356.      *
  357.      * @return  string
  358.      * @param   string $url                     The url to call.
  359.      * @param   array[optional] $parameters     Optional parameters.
  360.      * @param   bool[optional] $authenticate    Should we authenticate.
  361.      * @param   bool[optional] $method          The method to use. Possible values are GET, POST.
  362.      * @param   string[optional] $filePath      The path to the file to upload.
  363.      * @param   bool[optional] $expectJSON      Do we expect JSON.
  364.      * @param   bool[optional] $returnHeaders   Should the headers be returned?
  365.      */
  366.     private function doCall($url, array $parameters = null, $authenticate = false, $method = 'GET', $filePath = null, $expectJSON = true, $returnHeaders = false)
  367.     {
  368.         // allowed methods
  369.         $allowedMethods = array('GET', 'POST');
  370.  
  371.         // redefine
  372.         $url = (string) $url;
  373.         $parameters = (array) $parameters;
  374.         $authenticate = (bool) $authenticate;
  375.         $method = (string) $method;
  376.         $expectJSON = (bool) $expectJSON;
  377.  
  378.         // validate method
  379.         if(!in_array($method, $allowedMethods)) throw new TwitterException('Unknown method (' . $method . '). Allowed methods are: ' . implode(', ', $allowedMethods));
  380.  
  381.         // append default parameters
  382.         $oauth['oauth_consumer_key'] = $this->getConsumerKey();
  383.         $oauth['oauth_nonce'] = md5(microtime() . rand());
  384.         $oauth['oauth_timestamp'] = time();
  385.         $oauth['oauth_token'] = $this->getOAuthToken();
  386.         $oauth['oauth_signature_method'] = 'HMAC-SHA1';
  387.         $oauth['oauth_version'] = '1.0';
  388.  
  389.         // set data
  390.         $data = $oauth;
  391.         if(!empty($parameters)) $data = array_merge($data, $parameters);
  392.  
  393.         // calculate the base string
  394.         $base = $this->calculateBaseString(self::API_URL . '/' . $url, $method, $data);
  395.  
  396.         // based on the method, we should handle the parameters in a different way
  397.         if($method == 'POST')
  398.         {
  399.             // file provided?
  400.             if($filePath != null)
  401.             {
  402.                 // build a boundary
  403.                 $boundary = md5(time());
  404.  
  405.                 // process file
  406.                 $fileInfo = pathinfo($filePath);
  407.  
  408.                 // set mimeType
  409.                 $mimeType = 'application/octet-stream';
  410.                 if($fileInfo['extension'] == 'jpg' || $fileInfo['extension'] == 'jpeg') $mimeType = 'image/jpeg';
  411.                 elseif($fileInfo['extension'] == 'gif') $mimeType = 'image/gif';
  412.                 elseif($fileInfo['extension'] == 'png') $mimeType = 'image/png';
  413.  
  414.                 // init var
  415.                 $content = '--' . $boundary . "\r\n";
  416.  
  417.                 // set file
  418.                 $content .= 'Content-Disposition: form-data; name=image; filename="' . $fileInfo['basename'] . '"' . "\r\n";
  419.                 $content .= 'Content-Type: ' . $mimeType . "\r\n";
  420.                 $content .= "\r\n";
  421.                 $content .= file_get_contents($filePath);
  422.                 $content .= "\r\n";
  423.                 $content .= "--" . $boundary . '--';
  424.  
  425.                 // build headers
  426.                 $headers[] = 'Content-Type: multipart/form-data; boundary=' . $boundary;
  427.                 $headers[] = 'Content-Length: ' . strlen($content);
  428.  
  429.                 // set content
  430.                 $options[CURLOPT_POSTFIELDS] = $content;
  431.             }
  432.  
  433.             // no file
  434.             else $options[CURLOPT_POSTFIELDS] = $this->buildQuery($parameters);
  435.  
  436.             // enable post
  437.             $options[CURLOPT_POST] = true;
  438.         }
  439.  
  440.         else
  441.         {
  442.             // add the parameters into the querystring
  443.             if(!empty($parameters)) $url .= '?' . $this->buildQuery($parameters);
  444.  
  445.             $options[CURLOPT_POST] = false;
  446.         }
  447.  
  448.         // add sign into the parameters
  449.         $oauth['oauth_signature'] = $this->hmacsha1($this->getConsumerSecret() . '&' . $this->getOAuthTokenSecret(), $base);
  450.  
  451.         $headers[] = $this->calculateHeader($oauth, self::API_URL . '/' . $url);
  452.         $headers[] = 'Expect:';
  453.  
  454.         // set options
  455.         $options[CURLOPT_URL] = self::API_URL . '/' . $url;
  456.         $options[CURLOPT_PORT] = self::API_PORT;
  457.         $options[CURLOPT_USERAGENT] = $this->getUserAgent();
  458.         if(ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) $options[CURLOPT_FOLLOWLOCATION] = true;
  459.         $options[CURLOPT_RETURNTRANSFER] = true;
  460.         $options[CURLOPT_TIMEOUT] = (int) $this->getTimeOut();
  461.         $options[CURLOPT_SSL_VERIFYPEER] = false;
  462.         $options[CURLOPT_SSL_VERIFYHOST] = false;
  463.         $options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
  464.         $options[CURLOPT_HTTPHEADER] = $headers;
  465.  
  466.         // init
  467.         if($this->curl == null) $this->curl = curl_init();
  468.  
  469.         // set options
  470.         curl_setopt_array($this->curl, $options);
  471.  
  472.         // execute
  473.         $response = curl_exec($this->curl);
  474.         $headers = curl_getinfo($this->curl);
  475.  
  476.         // fetch errors
  477.         $errorNumber = curl_errno($this->curl);
  478.         $errorMessage = curl_error($this->curl);
  479.  
  480.         // return the headers
  481.         if($returnHeaders) return $headers;
  482.  
  483.         // we don't expext JSON, return the response
  484.         if(!$expectJSON) return $response;
  485.  
  486.         // replace ids with their string values, added because of some PHP-version can't handle these large values
  487.         $response = preg_replace('/id":(\d+)/', 'id":"\1"', $response);
  488.  
  489.         // we expect JSON, so decode it
  490.         $json = @json_decode($response, true);
  491.  
  492.         // validate JSON
  493.         if($json === null)
  494.         {
  495.             // should we provide debug information
  496.             if(self::DEBUG)
  497.             {
  498.                 // make it output proper
  499.                 echo '<pre>';
  500.  
  501.                 // dump the header-information
  502.                 var_dump($headers);
  503.  
  504.                 // dump the error
  505.                 var_dump($errorMessage);
  506.  
  507.                 // dump the raw response
  508.                 var_dump($response);
  509.  
  510.                 // end proper format
  511.                 echo '</pre>';
  512.             }
  513.  
  514.             // throw exception
  515.             throw new TwitterException('Invalid response.');
  516.         }
  517.  
  518.  
  519.         // any errors
  520.         if(isset($json['errors']))
  521.         {
  522.             // should we provide debug information
  523.             if(self::DEBUG)
  524.             {
  525.                 // make it output proper
  526.                 echo '<pre>';
  527.  
  528.                 // dump the header-information
  529.                 var_dump($headers);
  530.  
  531.                 // dump the error
  532.                 var_dump($errorMessage);
  533.  
  534.                 // dump the raw response
  535.                 var_dump($response);
  536.  
  537.                 // end proper format
  538.                 echo '</pre>';
  539.             }
  540.  
  541.             // throw exception
  542.             if(isset($json['errors'][0]['message'])) throw new TwitterException($json['errors'][0]['message']);
  543.             elseif(isset($json['errors']) && is_string($json['errors'])) throw new TwitterException($json['errors']);
  544.             else throw new TwitterException('Invalid response.');
  545.         }
  546.  
  547.  
  548.         // any error
  549.         if(isset($json['error']))
  550.         {
  551.             // should we provide debug information
  552.             if(self::DEBUG)
  553.             {
  554.                 // make it output proper
  555.                 echo '<pre>';
  556.  
  557.                 // dump the header-information
  558.                 var_dump($headers);
  559.  
  560.                 // dump the raw response
  561.                 var_dump($response);
  562.  
  563.                 // end proper format
  564.                 echo '</pre>';
  565.             }
  566.  
  567.             // throw exception
  568.             throw new TwitterException($json['error']);
  569.         }
  570.  
  571.         // return
  572.         return $json;
  573.     }
  574.  
  575.  
  576.     /**
  577.      * Make the call
  578.      *
  579.      * @return  string
  580.      * @param   string $url                     The url to call.
  581.      * @param   array[optional] $parameters     Optional parameters.
  582.      */
  583.     private function doSearchCall($url, array $parameters = null)
  584.     {
  585.         // redefine
  586.         $url = (string) $url;
  587.         $parameters = (array) $parameters;
  588.  
  589.         // add the parameters into the querystring
  590.         if(!empty($parameters)) $url .= '?' . $this->buildQuery($parameters);
  591.  
  592.         // set options
  593.         $options[CURLOPT_URL] = self::SEARCH_API_URL . '/' . $url;
  594.         $options[CURLOPT_PORT] = self::SEARCH_API_PORT;
  595.         $options[CURLOPT_USERAGENT] = $this->getUserAgent();
  596.         if(ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) $options[CURLOPT_FOLLOWLOCATION] = true;
  597.         $options[CURLOPT_RETURNTRANSFER] = true;
  598.         $options[CURLOPT_TIMEOUT] = (int) $this->getTimeOut();
  599.         $options[CURLOPT_SSL_VERIFYPEER] = false;
  600.         $options[CURLOPT_SSL_VERIFYHOST] = false;
  601.         $options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
  602.  
  603.         // init
  604.         if($this->curl == null) $this->curl = curl_init();
  605.  
  606.         // set options
  607.         curl_setopt_array($this->curl, $options);
  608.  
  609.         // execute
  610.         $response = curl_exec($this->curl);
  611.         $headers = curl_getinfo($this->curl);
  612.  
  613.         // fetch errors
  614.         $errorNumber = curl_errno($this->curl);
  615.         $errorMessage = curl_error($this->curl);
  616.  
  617.         // replace ids with their string values, added because of some PHP-version can't handle these large values
  618.         $response = preg_replace('/id":(\d+)/', 'id":"\1"', $response);
  619.  
  620.         // we expect JSON, so decode it
  621.         $json = @json_decode($response, true);
  622.  
  623.         // validate JSON
  624.         if($json === null)
  625.         {
  626.             // should we provide debug information
  627.             if(self::DEBUG)
  628.             {
  629.                 // make it output proper
  630.                 echo '<pre>';
  631.  
  632.                 // dump the header-information
  633.                 var_dump($headers);
  634.  
  635.                 // dump the error
  636.                 var_dump($errorMessage);
  637.  
  638.                 // dump the raw response
  639.                 var_dump($response);
  640.  
  641.                 // end proper format
  642.                 echo '</pre>';
  643.             }
  644.  
  645.             // throw exception
  646.             throw new TwitterException('Invalid response.');
  647.         }
  648.  
  649.  
  650.         // any errors
  651.         if(isset($json['errors']))
  652.         {
  653.             // should we provide debug information
  654.             if(self::DEBUG)
  655.             {
  656.                 // make it output proper
  657.                 echo '<pre>';
  658.  
  659.                 // dump the header-information
  660.                 var_dump($headers);
  661.  
  662.                 // dump the error
  663.                 var_dump($errorMessage);
  664.  
  665.                 // dump the raw response
  666.                 var_dump($response);
  667.  
  668.                 // end proper format
  669.                 echo '</pre>';
  670.             }
  671.  
  672.             // throw exception
  673.             if(isset($json['errors'][0]['message'])) throw new TwitterException($json['errors'][0]['message']);
  674.             else throw new TwitterException('Invalid response.');
  675.         }
  676.  
  677.  
  678.         // any error
  679.         if(isset($json['error']))
  680.         {
  681.             // should we provide debug information
  682.             if(self::DEBUG)
  683.             {
  684.                 // make it output proper
  685.                 echo '<pre>';
  686.  
  687.                 // dump the header-information
  688.                 var_dump($headers);
  689.  
  690.                 // dump the raw response
  691.                 var_dump($response);
  692.  
  693.                 // end proper format
  694.                 echo '</pre>';
  695.             }
  696.  
  697.             // throw exception
  698.             throw new TwitterException($json['error']);
  699.         }
  700.  
  701.         // return
  702.         return $json;
  703.     }
  704.  
  705.  
  706.     /**
  707.      * Get the consumer key
  708.      *
  709.      * @return  string
  710.      */
  711.     private function getConsumerKey()
  712.     {
  713.         return $this->consumerKey;
  714.     }
  715.  
  716.  
  717.     /**
  718.      * Get the consumer secret
  719.      *
  720.      * @return  string
  721.      */
  722.     private function getConsumerSecret()
  723.     {
  724.         return $this->consumerSecret;
  725.     }
  726.  
  727.  
  728.     /**
  729.      * Get the oAuth-token
  730.      *
  731.      * @return  string
  732.      */
  733.     private function getOAuthToken()
  734.     {
  735.         return $this->oAuthToken;
  736.     }
  737.  
  738.  
  739.     /**
  740.      * Get the oAuth-token-secret
  741.      *
  742.      * @return  string
  743.      */
  744.     private function getOAuthTokenSecret()
  745.     {
  746.         return $this->oAuthTokenSecret;
  747.     }
  748.  
  749.  
  750.     /**
  751.      * Get the timeout
  752.      *
  753.      * @return  int
  754.      */
  755.     public function getTimeOut()
  756.     {
  757.         return (int) $this->timeOut;
  758.     }
  759.  
  760.  
  761.     /**
  762.      * Get the useragent that will be used. Our version will be prepended to yours.
  763.      * It will look like: "PHP Twitter/<version> <your-user-agent>"
  764.      *
  765.      * @return  string
  766.      */
  767.     public function getUserAgent()
  768.     {
  769.         return (string) 'PHP Twitter/' . self::VERSION . ' ' . $this->userAgent;
  770.     }
  771.  
  772.  
  773.     /**
  774.      * Set the consumer key
  775.      *
  776.      * @return  void
  777.      * @param   string $key     The consumer key to use.
  778.      */
  779.     private function setConsumerKey($key)
  780.     {
  781.         $this->consumerKey = (string) $key;
  782.     }
  783.  
  784.  
  785.     /**
  786.      * Set the consumer secret
  787.      *
  788.      * @return  void
  789.      * @param   string $secret  The consumer secret to use.
  790.      */
  791.     private function setConsumerSecret($secret)
  792.     {
  793.         $this->consumerSecret = (string) $secret;
  794.     }
  795.  
  796.  
  797.     /**
  798.      * Set the oAuth-token
  799.      *
  800.      * @return  void
  801.      * @param   string $token   The token to use.
  802.      */
  803.     public function setOAuthToken($token)
  804.     {
  805.         $this->oAuthToken = (string) $token;
  806.     }
  807.  
  808.  
  809.     /**
  810.      * Set the oAuth-secret
  811.      *
  812.      * @return  void
  813.      * @param   string $secret  The secret to use.
  814.      */
  815.     public function setOAuthTokenSecret($secret)
  816.     {
  817.         $this->oAuthTokenSecret = (string) $secret;
  818.     }
  819.  
  820.  
  821.     /**
  822.      * Set the timeout
  823.      *
  824.      * @return  void
  825.      * @param   int $seconds    The timeout in seconds.
  826.      */
  827.     public function setTimeOut($seconds)
  828.     {
  829.         $this->timeOut = (int) $seconds;
  830.     }
  831.  
  832.  
  833.     /**
  834.      * Get the useragent that will be used. Our version will be prepended to yours.
  835.      * It will look like: "PHP Twitter/<version> <your-user-agent>"
  836.      *
  837.      * @return  void
  838.      * @param   string $userAgent   Your user-agent, it should look like <app-name>/<app-version>.
  839.      */
  840.     public function setUserAgent($userAgent)
  841.     {
  842.         $this->userAgent = (string) $userAgent;
  843.     }
  844.  
  845.  
  846.     /**
  847.      * Build the signature for the data
  848.      *
  849.      * @return  string
  850.      * @param   string $key     The key to use for signing.
  851.      * @param   string $data    The data that has to be signed.
  852.      */
  853.     private function hmacsha1($key, $data)
  854.     {
  855.         return base64_encode(hash_hmac('SHA1', $data, $key, true));
  856.     }
  857.  
  858.  
  859.     /**
  860.      * URL-encode method for internal use
  861.      *
  862.      * @return  string
  863.      * @param   mixed $value    The value to encode.
  864.      */
  865.     private static function urlencode_rfc3986($value)
  866.     {
  867.         if(is_array($value)) return array_map(array('Twitter', 'urlencode_rfc3986'), $value);
  868.         else
  869.         {
  870.             $search = array('+', ' ', '%7E', '%');
  871.             $replace = array('%20', '%20', '~', '%25');
  872.  
  873.             return str_replace($search, $replace, urlencode($value));
  874.         }
  875.     }
  876.  
  877.  
  878. // Timeline resources
  879.     /**
  880.      * Returns the 20 most recent statuses from non-protected users who have set a custom user icon.
  881.      * The public timeline is cached for 60 seconds and requesting it more often than that is unproductive and a waste of resources.
  882.      *
  883.      * @return  array
  884.      * @param   bool[optional] $trimUser            When set to true each tweet returned in a timeline will include a user object including only the status authors numerical ID. Omit this parameter to receive the complete user object.
  885.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  886.      */
  887.     public function statusesPublicTimeline($trimUser = false, $includeEntities = false)
  888.     {
  889.         // redefine
  890.         $trimUser = (bool) $trimUser;
  891.         $includeEntities = (bool) $includeEntities;
  892.  
  893.         // build parameters
  894.         $parameters = array();
  895.         if($trimUser) $parameters['trim_user'] = 'true';
  896.         if($includeEntities) $parameters['include_entities'] = 'true';
  897.  
  898.         // make the call
  899.         return (array) $this->doCall('statuses/public_timeline.json', $parameters);
  900.     }
  901.  
  902.  
  903.     /**
  904.      * Returns the 20 most recent statuses, including retweets if they exist, posted by the authenticating user and the user's they follow. This is the same timeline seen by a user when they login to twitter.com.
  905.      * This method is identical to statusesFriendsTimeline, except that this method always includes retweets.
  906.      *
  907.      * @return  array
  908.      * @param   string[optional] $sinceId           Returns results with an ID greater than (that is, more recent than) the specified ID.
  909.      * @param   string[optional] $maxId             Returns results with an ID less than (that is, older than) or equal to the specified ID.
  910.      * @param   int[optional] $count                Specifies the number of records to retrieve. May not be greater than 200.
  911.      * @param   int[optional] $page                 Specifies the page of results to retrieve.
  912.      * @param   bool[optional] $trimUser            When set to true each tweet returned in a timeline will include a user object including only the status authors numerical ID. Omit this parameter to receive the complete user object.
  913.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  914.      */
  915.     public function statusesHomeTimeline($sinceId = null, $maxId = null, $count = null, $page = null, $trimUser = false, $includeEntities = false)
  916.     {
  917.         // build parameters
  918.         $parameters = array();
  919.         if($sinceId != null) $parameters['since_id'] = (string) $sinceId;
  920.         if($maxId != null) $parameters['max_id'] = (string) $maxId;
  921.         if($count != null) $parameters['count'] = (int) $count;
  922.         if($page != null) $parameters['page'] = (int) $page;
  923.         if($trimUser) $parameters['trim_user'] = 'true';
  924.         if($includeEntities) $parameters['include_entities'] = 'true';
  925.  
  926.         // make the call
  927.         return (array) $this->doCall('statuses/home_timeline.json', $parameters, true);
  928.     }
  929.  
  930.  
  931.     /**
  932.      * Returns the 20 most recent statuses posted by the authenticating user and the user's they follow. This is the same timeline seen by a user when they login to twitter.com.
  933.      * This method is identical to statuses/home_timeline, except that this method will only include retweets if the includeRts parameter is set.
  934.      *
  935.      * @return  array
  936.      * @param   string[optional] $sinceId           Returns results with an ID greater than (that is, more recent than) the specified ID.
  937.      * @param   string[optional] $maxId             Returns results with an ID less than (that is, older than) or equal to the specified ID.
  938.      * @param   int[optional] $count                Specifies the number of records to retrieve. May not be greater than 200.
  939.      * @param   int[optional] $page                 Specifies the page of results to retrieve.
  940.      * @param   bool[optional] $trimUser            When set to true each tweet returned in a timeline will include a user object including only the status authors numerical ID. Omit this parameter to receive the complete user object.
  941.      * @param   bool[optional] $includeRts          When set to true the timeline will contain native retweets (if they exist) in addition to the standard stream of tweets. The output format of retweeted tweets is identical to the representation you see in home_timeline. Note: If you're using the trim_user parameter in conjunction with include_rts, the retweets will still contain a full user object.
  942.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  943.      */
  944.     public function statusesFriendsTimeline($sinceId = null, $maxId = null, $count = null, $page = null, $trimUser = false, $includeRts = false, $includeEntities = false)
  945.     {
  946.         // build parameters
  947.         $parameters = array();
  948.         if($sinceId != null) $parameters['since_id'] = (string) $sinceId;
  949.         if($maxId != null) $parameters['max_id'] = (string) $maxId;
  950.         if($count != null) $parameters['count'] = (int) $count;
  951.         if($page != null) $parameters['page'] = (int) $page;
  952.         if($trimUser) $parameters['trim_user'] = 'true';
  953.         if($includeRts) $parameters['include_rts'] = 'true';
  954.         if($includeEntities) $parameters['include_entities'] = 'true';
  955.  
  956.         // make the call
  957.         return (array) $this->doCall('statuses/friends_timeline.json', $parameters, true);
  958.     }
  959.  
  960.  
  961.     /**
  962.      * Returns the 20 most recent statuses posted by the authenticating user. It is also possible to request another user's timeline by using the screen_name or user_id parameter. The other users timeline will only be visible if they are not protected, or if the authenticating user's follow request was accepted by the protected user.
  963.      * The timeline returned is the equivalent of the one seen when you view a user's profile on twitter.com.
  964.      *
  965.      * @return  array
  966.      * @param   string[optional] $userId            Specfies the ID of the user for whom to return results for. Helpful for disambiguating when a valid user ID is also a valid screen name.
  967.      * @param   string[optional] $screenName        Specfies the screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  968.      * @param   string[optional] $sinceId           Returns results with an ID greater than (that is, more recent than) the specified ID.
  969.      * @param   string[optional] $maxId             Returns results with an ID less than (that is, older than) or equal to the specified ID.
  970.      * @param   int[optional] $count                Specifies the number of records to retrieve. May not be greater than 200.
  971.      * @param   int[optional] $page                 Specifies the page of results to retrieve.
  972.      * @param   bool[optional] $trimUser            When set to true each tweet returned in a timeline will include a user object including only the status authors numerical ID. Omit this parameter to receive the complete user object.
  973.      * @param   bool[optional] $includeRts          When set to true the timeline will contain native retweets (if they exist) in addition to the standard stream of tweets. The output format of retweeted tweets is identical to the representation you see in home_timeline. Note: If you're using the trim_user parameter in conjunction with include_rts, the retweets will still contain a full user object.
  974.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  975.      */
  976.     public function statusesUserTimeline($userId = null, $screenName = null, $sinceId = null, $maxId = null, $count = null, $page = null, $trimUser = false, $includeRts = false, $includeEntities = false)
  977.     {
  978.         // build parameters
  979.         $parameters = array();
  980.         if($userId != null) $parameters['user_id'] = (string) $userId;
  981.         if($screenName != null) $parameters['screen_name'] = (string) $screenName;
  982.         if($sinceId != null) $parameters['since_id'] = (string) $sinceId;
  983.         if($maxId != null) $parameters['max_id'] = (string) $maxId;
  984.         if($count != null) $parameters['count'] = (int) $count;
  985.         if($page != null) $parameters['page'] = (int) $page;
  986.         if($trimUser) $parameters['trim_user'] = 'true';
  987.         if($includeRts) $parameters['include_rts'] = 'true';
  988.         if($includeEntities) $parameters['include_entities'] = 'true';
  989.  
  990.         // make the call
  991.         return (array) $this->doCall('statuses/user_timeline.json', $parameters);
  992.     }
  993.  
  994.  
  995.     /**
  996.      * Returns the 20 most recent mentions (status containing @username) for the authenticating user.
  997.      * The timeline returned is the equivalent of the one seen when you view your mentions on twitter.com.
  998.      *
  999.      * @return  array
  1000.      * @param   string[optional] $sinceId           Returns results with an ID greater than (that is, more recent than) the specified ID.
  1001.      * @param   string[optional] $maxId             Returns results with an ID less than (that is, older than) or equal to the specified ID.
  1002.      * @param   int[optional] $count                Specifies the number of records to retrieve. May not be greater than 200.
  1003.      * @param   int[optional] $page                 Specifies the page of results to retrieve.
  1004.      * @param   bool[optional] $trimUser            When set to either true, each tweet returned in a timeline will include a user object including only the status authors numerical ID. Omit this parameter to receive the complete user object.
  1005.      * @param   bool[optional] $includeRts          When set to either true, the timeline will contain native retweets (if they exist) in addition to the standard stream of tweets. The output format of retweeted tweets is identical to the representation you see in home_timeline. Note: If you're using the trim_user parameter in conjunction with include_rts, the retweets will still contain a full user object.
  1006.      * @param   bool[optional] $includeEntities     When set to either true, each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags. While entities are opt-in on timelines at present, they will be made a default component of output in the future.
  1007.      */
  1008.     public function statusesMentions($sinceId = null, $maxId = null, $count = null, $page = null, $trimUser = false, $includeRts = false, $includeEntities = false)
  1009.     {
  1010.         // validate
  1011.         if($count != null && $count > 200) throw new TwitterException('Count may not be greater than 200.');
  1012.  
  1013.         // build parameters
  1014.         $parameters = array();
  1015.         if($sinceId != null) $parameters['since_id'] = (string) $sinceId;
  1016.         if($maxId != null) $parameters['max_id'] = (string) $maxId;
  1017.         if($count != null) $parameters['count'] = (int) $count;
  1018.         if($page != null) $parameters['page'] = (int) $page;
  1019.         if($trimUser) $parameters['trim_user'] = 'true';
  1020.         if($includeRts) $parameters['include_rts'] = 'true';
  1021.         if($includeEntities) $parameters['include_entities'] = 'true';
  1022.  
  1023.         // make the call
  1024.         return (array) $this->doCall('statuses/mentions.json', $parameters, true);
  1025.     }
  1026.  
  1027.  
  1028.     /**
  1029.      * Returns the 20 most recent retweets posted by the authenticating user.
  1030.      *
  1031.      * @return  array
  1032.      * @param   string[optional] $sinceId           Returns results with an ID greater than (that is, more recent than) the specified ID.
  1033.      * @param   string[optional] $maxId             Returns results with an ID less than (that is, older than) or equal to the specified ID.
  1034.      * @param   int[optional] $count                Specifies the number of records to retrieve. May not be greater than 200.
  1035.      * @param   int[optional] $page                 Specifies the page of results to retrieve.
  1036.      * @param   bool[optional] $trimUser            When set to true each tweet returned in a timeline will include a user object including only the status authors numerical ID. Omit this parameter to receive the complete user object.
  1037.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1038.      */
  1039.     public function statusesRetweetedByMe($sinceId = null, $maxId = null, $count = null, $page = null, $trimUser = false, $includeEntities = false)
  1040.     {
  1041.         // validate
  1042.         if($count != null && $count > 200) throw new TwitterException('Count may not be greater than 200.');
  1043.  
  1044.         // build parameters
  1045.         $parameters = array();
  1046.         if($sinceId != null) $parameters['since_id'] = (string) $sinceId;
  1047.         if($maxId != null) $parameters['max_id'] = (string) $maxId;
  1048.         if($count != null) $parameters['count'] = (int) $count;
  1049.         if($page != null) $parameters['page'] = (int) $page;
  1050.         if($trimUser) $parameters['trim_user'] = 'true';
  1051.         if($includeEntities) $parameters['include_entities'] = 'true';
  1052.  
  1053.         // make the call
  1054.         return (array) $this->doCall('statuses/retweeted_by_me.json', $parameters, true);
  1055.     }
  1056.  
  1057.  
  1058.     /**
  1059.      * Returns the 20 most recent retweets posted by users the authenticating user follow.
  1060.      *
  1061.      * @return  array
  1062.      * @param   string[optional] $sinceId           Returns results with an ID greater than (that is, more recent than) the specified ID.
  1063.      * @param   string[optional] $maxId             Returns results with an ID less than (that is, older than) or equal to the specified ID.
  1064.      * @param   int[optional] $count                Specifies the number of records to retrieve. May not be greater than 200.
  1065.      * @param   int[optional] $page                 Specifies the page of results to retrieve.
  1066.      * @param   bool[optional] $trimUser            When set to true each tweet returned in a timeline will include a user object including only the status authors numerical ID. Omit this parameter to receive the complete user object.
  1067.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1068.      */
  1069.     public function statusesRetweetedToMe($sinceId = null, $maxId = null, $count = null, $page = null, $trimUser = false, $includeEntities = false)
  1070.     {
  1071.         // validate
  1072.         if($count != null && $count > 200) throw new TwitterException('Count may not be greater than 200.');
  1073.  
  1074.         // build parameters
  1075.         $parameters = array();
  1076.         if($sinceId != null) $parameters['since_id'] = (string) $sinceId;
  1077.         if($maxId != null) $parameters['max_id'] = (string) $maxId;
  1078.         if($count != null) $parameters['count'] = (int) $count;
  1079.         if($page != null) $parameters['page'] = (int) $page;
  1080.         if($trimUser) $parameters['trim_user'] = 'true';
  1081.         if($includeEntities) $parameters['include_entities'] = 'true';
  1082.  
  1083.         // make the call
  1084.         return (array) $this->doCall('statuses/retweeted_by_me.json', $parameters, true);
  1085.     }
  1086.  
  1087.  
  1088.     /**
  1089.      * Returns the 20 most recent tweets of the authenticated user that have been retweeted by others.
  1090.      *
  1091.      * @return  array
  1092.      * @param   string[optional] $sinceId           Returns results with an ID greater than (that is, more recent than) the specified ID.
  1093.      * @param   string[optional] $maxId             Returns results with an ID less than (that is, older than) or equal to the specified ID.
  1094.      * @param   int[optional] $count                Specifies the number of records to retrieve. May not be greater than 200.
  1095.      * @param   int[optional] $page                 Specifies the page of results to retrieve.
  1096.      * @param   bool[optional] $trimUser            When set to true each tweet returned in a timeline will include a user object including only the status authors numerical ID. Omit this parameter to receive the complete user object.
  1097.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1098.      */
  1099.     public function statusesReweetsOfMe($sinceId = null, $maxId = null, $count = null, $page = null, $trimUser = false, $includeEntities = false)
  1100.     {
  1101.         // validate
  1102.         if($count != null && $count > 200) throw new TwitterException('Count may not be greater than 200.');
  1103.  
  1104.         // build parameters
  1105.         $parameters = array();
  1106.         if($sinceId != null) $parameters['since_id'] = (string) $sinceId;
  1107.         if($maxId != null) $parameters['max_id'] = (string) $maxId;
  1108.         if($count != null) $parameters['count'] = (int) $count;
  1109.         if($page != null) $parameters['page'] = (int) $page;
  1110.         if($trimUser) $parameters['trim_user'] = 'true';
  1111.         if($includeEntities) $parameters['include_entities'] = 'true';
  1112.  
  1113.         // make the call
  1114.         return (array) $this->doCall('statuses/retweets_of_me.json', $parameters, true);
  1115.     }
  1116.  
  1117.  
  1118. // Tweets resources
  1119.     /**
  1120.      * Returns a single status, specified by the id parameter below. The status's author will be returned inline.
  1121.      *
  1122.      * @return  array
  1123.      * @param   string $id                          The numerical ID of the desired status.
  1124.      * @param   bool[optional] $trimUser            When set to true each tweet returned in a timeline will include a user object including only the status authors numerical ID. Omit this parameter to receive the complete user object.
  1125.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1126.      */
  1127.     public function statusesShow($id, $trimUser = false, $includeEntities = false)
  1128.     {
  1129.         // build parameters
  1130.         $parameters['id'] = (string) $id;
  1131.         if($trimUser) $parameters['trim_user'] = 'true';
  1132.         if($includeEntities) $parameters['include_entities'] = 'true';
  1133.  
  1134.         // make the call
  1135.         return (array) $this->doCall('statuses/show.json', $parameters, true);
  1136.     }
  1137.  
  1138.  
  1139.     /**
  1140.      * Updates the authenticating user's status. A status update with text identical to the authenticating user's text identical to the authenticating user's current status will be ignored to prevent duplicates.
  1141.      *
  1142.      * @return  array
  1143.      * @param   string $status                          The text of your status update, up to 140 characters. URL encode as necessary.
  1144.      * @param   string[optional] $inReplyToStatusId     The ID of an existing status that the update is in reply to.
  1145.      * @param   float[optional] $lat                    The location's latitude that this tweet refers to.
  1146.      * @param   float[optional] $long                   The location's longitude that this tweet refers to.
  1147.      * @param   string[optional] $placeId               A place in the world. These IDs can be retrieved from geo/reverse_geocode.
  1148.      * @param   bool[optional] $displayCoordinates      Whether or not to put a pin on the exact coordinates a tweet has been sent from.
  1149.      * @param   bool[optional] $trimUser                When set to true each tweet returned in a timeline will include a user object including only the status authors numerical ID. Omit this parameter to receive the complete user object.
  1150.      * @param   bool[optional] $includeEntities         When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1151.      */
  1152.     public function statusesUpdate($status, $inReplyToStatusId = null, $lat = null, $long = null, $placeId = null, $displayCoordinates = false, $trimUser = false, $includeEntities = false)
  1153.     {
  1154.         // build parameters
  1155.         $parameters['status'] = (string) $status;
  1156.         if($inReplyToStatusId != null) $parameters['in_reply_to_status_id'] = (string) $inReplyToStatusId;
  1157.         if($lat != null) $parameters['lat'] = (float) $lat;
  1158.         if($long != null) $parameters['long'] = (float) $long;
  1159.         if($placeId != null) $parameters['place_id'] = (string) $placeId;
  1160.         if($displayCoordinates) $parameters['display_coordinates'] = 'true';
  1161.         if($trimUser) $parameters['trim_user'] = 'true';
  1162.         if($includeEntities) $parameters['include_entities'] = 'true';
  1163.  
  1164.         // make the call
  1165.         return (array) $this->doCall('statuses/update.json', $parameters, true, 'POST');
  1166.     }
  1167.  
  1168.  
  1169.     /**
  1170.      * Destroys the status specified by the required ID parameter.
  1171.      * Usage note: The authenticating user must be the author of the specified status.
  1172.      *
  1173.      * @return  bool
  1174.      * @param   string $id                          The numerical ID of the desired status.
  1175.      * @param   bool[optional] $trimUser            When set to true each tweet returned in a timeline will include a user object including only the status authors numerical ID. Omit this parameter to receive the complete user object.
  1176.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1177.      */
  1178.     public function statusesDestroy($id, $trimUser = false, $includeEntities = false)
  1179.     {
  1180.         // build parameters
  1181.         $parameters['id'] = (string) $id;
  1182.         if($trimUser) $parameters['trim_user'] = 'true';
  1183.         if($includeEntities) $parameters['include_entities'] = 'true';
  1184.  
  1185.         // make the call
  1186.         return (array) $this->doCall('statuses/destroy.json', $parameters, true, 'POST');
  1187.     }
  1188.  
  1189.  
  1190.     /**
  1191.      * Retweets a tweet. Returns the original tweet with retweet details embedded.
  1192.      *
  1193.      * @return  array
  1194.      * @param   string $id                          The numerical ID of the desired status.
  1195.      * @param   bool[optional] $trimUser            When set to true each tweet returned in a timeline will include a user object including only the status authors numerical ID. Omit this parameter to receive the complete user object.
  1196.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1197.      */
  1198.     public function statusesRetweet($id, $trimUser = false, $includeEntities = false)
  1199.     {
  1200.         $parameters = null;
  1201.         if($trimUser) $parameters['trim_user'] = 'true';
  1202.         if($includeEntities) $parameters['include_entities'] = 'true';
  1203.  
  1204.         // make the call
  1205.         return (array) $this->doCall('statuses/retweet/' . $id . '.json', $parameters, true, 'POST');
  1206.     }
  1207.  
  1208.  
  1209.     /**
  1210.      * Returns up to 100 of the first retweets of a given tweet.
  1211.      *
  1212.      * @return  array
  1213.      * @param   string $id                          The numerical ID of the desired status.
  1214.      * @param   int[optional] $count                Specifies the number of records to retrieve. May not be greater than 100.
  1215.      * @param   bool[optional] $trimUser            When set to true each tweet returned in a timeline will include a user object including only the status authors numerical ID. Omit this parameter to receive the complete user object.
  1216.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1217.      */
  1218.     public function statusesRetweets($id, $count = null, $trimUser = false, $includeEntities = false)
  1219.     {
  1220.         // validate
  1221.         if($count != null && $count > 100) throw new TwitterException('Count may not be greater than 100.');
  1222.  
  1223.         // build parameters
  1224.         $parameters = null;
  1225.         if($count != null) $parameters['count'] = (int) $count;
  1226.         if($trimUser) $parameters['trim_user'] = 'true';
  1227.         if($includeEntities) $parameters['include_entities'] = 'true';
  1228.  
  1229.         // make the call
  1230.         return (array) $this->doCall('statuses/retweets/' . $id . '.json', $parameters);
  1231.     }
  1232.  
  1233.  
  1234.     /**
  1235.      * Show user objects of up to 100 members who retweeted the status.
  1236.      *
  1237.      * @return  array
  1238.      * @param   string $id                          The numerical ID of the desired status.
  1239.      * @param   int[optional] $count                Specifies the number of records to retrieve. May not be greater than 200.
  1240.      * @param   int[optional] $page                 Specifies the page of results to retrieve.
  1241.      * @param   bool[optional] $trimUser            When set to true each tweet returned in a timeline will include a user object including only the status authors numerical ID. Omit this parameter to receive the complete user object.
  1242.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1243.      */
  1244.     public function statusesIdRetweetedBy($id, $count = null, $page = null, $trimUser = false, $includeEntities = false)
  1245.     {
  1246.         // validate
  1247.         if($count != null && $count > 200) throw new TwitterException('Count may not be greater than 200.');
  1248.  
  1249.         // build parameters
  1250.         $parameters = null;
  1251.         if($count != null) $parameters['count'] = (int) $count;
  1252.         if($page != null) $parameters['page'] = (int) $page;
  1253.         if($trimUser) $parameters['trim_user'] = 'true';
  1254.         if($includeEntities) $parameters['include_entities'] = 'true';
  1255.  
  1256.         // make the call
  1257.         return (array) $this->doCall('statuses/' . (string) $id . '/retweeted_by.json', $parameters, true);
  1258.     }
  1259.  
  1260.  
  1261.     /**
  1262.      * Show user ids of up to 100 users who retweeted the status.
  1263.      *
  1264.      * @return  array
  1265.      * @param   string $id                          The numerical ID of the desired status.
  1266.      * @param   int[optional] $count                Specifies the number of records to retrieve. May not be greater than 200.
  1267.      * @param   int[optional] $page                 Specifies the page of results to retrieve.
  1268.      * @param   bool[optional] $trimUser            When set to true each tweet returned in a timeline will include a user object including only the status authors numerical ID. Omit this parameter to receive the complete user object.
  1269.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1270.      */
  1271.     public function statusesIdRetweetedByIds($id, $count = null, $page = null, $trimUser = false, $includeEntities = false)
  1272.     {
  1273.         // validate
  1274.         if($count != null && $count > 200) throw new TwitterException('Count may not be greater than 200.');
  1275.  
  1276.         // build parameters
  1277.         $parameters = null;
  1278.         if($count != null) $parameters['count'] = (int) $count;
  1279.         if($page != null) $parameters['page'] = (int) $page;
  1280.         if($trimUser) $parameters['trim_user'] = 'true';
  1281.         if($includeEntities) $parameters['include_entities'] = 'true';
  1282.  
  1283.         // make the call
  1284.         return (array) $this->doCall('statuses/' . (string) $id . '/retweeted_by/ids.json', $parameters, true);
  1285.     }
  1286.  
  1287.  
  1288. // User resources
  1289.     /**
  1290.      * Returns extended information of a given user, specified by ID or screen name as per the required id parameter.
  1291.      * The author's most recent status will be returned inline.
  1292.      *
  1293.      * @return  array
  1294.      * @param   string[optional] $userId            Specfies the ID of the user for whom to return results for. Helpful for disambiguating when a valid user ID is also a valid screen name.
  1295.      * @param   string[optional] $screenName        Specfies the screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  1296.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1297.      */
  1298.     public function usersShow($userId = null, $screenName = null, $includeEntities = false)
  1299.     {
  1300.         // validate
  1301.         if($userId == '' && $screenName == '') throw new TwitterException('Specify an userId or a screenName.');
  1302.  
  1303.         // build parameters
  1304.         $parameters = null;
  1305.         if($userId != null) $parameters['user_id'] = (string) $userId;
  1306.         if($screenName != null) $parameters['screen_name'] = (string) $screenName;
  1307.         if($includeEntities) $parameters['include_entities'] = 'true';
  1308.  
  1309.         // make the call
  1310.         return (array) $this->doCall('users/show.json', $parameters);
  1311.     }
  1312.  
  1313.  
  1314.     /**
  1315.      * Return up to 100 users worth of extended information, specified by either ID, screen name, or combination of the two.
  1316.      * The author's most recent status (if the authenticating user has permission) will be returned inline.
  1317.      *
  1318.      * @return  array
  1319.      * @param   mixed[optional] $userIds            An array of user IDs, up to 100 in total.
  1320.      * @param   mixed[optional] $screenNames        An array of screen names, up to 100 in total.
  1321.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1322.      */
  1323.     public function usersLookup($userIds = null, $screenNames = null, $includeEntities = false)
  1324.     {
  1325.         // redefine
  1326.         $userIds = (array) $userIds;
  1327.         $screenNames = (array) $screenNames;
  1328.  
  1329.         // validate
  1330.         if(empty($userIds) && empty($screenNames)) throw new TwitterException('Specify an userId or a screenName.');
  1331.  
  1332.         // build parameters
  1333.         $parameters = null;
  1334.         if(!empty($userIds)) $parameters['user_id'] = implode(',', $userIds);
  1335.         if(!empty($screenNames)) $parameters['screen_name'] = implode(',', $screenNames);
  1336.         if($includeEntities) $parameters['include_entities'] = 'true';
  1337.  
  1338.         // make the call
  1339.         return (array) $this->doCall('users/lookup.json', $parameters, true);
  1340.  
  1341.     }
  1342.  
  1343.  
  1344.     /**
  1345.      * Run a search for users similar to the Find People button on Twitter.com; the same results returned by people search on Twitter.com will be returned by using this API.
  1346.      * Usage note: It is only possible to retrieve the first 1000 matches from this API.
  1347.      *
  1348.      * @return  array
  1349.      * @param   string $q                           The search query term.
  1350.      * @param   int[optional] $perPage              Specifies the number of results to retrieve.
  1351.      * @param   int[optional] $page                 Specifies the page of results to retrieve.
  1352.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1353.      */
  1354.     public function usersSearch($q, $perPage = null, $page = null, $includeEntities = false)
  1355.     {
  1356.         // build parameters
  1357.         $parameters['q'] = (string) $q;
  1358.         if($perPage != null) $parameters['per_page'] = (int) $perPage;
  1359.         if($page != null) $parameters['page'] = (int) $page;
  1360.         if($includeEntities) $parameters['include_entities'] = 'true';
  1361.  
  1362.         // make the call
  1363.         return (array) $this->doCall('users/search.json', $parameters, true);
  1364.     }
  1365.  
  1366.  
  1367.     /**
  1368.      * Access to Twitter's suggested user list. This returns the list of suggested user categories. The category can be used in the users/suggestions/category  endpoint to get the users in that category.
  1369.      *
  1370.      * @return  array
  1371.      */
  1372.     public function usersSuggestions()
  1373.     {
  1374.         return (array) $this->doCall('users/suggestions.json');
  1375.     }
  1376.  
  1377.  
  1378.     /**
  1379.      * Access the users in a given category of the Twitter suggested user list.
  1380.      * It is recommended that end clients cache this data for no more than one hour.
  1381.      *
  1382.      * @return  array
  1383.      * @param   string $slug    The short name of list or a category.
  1384.      */
  1385.     public function usersSuggestionsSlug($slug)
  1386.     {
  1387.         return (array) $this->doCall('users/suggestions/' . (string) $slug . '.json');
  1388.     }
  1389.  
  1390.  
  1391.     /**
  1392.      * Access the profile image in various sizes for the user with the indicated screen_name. If no size is provided the normal image is returned.
  1393.      * This method return an URL to the actual image resource.
  1394.      * This method should only be used by application developers to lookup or check the profile image URL for a user.
  1395.      * This method must not be used as the image source URL presented to users of your application.
  1396.      *
  1397.      * @return  string
  1398.      * @param   string $screenName          The screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  1399.      * @param   string[optional] $size      Specifies the size of image to fetch. Not specifying a size will give the default, normal size of 48px by 48px. Valid options include: bigger (73x73px), normal (48x48px), mini (24x24px).
  1400.      */
  1401.     public function usersProfileImage($screenName, $size = 'normal')
  1402.     {
  1403.         // possible modes
  1404.         $allowedSizes = array('normal', 'bigger', 'mini');
  1405.  
  1406.         // validate
  1407.         if($size != null && !in_array($size, $allowedSizes)) throw new TwitterException('Invalid size (' . $size . '), possible values are: ' . implode($allowedSizes) . '.');
  1408.  
  1409.         // build parameters
  1410.         $parameters['size'] = (string) $size;
  1411.  
  1412.         $headers = $this->doCall('users/profile_image/' . (string) $screenName . '.json', $parameters, false, 'GET', null, false, true);
  1413.  
  1414.         // return the URL
  1415.         if(isset($headers['url'])) return $headers['url'];
  1416.  
  1417.         // fallback
  1418.         return false;
  1419.     }
  1420.  
  1421.  
  1422.     /**
  1423.      * Returns a user's friends, each with current status inline. They are ordered by the order in which the user followed them, most recently followed first, 100 at a time.
  1424.      * (Please note that the result set isn't guaranteed to be 100 every time as suspended users will be filtered out.)
  1425.      *
  1426.      * Use the cursor option to access older friends.
  1427.      * With no user specified, request defaults to the authenticated user's friends.
  1428.      * It's also possible to request another user's friends list via the id, screen_name or user_id parameter.
  1429.      *
  1430.      * @return  array
  1431.      * @param   string[optional] $userId            Specfies the ID of the user for whom to return results for. Helpful for disambiguating when a valid user ID is also a valid screen name.
  1432.      * @param   string[optional] $screenName        Specfies the screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  1433.      * @param   int[optional] $cursor               Breaks the results into pages. This is recommended for users who are following many users. Provide a value of -1  to begin paging. Provide values as returned to in the response body's next_cursor  and previous_cursor attributes to page back and forth in the list.
  1434.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1435.      */
  1436.     public function statusesFriends($userId = null, $screenName = null, $cursor = null, $includeEntities = false)
  1437.     {
  1438.         // build parameters
  1439.         $parameters = array();
  1440.         if($userId != null) $parameters['user_id'] = (string) $userId;
  1441.         if($screenName != null) $parameters['screen_name'] = (string) $screenName;
  1442.         if($cursor != null) $parameters['cursor'] = $cursor;
  1443.         if($includeEntities) $parameters['include_entities'] = 'true';
  1444.  
  1445.         // make the call
  1446.         return (array) $this->doCall('statuses/friends.json', $parameters, true);
  1447.     }
  1448.  
  1449.  
  1450.     /**
  1451.      * Returns the authenticating user's followers, each with current status inline. They are ordered by the order in which they followed the user, 100 at a time. (Please note that the result set isn't guaranteed to be 100 every time as suspended users will be filtered out.)
  1452.      * Use the cursor parameter to access earlier followers.
  1453.      *
  1454.      * @return  array
  1455.      * @param   string[optional] $userId            Specfies the ID of the user for whom to return results for. Helpful for disambiguating when a valid user ID is also a valid screen name.
  1456.      * @param   string[optional] $screenName        Specfies the screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  1457.      * @param   int[optional] $cursor               Breaks the results into pages. This is recommended for users who are following many users. Provide a value of -1  to begin paging. Provide values as returned to in the response body's next_cursor  and previous_cursor attributes to page back and forth in the list.
  1458.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1459.      */
  1460.     public function statusesFollowers($userId = null, $screenName = null, $cursor = null, $includeEntities = false)
  1461.     {
  1462.         // build parameters
  1463.         $parameters = array();
  1464.         if($userId != null) $parameters['user_id'] = (string) $userId;
  1465.         if($screenName != null) $parameters['screen_name'] = (string) $screenName;
  1466.         if($cursor != null) $parameters['cursor'] = $cursor;
  1467.         if($includeEntities) $parameters['include_entities'] = 'true';
  1468.  
  1469.         // make the call
  1470.         return (array) $this->doCall('statuses/followers.json', $parameters, true);
  1471.     }
  1472.  
  1473.  
  1474. // Trends resources
  1475.     /**
  1476.      * Returns the top ten topics that are currently trending on Twitter.
  1477.      * The response includes the time of the request, the name of each trend, and the url to the Twitter Search results page for that topic.
  1478.      *
  1479.      * @return  array
  1480.      */
  1481.     public function trends()
  1482.     {
  1483.         return (array) $this->doCall('trends.json');
  1484.     }
  1485.  
  1486.  
  1487.     /**
  1488.      * Returns the current top 10 trending topics on Twitter. The response includes the time of the request, the name of each trending topic, and query used on Twitter Search results page for that topic.
  1489.      *
  1490.      * @return  array
  1491.      * @param   string[optional] $exclude   Setting this equal to hashtags will remove all hashtags from the trends list.
  1492.      */
  1493.     public function trendsCurrent($exclude = null)
  1494.     {
  1495.         // build parameters
  1496.         $parameters = null;
  1497.         if($exclude != null) $parameters['exclude'] = (string) $exclude;
  1498.  
  1499.         // make the call
  1500.         return (array) $this->doCall('trends/current.json', $parameters);
  1501.     }
  1502.  
  1503.  
  1504.     /**
  1505.      * Returns the top 20 trending topics for each hour in a given day.
  1506.      *
  1507.      * @return  array
  1508.      * @param   string[optional] $date      Permits specifying a start date for the report. The date should be formatted YYYY-MM-DD.
  1509.      * @param   string[optional] $exclude   Setting this equal to hashtags will remove all hashtags from the trends list.
  1510.      */
  1511.     public function trendsDaily($date = null, $exclude = null)
  1512.     {
  1513.         // build parameters
  1514.         $parameters = null;
  1515.         if($date != null) $parameters['date'] = (string) $date;
  1516.         if($exclude != null) $parameters['exclude'] = (string) $exclude;
  1517.  
  1518.         // make the call
  1519.         return (array) $this->doCall('trends/daily.json', $parameters);
  1520.     }
  1521.  
  1522.  
  1523.     /**
  1524.      * Returns the top 30 trending topics for each day in a given week.
  1525.      *
  1526.      * @return  array
  1527.      * @param   string[optional] $date      Permits specifying a start date for the report. The date should be formatted YYYY-MM-DD.
  1528.      * @param   string[optional] $exclude   Setting this equal to hashtags will remove all hashtags from the trends list.
  1529.      */
  1530.     public function trendsWeekly($date = null, $exclude = null)
  1531.     {
  1532.         // build parameters
  1533.         $parameters = null;
  1534.         if($date != null) $parameters['date'] = (string) $date;
  1535.         if($exclude != null) $parameters['exclude'] = (string) $exclude;
  1536.  
  1537.         // make the call
  1538.         return (array) $this->doCall('trends/weekly.json', $parameters);
  1539.     }
  1540.  
  1541.  
  1542. // List resources
  1543.     /**
  1544.      * Creates a new list for the authenticated user. Accounts are limited to 20 lists.
  1545.      *
  1546.      * @return  array
  1547.      * @param   string $user                    The user.
  1548.      * @param   string $name                    The name of the list you are creating.
  1549.      * @param   string[optional] $mode          Whether your list is public or private. Values can be public or private. Lists are public by default if no mode is specified.
  1550.      * @param   string[optional] $description   The description of the list you are creating.
  1551.      */
  1552.     public function userListsCreate($user, $name, $mode = null, $description = null)
  1553.     {
  1554.         // possible modes
  1555.         $allowedModes = array('public', 'private');
  1556.  
  1557.         // validate
  1558.         if($mode != null && !in_array($mode, $allowedModes)) throw new TwitterException('Invalid mode (), possible values are: ' . implode($allowedModes) . '.');
  1559.  
  1560.         // build parameters
  1561.         $parameters['name'] = (string) $name;
  1562.         if($mode != null) $parameters['mode'] = (string) $mode;
  1563.         if($description != null) $parameters['description'] = (string) $description;
  1564.  
  1565.         // make the call
  1566.         return (array) $this->doCall((string) $user . '/lists.json', $parameters, true, 'POST');
  1567.     }
  1568.  
  1569.  
  1570.     /**
  1571.      * List the lists of the specified user. Private lists will be included if the authenticated users is the same as the user who's lists are being returned.
  1572.      *
  1573.      * @return  array
  1574.      * @param   string $user                The user.
  1575.      * @param   string[optional] $cursor    Breaks the results into pages. This is recommended for users who are following many users. Provide a value of -1  to begin paging. Provide values as returned to in the response body's next_cursor  and previous_cursor attributes to page back and forth in the list.
  1576.      */
  1577.     public function userLists($user, $cursor = null)
  1578.     {
  1579.         $parameters = null;
  1580.         if($cursor != null) $parameters['cursor'] = (string) $cursor;
  1581.  
  1582.         // make the call
  1583.         return (array) $this->doCall((string) $user . '/lists.json', $parameters, true);
  1584.     }
  1585.  
  1586.  
  1587.     /**
  1588.      * Show the specified list. Private lists will only be shown if the authenticated user owns the specified list.
  1589.      *
  1590.      * @return  array
  1591.      * @param   string $user    The user.
  1592.      * @param   string $id      The id of the list.
  1593.      */
  1594.     public function userListsId($user, $id)
  1595.     {
  1596.         // make the call
  1597.         return (array) $this->doCall((string) $user . '/lists/' . (string) $id . '.json', null, true);
  1598.     }
  1599.  
  1600.  
  1601.     /**
  1602.      * Updates the specified list.
  1603.      *
  1604.      * @return  array
  1605.      * @param   string $user                    The user.
  1606.      * @param   string $id                      The id of the list.
  1607.      * @param   string[optional] $name          The name of the list you are creating.
  1608.      * @param   string[optional] $mode          Whether your list is public or private. Values can be public or private. Lists are public by default if no mode is specified.
  1609.      * @param   string[optional] $description   The description of the list you are creating.
  1610.      */
  1611.     public function userListsIdUpdate($user, $id, $name = null, $mode = null, $description = null)
  1612.     {
  1613.         // possible modes
  1614.         $allowedModes = array('public', 'private');
  1615.  
  1616.         // validate
  1617.         if($mode != null && !in_array($mode, $allowedModes)) throw new TwitterException('Invalid mode (), possible values are: ' . implode($allowedModes) . '.');
  1618.  
  1619.         // build parameters
  1620.         if($name != null) $parameters['name'] = (string) $name;
  1621.         if($mode != null) $parameters['mode'] = (string) $mode;
  1622.         if($description != null) $parameters['description'] = (string) $description;
  1623.  
  1624.         // make the call
  1625.         return (array) $this->doCall((string) $user . '/lists/' . (string) $id . '.json', $parameters, true, 'POST');
  1626.     }
  1627.  
  1628.  
  1629.     /**
  1630.      * Show tweet timeline for members of the specified list.
  1631.      *
  1632.      * @return  array
  1633.      * @param   string $user                        The user.
  1634.      * @param   string $id                          The id of the list.
  1635.      * @param   string[optional] $sinceId           Returns results with an ID greater than (that is, more recent than) the specified ID.
  1636.      * @param   string[optional] $maxId             Returns results with an ID less than (that is, older than) or equal to the specified ID.
  1637.      * @param   int[optional] $count                Specifies the number of records to retrieve. May not be greater than 200.
  1638.      * @param   int[optional] $page                 Specifies the page of results to retrieve.
  1639.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1640.      */
  1641.     public function userListsIdStatuses($user, $id, $sinceId = null, $maxId = null, $count = null, $page = null, $includeEntities = false)
  1642.     {
  1643.         // validate
  1644.         if($count != null && $count > 200) throw new TwitterException('Count may not be greater than 200.');
  1645.  
  1646.         // build parameters
  1647.         $parameters = array();
  1648.         if($sinceId != null) $parameters['since_id'] = (string) $sinceId;
  1649.         if($maxId != null) $parameters['max_id'] = (string) $maxId;
  1650.         if($count != null) $parameters['per_page'] = (int) $count;
  1651.         if($page != null) $parameters['page'] = (int) $page;
  1652.         if($includeEntities) $parameters['include_entities'] = 'true';
  1653.  
  1654.         // make the call
  1655.         return (array) $this->doCall((string) $user . '/lists/' . (string) $id . '/statuses.json', $parameters);
  1656.     }
  1657.  
  1658.  
  1659.     /**
  1660.      * List the lists the specified user has been added to.
  1661.      *
  1662.      * @return  array
  1663.      * @param   string $user                The user.
  1664.      * @param   string[optional] $cursor    Breaks the results into pages. This is recommended for users who are following many users. Provide a value of -1  to begin paging. Provide values as returned to in the response body's next_cursor  and previous_cursor attributes to page back and forth in the list.
  1665.      */
  1666.     public function userListsMemberships($user, $cursor = null)
  1667.     {
  1668.         // build parameters
  1669.         $parameters = null;
  1670.         if($cursor != null) $parameters['cursor'] = (string) $cursor;
  1671.  
  1672.         // make the call
  1673.         return (array) $this->doCall((string) $user . '/lists/memberships.json', $parameters, true);
  1674.     }
  1675.  
  1676.  
  1677.     /**
  1678.      * List the lists the specified user follows.
  1679.      *
  1680.      * @return  array
  1681.      * @param   string $user                The user.
  1682.      * @param   string[optional] $cursor    Breaks the results into pages. This is recommended for users who are following many users. Provide a value of -1  to begin paging. Provide values as returned to in the response body's next_cursor  and previous_cursor attributes to page back and forth in the list.
  1683.      */
  1684.     public function userListsSubscriptions($user, $cursor = null)
  1685.     {
  1686.         // build parameters
  1687.         $parameters = null;
  1688.         if($cursor != null) $parameters['cursor'] = (string) $cursor;
  1689.  
  1690.         // make the call
  1691.         return (array) $this->doCall((string) $user . '/lists/subscriptions.json', $parameters, true);
  1692.     }
  1693.  
  1694.  
  1695. // List Members resources
  1696.     /**
  1697.      * Returns the members of the specified list.
  1698.      *
  1699.      * @return  array
  1700.      * @param   string $user                        The user.
  1701.      * @param   string $id                          The id of the list.
  1702.      * @param   string[optional] $cursor            Breaks the results into pages. This is recommended for users who are following many users. Provide a value of -1  to begin paging. Provide values as returned to in the response body's next_cursor  and previous_cursor attributes to page back and forth in the list.
  1703.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1704.      */
  1705.     public function userListMembers($user, $id, $cursor = null, $includeEntities = false)
  1706.     {
  1707.         // build parameters
  1708.         $parameters = null;
  1709.         if($cursor != null) $parameters['cursor'] = (string) $cursor;
  1710.         if($includeEntities) $parameters['include_entities'] = 'true';
  1711.  
  1712.         // make the call
  1713.         return (array) $this->doCall((string) $user . '/' . (string) $id . '/members.json', $parameters, true);
  1714.     }
  1715.  
  1716.  
  1717.     /**
  1718.      * Add a member to a list. The authenticated user must own the list to be able to add members to it. Lists are limited to having 500 members.
  1719.      *
  1720.      * @return  array
  1721.      * @param   string $user    The user.
  1722.      * @param   string $id      The id of the list.
  1723.      * @param   string $userId  The id or screen name of the user to add as a member of the list.
  1724.      */
  1725.     public function userListMembersCreate($user, $id, $userId)
  1726.     {
  1727.         // build parameters
  1728.         $parameters['id'] = (string) $userId;
  1729.  
  1730.         // make the call
  1731.         return (array) $this->doCall((string) $user . '/' . (string) $id . '/members.json', $parameters, true, 'POST');
  1732.     }
  1733.  
  1734.  
  1735.     /**
  1736.      * Adds multiple members to a list, by specifying a comma-separated list of member ids or screen names. The authenticated user must own the list to be able to add members to it. Lists are limited to having 500 members, and you are limited to adding up to 100 members to a list at a time with this method.
  1737.      *
  1738.      * @return  array
  1739.      * @param   string $user                    The user.
  1740.      * @param   string $id                      The id of the list.
  1741.      * @param   mixed[optional] $userIds        An array of user IDs, up to 100 in total.
  1742.      * @param   mixed[optional] $screenNames    An array of screen names, up to 100 in total.
  1743.      */
  1744.     public function userListMembersCreateAll($user, $id, $userIds = null, $screenNames = null)
  1745.     {
  1746.         // redefine
  1747.         $userIds = (array) $userIds;
  1748.         $screenNames = (array) $screenNames;
  1749.  
  1750.         // validate
  1751.         if(empty($userIds) && empty($screenNames)) throw new TwitterException('Specify an userId or a screenName.');
  1752.  
  1753.         // build parameters
  1754.         $parameters = null;
  1755.         if(!empty($userIds)) $parameters['user_id'] = implode(',', $userIds);
  1756.         if(!empty($screenNames)) $parameters['screen_name'] = implode(',', $screenNames);
  1757.  
  1758.         // make the call
  1759.         return (array) $this->doCall((string) $user . '/' . (string) $id . '/create_all.json', $parameters, true, 'POST');
  1760.     }
  1761.  
  1762.  
  1763.     /**
  1764.      * Removes the specified member from the list. The authenticated user must be the list's owner to remove members from the list.
  1765.      *
  1766.      * @return  mixed
  1767.      * @param   string $user    The user.
  1768.      * @param   string $id      The id of the list.
  1769.      * @param   string $userId  Specfies the ID of the user for whom to return results for.
  1770.      */
  1771.     public function userListMembersDelete($user, $id, $userId)
  1772.     {
  1773.         // build parameters
  1774.         $parameters['id'] = (string) $userId;
  1775.         $parameters['_method'] = 'DELETE';
  1776.  
  1777.         // make the call
  1778.         return (array) $this->doCall((string) $user . '/' . (string) $id . '/members.json', $parameters, true, 'POST');
  1779.     }
  1780.  
  1781.  
  1782.     /**
  1783.      * Check if a user is a member of the specified list.
  1784.      *
  1785.      * @return  mixed
  1786.      * @param   string $user                        The user.
  1787.      * @param   string $id                          The id of the list.
  1788.      * @param   string $userId                      Specfies the ID of the user for whom to return results for.
  1789.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1790.      */
  1791.     public function userListMembersId($user, $id, $userId, $includeEntities = false)
  1792.     {
  1793.         try
  1794.         {
  1795.             // build parameters
  1796.             $parameters = null;
  1797.             if($includeEntities) $parameters['include_entities'] = 'true';
  1798.  
  1799.             // make the call
  1800.             return (array) $this->doCall((string) $user . '/' . (string) $id . '/members/' . (string) $userId . '.json', $parameters, true);
  1801.         }
  1802.  
  1803.         // catch exceptions
  1804.         catch(TwitterException $e)
  1805.         {
  1806.             if($e->getMessage() == 'The specified user is not a member of this list') return false;
  1807.             else throw $e;
  1808.         }
  1809.     }
  1810.  
  1811.  
  1812. // List Subscribers resources
  1813.     /**
  1814.      * Returns the subscribers of the specified list.
  1815.      *
  1816.      * @return  array
  1817.      * @param   string $user                        The user.
  1818.      * @param   string $id                          The id of the list.
  1819.      * @param   string[optional] $cursor            Breaks the results into pages. This is recommended for users who are following many users. Provide a value of -1  to begin paging. Provide values as returned to in the response body's next_cursor  and previous_cursor attributes to page back and forth in the list.
  1820.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1821.      */
  1822.     public function userListSubscribers($user, $id, $cursor = null, $includeEntities = false)
  1823.     {
  1824.         // build parameters
  1825.         $parameters = null;
  1826.         if($cursor != null) $parameters['cursor'] = (string) $cursor;
  1827.         if($includeEntities) $parameters['include_entities'] = 'true';
  1828.  
  1829.         // make the call
  1830.         return (array) $this->doCall((string) $user . '/' . (string) $id . '/subscribers.json', $parameters, true);
  1831.     }
  1832.  
  1833.  
  1834.     /**
  1835.      * Make the authenticated user follow the specified list.
  1836.      *
  1837.      * @return  array
  1838.      * @param   string $user    The user.
  1839.      * @param   string $id      The id of the list.
  1840.      */
  1841.     public function userListSubscribersCreate($user, $id)
  1842.     {
  1843.         // make the call
  1844.         return (array) $this->doCall((string) $user . '/' . (string) $id . '/subscribers.json', null, true, 'POST');
  1845.     }
  1846.  
  1847.  
  1848.     /**
  1849.      * Unsubscribes the authenticated user form the specified list.
  1850.      *
  1851.      * @return  array
  1852.      * @param   string $user    The user.
  1853.      * @param   string $id      The id of the list.
  1854.      */
  1855.     public function userListSubscribersDelete($user, $id)
  1856.     {
  1857.         // build parameters
  1858.         $parameters['_method'] = 'DELETE';
  1859.  
  1860.         // make the call
  1861.         return (array) $this->doCall((string) $user . '/' . (string) $id . '/subscribers.json', $parameters, true, 'POST');
  1862.     }
  1863.  
  1864.  
  1865.     /**
  1866.      * Check if the specified user is a subscriber of the specified list.
  1867.      *
  1868.      * @return  mixed
  1869.      * @param   string $user                        The user.
  1870.      * @param   string $id                          The id of the list.
  1871.      * @param   string $userId                      Specfies the ID of the user for whom to return results for.
  1872.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1873.      */
  1874.     public function userListSubscribersId($user, $id, $userId, $includeEntities = false)
  1875.     {
  1876.         try
  1877.         {
  1878.             // build parameters
  1879.             $parameters = null;
  1880.             if($includeEntities) $parameters['include_entities'] = 'true';
  1881.  
  1882.             // make the call
  1883.             return (array) $this->doCall((string) $user . '/' . (string) $id . '/subscribers/' . (string) $userId . '.json', $parameters, true);
  1884.         }
  1885.  
  1886.         // catch exceptions
  1887.         catch(TwitterException $e)
  1888.         {
  1889.             if($e->getMessage() == 'The specified user is not a subscriber of this list') return false;
  1890.             else throw $e;
  1891.         }
  1892.  
  1893.     }
  1894.  
  1895.  
  1896. // Direct Messages resources
  1897.     /**
  1898.      * Returns a list of the 20 most recent direct messages sent to the authenticating user.
  1899.      *
  1900.      * @return  array
  1901.      * @param   string[optional] $sinceId           Returns results with an ID greater than (that is, more recent than) the specified ID.
  1902.      * @param   string[optional] $maxId             Returns results with an ID less than (that is, older than) or equal to the specified ID.
  1903.      * @param   int[optional] $count                Specifies the number of records to retrieve. May not be greater than 200.
  1904.      * @param   int[optional] $page                 Specifies the page of results to retrieve.
  1905.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1906.      */
  1907.     public function directMessages($sinceId = null, $maxId = null, $count = null, $page = null, $includeEntities = false)
  1908.     {
  1909.         // validate
  1910.         if($count != null && $count > 200) throw new TwitterException('Count may not be greater than 200.');
  1911.  
  1912.         // build parameters
  1913.         $parameters = array();
  1914.         if($sinceId != null) $parameters['since_id'] = (string) $sinceId;
  1915.         if($maxId != null) $parameters['max_id'] = (string) $maxId;
  1916.         if($count != null) $parameters['count'] = (int) $count;
  1917.         if($page != null) $parameters['page'] = (int) $page;
  1918.         if($includeEntities) $parameters['include_entities'] = 'true';
  1919.  
  1920.         // make the call
  1921.         return (array) $this->doCall('direct_messages.json', $parameters, true);
  1922.     }
  1923.  
  1924.  
  1925.     /**
  1926.      * Returns a list of the 20 most recent direct messages sent by the authenticating user.
  1927.      *
  1928.      * @return  array
  1929.      * @param   string[optional] $sinceId           Returns results with an ID greater than (that is, more recent than) the specified ID.
  1930.      * @param   string[optional] $maxId             Returns results with an ID less than (that is, older than) or equal to the specified ID.
  1931.      * @param   int[optional] $count                Specifies the number of records to retrieve. May not be greater than 200.
  1932.      * @param   int[optional] $page                 Specifies the page of results to retrieve.
  1933.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1934.      */
  1935.     public function directMessagesSent($sinceId = null, $maxId = null, $count = null, $page = null, $includeEntities = false)
  1936.     {
  1937.         // validate
  1938.         if($count != null && $count > 200) throw new TwitterException('Count may not be greater than 200.');
  1939.  
  1940.         // build parameters
  1941.         $parameters = array();
  1942.         if($sinceId != null) $parameters['since_id'] = (string) $sinceId;
  1943.         if($maxId != null) $parameters['max_id'] = (string) $maxId;
  1944.         if($count != null) $parameters['count'] = (int) $count;
  1945.         if($page != null) $parameters['page'] = (int) $page;
  1946.         if($includeEntities) $parameters['include_entities'] = 'true';
  1947.  
  1948.         // make the call
  1949.         return (array) $this->doCall('direct_messages/sent.json', $parameters, true);
  1950.     }
  1951.  
  1952.  
  1953.     /**
  1954.      * Sends a new direct message to the specified user from the authenticating user.
  1955.      * Requires both the user and text parameters. Returns the sent message in the requested format when successful.
  1956.      *
  1957.      * @return  array
  1958.      * @param   string $text                        The text of your direct message. Be sure to URL encode as necessary, and keep it under 140 characters.
  1959.      * @param   string[optional] $userId            Specfies the screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  1960.      * @param   string[optional] $screenName        Specfies the ID of the user for whom to return results for. Helpful for disambiguating when a valid user ID is also a valid screen name.
  1961.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1962.      */
  1963.     public function directMessagesNew($text, $userId = null, $screenName = null, $includeEntities = false)
  1964.     {
  1965.         // validate
  1966.         if($userId == '' && $screenName == '') throw new TwitterException('Specify an userId or a screenName.');
  1967.  
  1968.         // build parameters
  1969.         $parameters['text'] = (string) $text;
  1970.         if($userId != null) $parameters['user_id'] = (string) $userId;
  1971.         if($screenName != null) $parameters['screen_name'] = (string) $screenName;
  1972.         if($includeEntities) $parameters['include_entities'] = 'true';
  1973.  
  1974.         // make the call
  1975.         return (array) $this->doCall('direct_messages/new.json', $parameters, true, 'POST');
  1976.     }
  1977.  
  1978.  
  1979.     /**
  1980.      * Destroys the direct message specified in the required ID parameter. The authenticating user must be the recipient of the specified direct message.
  1981.      *
  1982.      * @return  array
  1983.      * @param   string $id                          The ID of the desired direct message.
  1984.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  1985.      */
  1986.     public function directMessagesDestroy($id, $includeEntities = false)
  1987.     {
  1988.         // build parameters
  1989.         $parameters['id'] = (string) $id;
  1990.         if($includeEntities) $parameters['include_entities'] = 'true';
  1991.  
  1992.         // make the call
  1993.         return (array) $this->doCall('direct_messages/destroy.json', $parameters, true, 'POST');
  1994.     }
  1995.  
  1996.  
  1997. // Friendship resources
  1998.     /**
  1999.      * Allows the authenticating users to follow the user specified in the ID parameter.
  2000.      * Returns the befriended user in the requested format when successful.
  2001.      * Returns a string describing the failure condition when unsuccessful.
  2002.      *
  2003.      * @return  mixed
  2004.      * @param   string[optional] $userId            Specfies the screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  2005.      * @param   string[optional] $screenName        Specfies the ID of the user for whom to return results for. Helpful for disambiguating when a valid user ID is also a valid screen name.
  2006.      * @param   bool[optional] $follow              Returns public statuses that reference the given set of users.
  2007.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2008.      */
  2009.     public function friendshipsCreate($userId = null, $screenName = null, $follow = false, $includeEntities = false)
  2010.     {
  2011.         // validate
  2012.         if($userId == '' && $screenName == '') throw new TwitterException('Specify an userId or a screenName.');
  2013.  
  2014.         // build parameters
  2015.         $parameters = null;
  2016.         if($userId != null) $parameters['user_id'] = (string) $userId;
  2017.         if($screenName != null) $parameters['screen_name'] = (string) $screenName;
  2018.         $parameters['follow'] = ($follow) ? 'true' : 'false';
  2019.         if($includeEntities) $parameters['include_entities'] = 'true';
  2020.  
  2021.         // make the call
  2022.         return (array) $this->doCall('friendships/create.json', $parameters, true, 'POST');
  2023.     }
  2024.  
  2025.  
  2026.     /**
  2027.      * Allows the authenticating users to unfollow the user specified in the ID parameter.
  2028.      * Returns the unfollowed user in the requested format when successful. Returns a string describing the failure condition when unsuccessful.
  2029.      *
  2030.      * @return  array
  2031.      * @param   string[optional] $userId            Specfies the screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  2032.      * @param   string[optional] $screenName        Specfies the ID of the user for whom to return results for. Helpful for disambiguating when a valid user ID is also a valid screen name.
  2033.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2034.      */
  2035.     public function friendshipsDestroy($userId = null, $screenName = null, $includeEntities = false)
  2036.     {
  2037.         // validate
  2038.         if($userId == '' && $screenName == '') throw new TwitterException('Specify an userId or a screenName.');
  2039.  
  2040.         // build parameters
  2041.         if($userId != null) $parameters['user_id'] = (string) $userId;
  2042.         if($screenName != null) $parameters['screen_name'] = (string) $screenName;
  2043.         if($includeEntities) $parameters['include_entities'] = 'true';
  2044.  
  2045.         // make the call
  2046.         return (array) $this->doCall('friendships/destroy.json', $parameters, true, 'POST');
  2047.     }
  2048.  
  2049.  
  2050.     /**
  2051.      * Tests for the existence of friendship between two users. Will return true if user_a follows user_b, otherwise will return false.
  2052.      *
  2053.      * @return  bool
  2054.      * @param   string $userA   The ID or screen_name of the subject user.
  2055.      * @param   string $userB   The ID or screen_name of the user to test for following.
  2056.      */
  2057.     public function friendshipsExists($userA, $userB)
  2058.     {
  2059.         // build parameters
  2060.         $parameters['user_a'] = (string) $userA;
  2061.         $parameters['user_b'] = (string) $userB;
  2062.  
  2063.         // make the call
  2064.         return (bool) $this->doCall('friendships/exists.json', $parameters);
  2065.     }
  2066.  
  2067.  
  2068.     /**
  2069.      * Returns detailed information about the relationship between two users.
  2070.      *
  2071.      * @return  array
  2072.      * @param   string[optional] $sourceId              The user_id of the subject user.
  2073.      * @param   string[optional] $sourceScreenName      The screen_name of the subject user.
  2074.      * @param   string[optional] $targetId              The screen_name of the subject user.
  2075.      * @param   string[optional] $targetScreenName      The screen_name of the target user.
  2076.      */
  2077.     public function friendshipsShow($sourceId = null, $sourceScreenName = null, $targetId = null, $targetScreenName = null)
  2078.     {
  2079.         // validate
  2080.         if($sourceId == '' && $sourceScreenName == '') throw new TwitterException('Specify an sourceId or a sourceScreenName.');
  2081.         if($targetId == '' && $targetScreenName == '') throw new TwitterException('Specify an targetId or a targetScreenName.');
  2082.  
  2083.         // build parameters
  2084.         if($sourceId != null) $parameters['source_id'] = (string) $sourceId;
  2085.         if($sourceScreenName != null) $parameters['source_screen_name'] = (string) $sourceScreenName;
  2086.         if($targetId != null) $parameters['target_id'] = (string) $targetId;
  2087.         if($targetScreenName != null) $parameters['target_screen_name'] = (string) $targetScreenName;
  2088.  
  2089.         // make the call
  2090.         return (array) $this->doCall('friendships/show.json', $parameters);
  2091.     }
  2092.  
  2093.  
  2094.     /**
  2095.      * Returns an array of numeric IDs for every user who has a pending request to follow the authenticating user.
  2096.      *
  2097.      * @return  array
  2098.      * @param   string[optional] $cursor    Breaks the results into pages. This is recommended for users who are following many users. Provide a value of -1  to begin paging. Provide values as returned to in the response body's next_cursor  and previous_cursor attributes to page back and forth in the list.
  2099.      */
  2100.     public function friendshipsIncoming($cursor = null)
  2101.     {
  2102.         // build parameters
  2103.         $parameters = null;
  2104.         if($cursor != null) $parameters['cursor'] = (string) $cursor;
  2105.  
  2106.         // make the call
  2107.         return (array) $this->doCall('friendships/incoming.json', $parameters, true);
  2108.     }
  2109.  
  2110.  
  2111.     /**
  2112.      * Returns an array of numeric IDs for every protected user for whom the authenticating user has a pending follow request.
  2113.      *
  2114.      * @return  array
  2115.      * @param   string[optional] $cursor    Breaks the results into pages. This is recommended for users who are following many users. Provide a value of -1  to begin paging. Provide values as returned to in the response body's next_cursor  and previous_cursor attributes to page back and forth in the list.
  2116.      */
  2117.     public function friendshipsOutgoing($cursor = null)
  2118.     {
  2119.         // build parameters
  2120.         $parameters = null;
  2121.         if($cursor != null) $parameters['cursor'] = (string) $cursor;
  2122.  
  2123.         // make the call
  2124.         return (array) $this->doCall('friendships/outgoing.json', $parameters, true);
  2125.     }
  2126.  
  2127.  
  2128. // Friends and Followers resources
  2129.     /**
  2130.      * Returns an array of numeric IDs for every user the specified user is following.
  2131.      *
  2132.      * @return  array
  2133.      * @param   string[optional] $userId        Specfies the screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  2134.      * @param   string[optional] $screenName    Specfies the ID of the user for whom to return results for. Helpful for disambiguating when a valid user ID is also a valid screen name.
  2135.      * @param   string[optional] $cursor    Breaks the results into pages. This is recommended for users who are following many users. Provide a value of -1  to begin paging. Provide values as returned to in the response body's next_cursor  and previous_cursor attributes to page back and forth in the list.
  2136.      */
  2137.     public function friendsIds($userId = null, $screenName = null, $cursor = null)
  2138.     {
  2139.         // validate
  2140.         if($userId == '' && $screenName == '') throw new TwitterException('Specify an userId or a screenName.');
  2141.  
  2142.         // build parameters
  2143.         $parameters = null;
  2144.         if($userId != null) $parameters['user_id'] = (string) $userId;
  2145.         if($screenName != null) $parameters['screen_name'] = (string) $screenName;
  2146.         if($cursor != null) $parameters['cursor'] = (string) $cursor;
  2147.  
  2148.         // make the call
  2149.         return (array) $this->doCall('friends/ids.json', $parameters, true);
  2150.     }
  2151.  
  2152.  
  2153.     /**
  2154.      * Returns an array of numeric IDs for every user following the specified user.
  2155.      *
  2156.      * @return  array
  2157.      * @param   string[optional] $userId        Specfies the screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  2158.      * @param   string[optional] $screenName    Specfies the ID of the user for whom to return results for. Helpful for disambiguating when a valid user ID is also a valid screen name.
  2159.      * @param   string[optional] $cursor    Breaks the results into pages. This is recommended for users who are following many users. Provide a value of -1  to begin paging. Provide values as returned to in the response body's next_cursor  and previous_cursor attributes to page back and forth in the list.
  2160.      */
  2161.     public function followersIds($userId = null, $screenName = null, $cursor = null)
  2162.     {
  2163.         // validate
  2164.         if($userId == '' && $screenName == '') throw new TwitterException('Specify an userId or a screenName.');
  2165.  
  2166.         // build parameters
  2167.         if($userId != null) $parameters['user_id'] = (string) $userId;
  2168.         if($screenName != null) $parameters['screen_name'] = (string) $screenName;
  2169.         if($cursor != null) $parameters['cursor'] = (string) $cursor;
  2170.  
  2171.         // make the call
  2172.         return (array) $this->doCall('followers/ids.json', $parameters, true);
  2173.     }
  2174.  
  2175.  
  2176. // Account resources
  2177.     /**
  2178.      * Returns an HTTP 200 OK response code and a representation of the requesting user if authentication was successful; returns a 401 status code and an error message if not. Use this method to test if supplied user credentials are valid.
  2179.      *
  2180.      * @return  array
  2181.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2182.      */
  2183.     public function accountVerifyCredentials($includeEntities = false)
  2184.     {
  2185.         // build parameters
  2186.         $parameters = null;
  2187.         if($includeEntities) $parameters['include_entities'] = 'true';
  2188.  
  2189.         // make the call
  2190.         return (array) $this->doCall('account/verify_credentials.json', $parameters, true);
  2191.     }
  2192.  
  2193.  
  2194.     /**
  2195.      * Returns the remaining number of API requests available to the requesting user before the API limit is reached for the current hour. Calls to rate_limit_status do not count against the rate limit.
  2196.      * If authentication credentials are provided, the rate limit status for the authenticating user is returned. Otherwise, the rate limit status for the requester's IP address is returned.
  2197.      *
  2198.      * @return  array
  2199.      */
  2200.     public function accountRateLimitStatus()
  2201.     {
  2202.         // make the call
  2203.         return (array) $this->doCall('account/rate_limit_status.json', null);
  2204.     }
  2205.  
  2206.  
  2207.     /**
  2208.      * Ends the session of the authenticating user, returning a null cookie. Use this method to sign users out of client-facing applications like widgets.
  2209.      *
  2210.      * @return  bool
  2211.      */
  2212.     public function accountEndSession()
  2213.     {
  2214.         try
  2215.         {
  2216.             // make the call
  2217.             $this->doCall('account/end_session.json', null, true, 'POST');
  2218.         }
  2219.  
  2220.         // catch exceptions
  2221.         catch(TwitterException $e)
  2222.         {
  2223.             if($e->getMessage() == 'Logged out.') return true;
  2224.             else throw $e;
  2225.         }
  2226.     }
  2227.  
  2228.  
  2229.     /**
  2230.      * Sets which device Twitter delivers updates to for the authenticating user. Sending none as the device parameter will disable IM or SMS updates.
  2231.      *
  2232.      * @return  array
  2233.      * @param   string $device                      Delivery device type to send updates to.
  2234.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2235.      */
  2236.     public function accountUpdateDeliveryDevices($device, $includeEntities = false)
  2237.     {
  2238.         // build parameters
  2239.         $parameters['device'] = (string) $device;
  2240.         if($includeEntities) $parameters['include_entities'] = 'true';
  2241.  
  2242.         // make the call
  2243.         return (array) $this->doCall('account/update_delivery_device.json', $parameters, true, 'POST');
  2244.     }
  2245.  
  2246.  
  2247.     /**
  2248.      * Sets one or more hex values that control the color scheme of the authenticating user's profile page on twitter.com.
  2249.      * Each parameter's value must be a valid hexidecimal value, and may be either three or six characters (ex: #fff or #ffffff).
  2250.      *
  2251.      * @return  array
  2252.      * @param   string[optional] $profileBackgroundColor        Profile background color.
  2253.      * @param   string[optional] $profileTextColor              Profile text color.
  2254.      * @param   string[optional] $profileLinkColor              Profile link color.
  2255.      * @param   string[optional] $profileSidebarFillColor       Profile sidebar's background color.
  2256.      * @param   string[optional] $profileSidebarBorderColor     Profile sidebar's border color.
  2257.      * @param   bool[optional] $includeEntities                 When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2258.      */
  2259.     public function accountUpdateProfileColors($profileBackgroundColor = null, $profileTextColor = null, $profileLinkColor = null, $profileSidebarFillColor = null, $profileSidebarBorderColor = null, $includeEntities = false)
  2260.     {
  2261.         // validate
  2262.         if($profileBackgroundColor == '' && $profileTextColor == '' && $profileLinkColor == '' && $profileSidebarFillColor == '' && $profileSidebarBorderColor == '') throw new TwitterException('Specify a profileBackgroundColor, profileTextColor, profileLinkColor, profileSidebarFillColor or a profileSidebarBorderColor.');
  2263.  
  2264.         // build parameters
  2265.         if($profileBackgroundColor != null) $parameters['profile_background_color'] = (string) $profileBackgroundColor;
  2266.         if($profileTextColor != null) $parameters['profile_text_color'] = (string) $profileTextColor;
  2267.         if($profileLinkColor != null) $parameters['profile_link_color'] = (string) $profileLinkColor;
  2268.         if($profileSidebarFillColor != null) $parameters['profile_sidebar_fill_color'] = (string) $profileSidebarFillColor;
  2269.         if($profileSidebarBorderColor != null) $parameters['profile_sidebar_border_color'] = (string) $profileSidebarBorderColor;
  2270.         if($includeEntities) $parameters['include_entities'] = 'true';
  2271.  
  2272.         // make the call
  2273.         return (array) $this->doCall('account/update_profile_colors.json', $parameters, true, 'POST');
  2274.     }
  2275.  
  2276.  
  2277.     /**
  2278.      * Updates the authenticating user's profile image.
  2279.      *
  2280.      * @return  array
  2281.      * @param   string $image                       The path to the avatar image for the profile. Must be a valid GIF, JPG, or PNG image of less than 700 kilobytes in size. Images with width larger than 500 pixels will be scaled down.
  2282.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2283.      */
  2284.     public function accountUpdateProfileImage($image, $includeEntities = false)
  2285.     {
  2286.         // validate
  2287.         if(!file_exists($image)) throw new TwitterException('Image (' . $image . ') doesn\'t exists.');
  2288.  
  2289.         // build parameters
  2290.         $parameters = null;
  2291.         if($includeEntities) $parameters['include_entities'] = 'true';
  2292.  
  2293.         // make the call
  2294.         return (array) $this->doCall('account/update_profile_image.json', $parameters, true, 'POST', $image);
  2295.     }
  2296.  
  2297.  
  2298.     /**
  2299.      * Updates the authenticating user's profile background image.
  2300.      *
  2301.      * @return  array
  2302.      * @param   string $image                       The path to the background image for the profile. Must be a valid GIF, JPG, or PNG image of less than 800 kilobytes in size. Images with width larger than 2048 pixels will be forceably scaled down.
  2303.      * @param   bool[optional] $tile                Whether or not to tile the background image. If set to true the background image will be displayed tiled. The image will not be tiled otherwise.
  2304.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2305.      */
  2306.     public function accountUpdateProfileBackgroundImage($image, $tile = false, $includeEntities = false)
  2307.     {
  2308.         // validate
  2309.         if(!file_exists($image)) throw new TwitterException('Image (' . $image . ') doesn\'t exists.');
  2310.  
  2311.         // build parameters
  2312.         $parameters = null;
  2313.         if($tile) $parameters['tile'] = 'true';
  2314.         if($includeEntities) $parameters['include_entities'] = 'true';
  2315.  
  2316.         // make the call
  2317.         return (array) $this->doCall('account/update_profile_background_image.json', $parameters, true, 'POST', $image);
  2318.     }
  2319.  
  2320.  
  2321.     /**
  2322.      * Sets values that users are able to set under the "Account" tab of their settings page. Only the parameters specified will be updated.
  2323.      *
  2324.      * @return  array
  2325.      * @param   string[optional] $name          Full name associated with the profile. Maximum of 20 characters.
  2326.      * @param   string[optional] $url           URL associated with the profile. Will be prepended with "http://" if not present. Maximum of 100 characters.
  2327.      * @param   string[optional] $location      The city or country describing where the user of the account is located. The contents are not normalized or geocoded in any way. Maximum of 30 characters.
  2328.      * @param   string[optional] $description   A description of the user owning the account. Maximum of 160 characters.
  2329.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2330.      */
  2331.     public function accountUpdateProfile($name = null, $url = null, $location = null, $description = null, $includeEntities = false)
  2332.     {
  2333.         // build parameters
  2334.         $parameters = null;
  2335.         if($name != null) $parameters['name'] = (string) $name;
  2336.         if($url != null) $parameters['url'] = (string) $url;
  2337.         if($location != null) $parameters['location'] = (string) $location;
  2338.         if($description != null) $parameters['description'] = (string) $description;
  2339.         if($includeEntities) $parameters['include_entities'] = 'true';
  2340.  
  2341.         // make the call
  2342.         return (array) $this->doCall('account/update_profile.json', $parameters, true, 'POST');
  2343.     }
  2344.  
  2345.  
  2346. // Favorites resources
  2347.     /**
  2348.      * Returns the 20 most recent favorite statuses for the authenticating user or user specified by the ID parameter in the requested format.
  2349.      *
  2350.      * @return  array
  2351.      * @param   string[optional] $id                Specifies the ID or screen name of the user for whom to return results for.
  2352.      * @param   int[optional] $page                 Specifies the page of results to retrieve.
  2353.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2354.      */
  2355.     public function favorites($id = null, $page = null, $includeEntities = false)
  2356.     {
  2357.         // build parameters
  2358.         $parameters = null;
  2359.         if($id != null) $parameters['id'] = (string) $id;
  2360.         if($page != null) $parameters['page'] = (int) $page;
  2361.         if($includeEntities) $parameters['include_entities'] = 'true';
  2362.  
  2363.         // make the call
  2364.         return (array) $this->doCall('favorites.json', $parameters, true);
  2365.     }
  2366.  
  2367.  
  2368.     /**
  2369.      * Favorites the status specified in the ID parameter as the authenticating user. Returns the favorite status when successful.
  2370.      *
  2371.      * @return  array
  2372.      * @param   string $id                          The numerical ID of the desired status.
  2373.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2374.      */
  2375.     public function favoritesCreate($id, $includeEntities = false)
  2376.     {
  2377.         // build parameters
  2378.         $parameters = null;
  2379.         if($includeEntities) $parameters['include_entities'] = 'true';
  2380.  
  2381.         // make the call
  2382.         return (array) $this->doCall('favorites/create/' . $id . '.json', $parameters, true, 'POST');
  2383.     }
  2384.  
  2385.  
  2386.     /**
  2387.      * Un-favorites the status specified in the ID parameter as the authenticating user. Returns the un-favorited status in the requested format when successful.
  2388.      *
  2389.      * @return  array
  2390.      * @param   string $id                          The numerical ID of the desired status.
  2391.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2392.      */
  2393.     public function favoritesDestroy($id, $includeEntities = false)
  2394.     {
  2395.         // build parameters
  2396.         $parameters = null;
  2397.         if($includeEntities) $parameters['include_entities'] = 'true';
  2398.  
  2399.         // make the call
  2400.         return (array) $this->doCall('favorites/destroy/' . $id . '.json', $parameters, true, 'POST');
  2401.     }
  2402.  
  2403.  
  2404. // Notification resources
  2405.     /**
  2406.      * Enables device notifications for updates from the specified user. Returns the specified user when successful.
  2407.      *
  2408.      * @return  array
  2409.      * @param   string[optional] $userId            Specfies the screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  2410.      * @param   string[optional] $screenName        Specfies the ID of the user for whom to return results for. Helpful for disambiguating when a valid user ID is also a valid screen name.
  2411.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2412.      */
  2413.     public function notificationsFollow($userId = null, $screenName = null, $includeEntities = false)
  2414.     {
  2415.         // validate
  2416.         if($userId == '' && $screenName == '') throw new TwitterException('Specify an userId or a screenName.');
  2417.  
  2418.         // build parameters
  2419.         if($userId != null) $parameters['user_id'] = (string) $userId;
  2420.         if($screenName != null) $parameters['screen_name'] = (string) $screenName;
  2421.         if($includeEntities) $parameters['include_entities'] = 'true';
  2422.  
  2423.         // make the call
  2424.         return (array) $this->doCall('notifications/follow.json', $parameters, true, 'POST');
  2425.     }
  2426.  
  2427.  
  2428.     /**
  2429.      * Disables notifications for updates from the specified user to the authenticating user. Returns the specified user when successful.
  2430.      *
  2431.      * @return  array
  2432.      * @param   string[optional] $userId            Specfies the screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  2433.      * @param   string[optional] $screenName        Specfies the ID of the user for whom to return results for. Helpful for disambiguating when a valid user ID is also a valid screen name.
  2434.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2435.      */
  2436.     public function notificationsLeave($userId = null, $screenName = null, $includeEntities = false)
  2437.     {
  2438.         // validate
  2439.         if($userId == '' && $screenName == '') throw new TwitterException('Specify an userId or a screenName.');
  2440.  
  2441.         // build parameters
  2442.         if($userId != null) $parameters['user_id'] = (string) $userId;
  2443.         if($screenName != null) $parameters['screen_name'] = (string) $screenName;
  2444.         if($includeEntities) $parameters['include_entities'] = 'true';
  2445.  
  2446.         // make the call
  2447.         return (array) $this->doCall('notifications/leave.json', $parameters, true, 'POST');
  2448.     }
  2449.  
  2450.  
  2451. // Block resources
  2452.     /**
  2453.      * Blocks the user specified in the ID parameter as the authenticating user. Destroys a friendship to the blocked user if it exists. Returns the blocked user in the requested format when successful.
  2454.      *
  2455.      * @return  array
  2456.      * @param   string[optional] $userId            Specfies the screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  2457.      * @param   string[optional] $screenName        Specfies the ID of the user for whom to return results for. Helpful for disambiguating when a valid user ID is also a valid screen name.
  2458.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2459.      */
  2460.     public function blocksCreate($userId = null, $screenName = null, $includeEntities = false)
  2461.     {
  2462.         // validate
  2463.         if($userId == '' && $screenName == '') throw new TwitterException('Specify an userId or a screenName.');
  2464.  
  2465.         // build parameters
  2466.         if($userId != null) $parameters['user_id'] = (string) $userId;
  2467.         if($screenName != null) $parameters['screen_name'] = (string) $screenName;
  2468.         if($includeEntities) $parameters['include_entities'] = 'true';
  2469.  
  2470.         // make the call
  2471.         return (array) $this->doCall('blocks/create.json', $parameters, true, 'POST');
  2472.     }
  2473.  
  2474.  
  2475.     /**
  2476.      * Un-blocks the user specified in the ID parameter for the authenticating user. Returns the un-blocked user in the requested format when successful.
  2477.      *
  2478.      * @return  array
  2479.      * @param   string[optional] $userId            Specfies the screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  2480.      * @param   string[optional] $screenName        Specfies the ID of the user for whom to return results for. Helpful for disambiguating when a valid user ID is also a valid screen name.
  2481.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2482.      */
  2483.     public function blocksDestroy($userId = null, $screenName = null, $includeEntities = false)
  2484.     {
  2485.         // validate
  2486.         if($userId == '' && $screenName == '') throw new TwitterException('Specify an userId or a screenName.');
  2487.  
  2488.         // build parameters
  2489.         if($userId != null) $parameters['user_id'] = (string) $userId;
  2490.         if($screenName != null) $parameters['screen_name'] = (string) $screenName;
  2491.         if($includeEntities) $parameters['include_entities'] = 'true';
  2492.  
  2493.         // make the call
  2494.         return (array) $this->doCall('blocks/destroy.json', $parameters, true, 'POST');
  2495.     }
  2496.  
  2497.  
  2498.     /**
  2499.      * Un-blocks the user specified in the ID parameter for the authenticating user. Returns the un-blocked user in the requested format when successful.
  2500.      *
  2501.      * @return  mixed
  2502.      * @param   string[optional] $userId            Specfies the screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  2503.      * @param   string[optional] $screenName        Specfies the ID of the user for whom to return results for. Helpful for disambiguating when a valid user ID is also a valid screen name.
  2504.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2505.      */
  2506.     public function blocksExists($userId = null, $screenName = null, $includeEntities = false)
  2507.     {
  2508.         // validate
  2509.         if($userId == '' && $screenName == '') throw new TwitterException('Specify an userId or a screenName.');
  2510.  
  2511.         // build parameters
  2512.         if($userId != null) $parameters['user_id'] = (string) $userId;
  2513.         if($screenName != null) $parameters['screen_name'] = (string) $screenName;
  2514.         if($includeEntities) $parameters['include_entities'] = 'true';
  2515.  
  2516.         try
  2517.         {
  2518.             // make the call
  2519.             return (array) $this->doCall('blocks/exists.json', $parameters, true);
  2520.         }
  2521.         // catch exceptions
  2522.         catch(TwitterException $e)
  2523.         {
  2524.             if($e->getMessage() == 'You are not blocking this user.') return false;
  2525.             else throw $e;
  2526.         }
  2527.     }
  2528.  
  2529.  
  2530.     /**
  2531.      * Returns an array of user objects that the authenticating user is blocking.
  2532.      *
  2533.      * @return  array
  2534.      * @param   int[optional] $page                 Specifies the page of results to retrieve. Note: there are pagination limits. See the FAQ for details.
  2535.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2536.      */
  2537.     public function blocksBlocking($page = null, $includeEntities = false)
  2538.     {
  2539.         // build parameters
  2540.         $parameters = null;
  2541.         if($page != null) $parameters['page'] = (int) $page;
  2542.         if($includeEntities) $parameters['include_entities'] = 'true';
  2543.  
  2544.         // make the call
  2545.         return (array) $this->doCall('blocks/blocking.json', $parameters, true);
  2546.     }
  2547.  
  2548.  
  2549.     /**
  2550.      * Returns an array of numeric user ids the authenticating user is blocking.
  2551.      *
  2552.      * @return  array
  2553.      */
  2554.     public function blocksBlockingIds()
  2555.     {
  2556.         // make the call
  2557.         return (array) $this->doCall('blocks/blocking/ids.json', null, true);
  2558.     }
  2559.  
  2560.  
  2561. // Spam Reporting resources
  2562.     /**
  2563.      * The user specified in the id is blocked by the authenticated user and reported as a spammer.
  2564.      *
  2565.      * @return  array
  2566.      * @param   string[optional] $userId        Specfies the screen name of the user for whom to return results for. Helpful for disambiguating when a valid screen name is also a user ID.
  2567.      * @param   string[optional] $screenName    Specfies the ID of the user for whom to return results for. Helpful for disambiguating when a valid user ID is also a valid screen name.
  2568.      * @param   bool[optional] $includeEntities     When set to true each tweet will include a node called "entities,". This node offers a variety of metadata about the tweet in a discreet structure, including: user_mentions, urls, and hashtags.
  2569.      */
  2570.     public function reportSpam($userId = null, $screenName = null, $includeEntities = false)
  2571.     {
  2572.         // validate
  2573.         if($userId == '' && $screenName == '') throw new TwitterException('Specify an userId or a screenName.');
  2574.  
  2575.         // build parameters
  2576.         if($userId != null) $parameters['user_id'] = (string) $userId;
  2577.         if($screenName != null) $parameters['screen_name'] = (string) $screenName;
  2578.         if($includeEntities) $parameters['include_entities'] = 'true';
  2579.  
  2580.         // make the call
  2581.         return (array) $this->doCall('report_spam.json', $parameters, true, 'POST');
  2582.     }
  2583.  
  2584.  
  2585. // Search resources
  2586.     /**
  2587.      * Returns tweets that match a specified query.
  2588.      *
  2589.      * @return  array
  2590.      * @param   string $q                       Search query. Should be URL encoded. Queries will be limited by complexity.
  2591.      * @param   string[optional] $lang          Restricts tweets to the given language, given by an ISO 639-1 code.
  2592.      * @param   string[optional] $locale        Specify the language of the query you are sending (only ja is currently effective). This is intended for language-specific clients and the default should work in the majority of cases.
  2593.      * @param   int[optional] $rpp              The number of tweets to return per page, up to a max of 100.
  2594.      * @param   int[optional] $page             The page number (starting at 1) to return, up to a max of roughly 1500 results (based on rpp * page).
  2595.      * @param   string[optional] $sinceId       Returns results with an ID greater than (that is, more recent than) the specified ID. There are limits to the number of Tweets which can be accessed through the API. If the limit of Tweets has occured since the since_id, the since_id will be forced to the oldest ID available.
  2596.      * @param   string[optional] $until         Returns tweets generated before the given date. Date should be formatted as YYYY-MM-DD.
  2597.      * @param   string[optional] $geocode       Returns tweets by users located within a given radius of the given latitude/longitude. The location is preferentially taking from the Geotagging API, but will fall back to their Twitter profile. The parameter value is specified by "latitude,longitude,radius", where radius units must be specified as either "mi" (miles) or "km" (kilometers). Note that you cannot use the near operator via the API to geocode arbitrary locations; however you can use this geocode parameter to search near geocodes directly.
  2598.      * @param   bool[optional] $showUser        When true, prepends ":" to the beginning of the tweet. This is useful for readers that do not display Atom's author field. The default is false.
  2599.      * @param   string[optional] $resultType    Specifies what type of search results you would prefer to receive. The current default is "mixed." Valid values include: mixed, recent, popular.
  2600.      */
  2601.     public function search($q, $lang = null, $locale = null, $rpp = null, $page = null, $sinceId = null, $until = null, $geocode = null, $showUser = false, $resultType = null)
  2602.     {
  2603.         $parameters['q'] = (string) $q;
  2604.         if($lang !== null) $parameters['lang'] = (string) $lang;
  2605.         if($locale !== null) $parameters['locale'] = (string) $locale;
  2606.         if($rpp !== null) $parameters['rpp'] = (int) $rpp;
  2607.         if($page !== null) $parameters['page'] = (int) $page;
  2608.         if($sinceId !== null) $parameters['since_id'] = (string) $sinceId;
  2609.         if($until !== null) $parameters['until'] = (string) $until;
  2610.         if($geocode !== null) $parameters['geocode'] = (string) $geocode;
  2611.         if($showUser === true) $parameters['show_user'] = 'true';
  2612.         if($resultType !== null) $parameters['result_type'] = (string) $resultType;
  2613.  
  2614.         return (array) $this->doSearchCall('search.json', $parameters);
  2615.     }
  2616.  
  2617.  
  2618. // Saved Searches resources
  2619.     /**
  2620.      * Returns the authenticated user's saved search queries.
  2621.      *
  2622.      * @return  array
  2623.      */
  2624.     public function savedSearches()
  2625.     {
  2626.         // make the call
  2627.         return (array) $this->doCall('saved_searches.json', null, true);
  2628.     }
  2629.  
  2630.  
  2631.     /**
  2632.      * Retrieve the data for a saved search owned by the authenticating user specified by the given id.
  2633.      *
  2634.      * @return  array
  2635.      * @param   string $id  The ID of the desired saved search.
  2636.      */
  2637.     public function savedSearchesShow($id)
  2638.     {
  2639.         // make the call
  2640.         return (array) $this->doCall('saved_searches/show/' . (string) $id . '.json', null, true);
  2641.     }
  2642.  
  2643.  
  2644.     /**
  2645.      * Creates a saved search for the authenticated user.
  2646.      *
  2647.      * @return  array
  2648.      * @param   string $query   The query of the search the user would like to save.
  2649.      */
  2650.     public function savedSearchesCreate($query)
  2651.     {
  2652.         // build parameters
  2653.         $parameters['query'] = (string) $query;
  2654.  
  2655.         // make the call
  2656.         return (array) $this->doCall('saved_searches/create.json', $parameters, true, 'POST');
  2657.     }
  2658.  
  2659.  
  2660.     /**
  2661.      * Destroys a saved search for the authenticated user. The search specified by id must be owned by the authenticating user.
  2662.      *
  2663.      * @return  array
  2664.      * @param   string $id  The ID of the desired saved search.
  2665.      */
  2666.     public function savedSearchesDestroy($id)
  2667.     {
  2668.         return (array) $this->doCall('saved_searches/destroy/' . (string) $id . '.json', null, true, 'POST');
  2669.     }
  2670.  
  2671.  
  2672. // OAuth resources
  2673.     /**
  2674.      * Allows a Consumer application to obtain an OAuth Request Token to request user authorization.
  2675.      * This method fulfills Secion 6.1 of the OAuth 1.0 authentication flow.
  2676.      *
  2677.      * @return  array                           An array containg the token and the secret
  2678.      * @param   string[optional] $callbackURL   The callback URL.
  2679.      */
  2680.     public function oAuthRequestToken($callbackURL = null)
  2681.     {
  2682.         // init var
  2683.         $parameters = null;
  2684.  
  2685.         // set callback
  2686.         if($callbackURL != null) $parameters['oauth_callback'] = (string) $callbackURL;
  2687.  
  2688.         // make the call
  2689.         $response = $this->doOAuthCall('request_token', $parameters);
  2690.  
  2691.         // validate
  2692.         if(!isset($response['oauth_token'], $response['oauth_token_secret'])) throw new TwitterException(implode(', ', array_keys($response)));
  2693.  
  2694.         // set some properties
  2695.         if(isset($response['oauth_token'])) $this->setOAuthToken($response['oauth_token']);
  2696.         if(isset($response['oauth_token_secret'])) $this->setOAuthTokenSecret($response['oauth_token_secret']);
  2697.  
  2698.         // return
  2699.         return $response;
  2700.     }
  2701.  
  2702.  
  2703.     /**
  2704.      * Allows a Consumer application to exchange the OAuth Request Token for an OAuth Access Token.
  2705.      * This method fulfills Secion 6.3 of the OAuth 1.0 authentication flow.
  2706.      *
  2707.      * @return  array
  2708.      * @param   string $token       The token to use.
  2709.      * @param   string $verifier    The verifier.
  2710.      */
  2711.     public function oAuthAccessToken($token, $verifier)
  2712.     {
  2713.         // init var
  2714.         $parameters = array();
  2715.         $parameters['oauth_token'] = (string) $token;
  2716.         $parameters['oauth_verifier'] = (string) $verifier;
  2717.  
  2718.         // make the call
  2719.         $response = $this->doOAuthCall('access_token', $parameters);
  2720.  
  2721.         // set some properties
  2722.         if(isset($response['oauth_token'])) $this->setOAuthToken($response['oauth_token']);
  2723.         if(isset($response['oauth_token_secret'])) $this->setOAuthTokenSecret($response['oauth_token_secret']);
  2724.  
  2725.         // return
  2726.         return $response;
  2727.     }
  2728.  
  2729.  
  2730.     /**
  2731.      * Will redirect to the page to authorize the applicatione
  2732.      *
  2733.      * @return  void
  2734.      * @param   string  $token      The token.
  2735.      */
  2736.     public function oAuthAuthorize($token)
  2737.     {
  2738.         header('Location: ' . self::SECURE_API_URL . '/oauth/authorize?oauth_token=' . $token);
  2739.     }
  2740.  
  2741.  
  2742.     /**
  2743.      * Allows a Consumer application to use an OAuth request_token to request user authorization. This method is a replacement fulfills Secion 6.2 of the OAuth 1.0 authentication flow for applications using the Sign in with Twitter authentication flow. The method will use the currently logged in user as the account to for access authorization unless the force_login parameter is set to true
  2744.      * REMARK: This method seems not to work    @later
  2745.      *
  2746.      * @return  void
  2747.      * @param   bool[optional] $force   Force the authentication.
  2748.      */
  2749.     public function oAuthAuthenticate($force = false)
  2750.     {
  2751.         throw new TwitterException('Not implemented');
  2752.  
  2753.         // build parameters
  2754.         $parameters = null;
  2755.         if((bool) $force) $parameters['force_login'] = 'true';
  2756.  
  2757.         // make the call
  2758.         return $this->doCall('/oauth/authenticate.oauth', $parameters);
  2759.     }
  2760.  
  2761.  
  2762. // Local Trends resources
  2763.     /**
  2764.      * Returns the locations that Twitter has trending topic information for.
  2765.      * The response is an array of "locations" that encode the location's WOEID (a Yahoo! Where On Earth ID) and some other human-readable information such as a canonical name and country the location belongs in.
  2766.      * The WOEID that is returned in the location object is to be used when querying for a specific trend.
  2767.      *
  2768.      * @return  array
  2769.      * @param   float[optional] $lat    If passed in conjunction with long, then the available trend locations will be sorted by distance to the lat  and long passed in. The sort is nearest to furthest.
  2770.      * @param   float[optional] $long   If passed in conjunction with lat, then the available trend locations will be sorted by distance to the lat  and long passed in. The sort is nearest to furthest.
  2771.      */
  2772.     public function trendsAvailable($lat = null, $long = null)
  2773.     {
  2774.         // build parameters
  2775.         $parameters = null;
  2776.         if($lat != null) $parameters['lat_for_trends'] = (float) $lat;
  2777.         if($long != null) $parameters['long_for_trends'] = (float) $long;
  2778.  
  2779.         // make the call
  2780.         return (array) $this->doCall('trends/available.json', $parameters);
  2781.     }
  2782.  
  2783.  
  2784.     /**
  2785.      * Returns the top 10 trending topics for a specific location Twitter has trending topic information for.
  2786.      * The response is an array of "trend" objects that encode the name of the trending topic, the query parameter that can be used to search for the topic on Search, and the direct URL that can be issued against Search.
  2787.      * This information is cached for five minutes, and therefore users are discouraged from querying these endpoints faster than once every five minutes. Global trends information is also available from this API by using a WOEID of 1.
  2788.      *
  2789.      * @return  array
  2790.      * @param   string $woeid   The WOEID of the location to be querying for.
  2791.      */
  2792.     public function trendsLocation($woeid)
  2793.     {
  2794.         // make the call
  2795.         return (array) $this->doCall('trends/' . (string) $woeid . '.json');
  2796.     }
  2797.  
  2798.  
  2799. // Geo resources
  2800.     /**
  2801.      * Search for places that can be attached to a statuses/update. Given a latitude and a longitude pair, an IP address, or a name, this request will return a list of all the valid places that can be used as the place_id when updating a status.
  2802.      * Conceptually, a query can be made from the user's location, retrieve a list of places, have the user validate the location he or she is at, and then send the ID of this location with a call to statuses/update.
  2803.      * This is the recommended method to use find places that can be attached to statuses/update. Unlike geo/reverse_geocode which provides raw data access, this endpoint can potentially re-order places with regards to the user who is authenticated. This approach is also preferred for interactive place matching with the user.
  2804.      *
  2805.      * @return  array
  2806.      * @param   float[optional] $lat                The latitude to search around. This parameter will be ignored unless it is inside the range -90.0 to +90.0 (North is positive) inclusive. It will also be ignored if there isn't a corresponding long parameter.
  2807.      * @param   float[optional] $long               The longitude to search around. The valid ranges for longitude is -180.0 to +180.0 (East is positive) inclusive. This parameter will be ignored if outside that range, if it is not a number, if geo_enabled is disabled, or if there not a corresponding lat parameter.
  2808.      * @param   string[optional] $query             Free-form text to match against while executing a geo-based query, best suited for finding nearby locations by name.
  2809.      * @param   string[optional] $ip                An IP address. Used when attempting to fix geolocation based off of the user's IP address.
  2810.      * @param   string[optional] $accuracy          A hint on the "region" in which to search. If a number, then this is a radius in meters, but it can also take a string that is suffixed with ft to specify feet. If this is not passed in, then it is assumed to be 0m. If coming from a device, in practice, this value is whatever accuracy the device has measuring its location (whether it be coming from a GPS, WiFi triangulation, etc.).
  2811.      * @param   string[optional] $granularity       The minimal granularity of data to return. If this is not passed in, then neighborhood is assumed. city can also be passed.
  2812.      * @param   int[optional] $maxResults           A hint as to the number of results to return. This does not guarantee that the number of results returned will equal max_results, but instead informs how many "nearby" results to return. Ideally, only pass in the number of places you intend to display to the user here.
  2813.      * @param   string[optional] $containedWithin   This is the place_id which you would like to restrict the search results to. Setting this value means only places within the given place_id will be found.
  2814.      * @param   array[optional] $attributes         This parameter searches for places which have this given. This should be an key-value-pair-array.
  2815.      */
  2816.     public function geoSearch($lat = null, $long = null, $query = null, $ip = null, $accuracy = null, $granularity = null, $maxResults = null, $containedWithin = null, array $attributes = null)
  2817.     {
  2818.         // build parameters
  2819.         if($lat != null) $parameters['lat'] = (float) $lat;
  2820.         if($long != null) $parameters['long'] = (float) $long;
  2821.         if($query != null) $parameters['query'] = (string) $query;
  2822.         if($ip != null) $parameters['ip'] = (string) $ip;
  2823.         if($accuracy != null) $parameters['accuracy'] = (string) $accuracy;
  2824.         if($granularity != null) $parameters['granularity'] = (string) $granularity;
  2825.         if($maxResults != null) $parameters['max_results'] = (int) $maxResults;
  2826.         if($containedWithin != null) $parameters['contained_within'] = (string) $containedWithin;
  2827.         if($attributes != null)
  2828.         {
  2829.             // loop
  2830.             foreach($attributes as $key => $value) $parameters['attribute:' . $key] = (string) $value;
  2831.         }
  2832.  
  2833.         // make the call
  2834.         return (array) $this->doCall('geo/search.json', $parameters);
  2835.     }
  2836.  
  2837.  
  2838.     /**
  2839.      * Locates places near the given coordinates which are similar in name.
  2840.      * Conceptually you would use this method to get a list of known places to choose from first. Then, if the desired place doesn't exist, make a request to post/geo/place to create a new one.
  2841.      * The token contained in the response is the token needed to be able to create a new place.
  2842.      *
  2843.      * @return  array
  2844.      * @param   float $lat                          The location's latitude that this tweet refers to.
  2845.      * @param   float $long                         The location's longitude that this tweet refers to.
  2846.      * @param   string $name                        The name a place is known as.
  2847.      * @param   string[optional] $containedWithin   This is the place_id which you would like to restrict the search results to. Setting this value means only places within the given place_id will be found.
  2848.      * @param   array[optional] $attributes         This parameter searches for places which have this given. This should be an key-value-pair-array.
  2849.      */
  2850.     public function geoSimilarPlaces($lat, $long, $name, $containedWithin = null, array $attributes = null)
  2851.     {
  2852.         // build parameters
  2853.         $parameters['lat'] = (float) $lat;
  2854.         $parameters['long'] = (float) $long;
  2855.         $parameters['name'] = (string) $name;
  2856.         if($containedWithin != null) $parameters['contained_within'] = (string) $containedWithin;
  2857.         if($attributes != null)
  2858.         {
  2859.             // loop
  2860.             foreach($attributes as $key => $value) $parameters['attribute:' . $key] = (string) $value;
  2861.         }
  2862.  
  2863.         // make the call
  2864.         return (array) $this->doCall('geo/similar_places.json', $parameters);
  2865.     }
  2866.  
  2867.  
  2868.     /**
  2869.      * Search for places (cities and neighborhoods) that can be attached to a statuses/update. Given a latitude and a longitude, return a list of all the valid places that can be used as a place_id when updating a status.
  2870.      * Conceptually, a query can be made from the user's location, retrieve a list of places, have the user validate the location he or she is at, and then send the ID of this location up with a call to statuses/update.
  2871.      * There are multiple granularities of places that can be returned -- "neighborhoods", "cities", etc. At this time, only United States data is available through this method.
  2872.      * This API call is meant to be an informative call and will deliver generalized results about geography.
  2873.      *
  2874.      * @return  array
  2875.      * @param   float $lat                      The location's latitude that this tweet refers to.
  2876.      * @param   float $long                     The location's longitude that this tweet refers to.
  2877.      * @param   string[optional] $accuracy      A hint on the "region" in which to search. If a number, then this is a radius in meters, but it can also take a string that is suffixed with ft to specify feet. If this is not passed in, then it is assumed to be 0m. If coming from a device, in practice, this value is whatever accuracy the device has measuring its location (whether it be coming from a GPS, WiFi triangulation, etc.).
  2878.      * @param   string[optional] $granularity   The minimal granularity of data to return. If this is not passed in, then neighborhood is assumed. city can also be passed.
  2879.      * @param   int[optional] $maxResults       A hint as to the number of results to return. This does not guarantee that the number of results returned will equal max_results, but instead informs how many "nearby" results to return. Ideally, only pass in the number of places you intend to display to the user here.
  2880.      */
  2881.     public function geoReverseGeoCode($lat, $long, $accuracy = null, $granularity = null, $maxResults = null)
  2882.     {
  2883.         // build parameters
  2884.         $parameters['lat'] = (float) $lat;
  2885.         $parameters['long'] = (float) $long;
  2886.         if($accuracy != null) $parameters['accuracy'] = (string) $accuracy;
  2887.         if($granularity != null) $parameters['granularity'] = (string) $granularity;
  2888.         if($maxResults != null) $parameters['max_results'] = (int) $maxResults;
  2889.  
  2890.         // make the call
  2891.         return (array) $this->doCall('geo/reverse_geocode.json', $parameters);
  2892.     }
  2893.  
  2894.  
  2895.     /**
  2896.      * Find out more details of a place that was returned from the geo/reverse_geocode method.
  2897.      *
  2898.      * @return  array
  2899.      * @param   string $id                  The id of the place.
  2900.      * @param   string[optional] $placeId   A place in the world. These IDs can be retrieved from geo/reverse_geocode.
  2901.      */
  2902.     public function geoId($id, $placeId = null)
  2903.     {
  2904.         // build parameters
  2905.         $parameters = null;
  2906.         if($placeId != null) $parameters['place_id'] = (string) $placeId;
  2907.  
  2908.         // make the call
  2909.         return (array) $this->doCall('geo/id/' . (string) $id . '.json', $parameters);
  2910.     }
  2911.  
  2912.  
  2913.     /**
  2914.      * Creates a new place at the given latitude and longitude.
  2915.      *
  2916.      * @return  array
  2917.      * @param   string $name                    The name a place is known as.
  2918.      * @param   string $containedWithin         This is the place_id which you would like to restrict the search results to. Setting this value means only places within the given place_id will be found.
  2919.      * @param   string $token                   The token found in the response from geo/similar_places.
  2920.      * @param   float $lat                      The latitude the place is located at. This parameter will be ignored unless it is inside the range -90.0 to +90.0 (North is positive) inclusive. It will also be ignored if there isn't a corresponding long parameter.
  2921.      * @param   float $long                     The longitude the place is located at. The valid ranges for longitude is -180.0 to +180.0 (East is positive) inclusive. This parameter will be ignored if outside that range, if it is not a number, if geo_enabled is disabled, or if there not a corresponding lat parameter.
  2922.      * @param   array[optional] $attributes     This parameter searches for places which have this given. This should be an key-value-pair-array.
  2923.      */
  2924.     public function geoPlaceCreate($name, $containedWithin, $token, $lat, $long, array $attributes = null)
  2925.     {
  2926.         // build parameters
  2927.         $parameters['name'] = (string) $name;
  2928.         $parameters['contained_within'] = (string) $containedWithin;
  2929.         $parameters['token'] = (string) $token;
  2930.         $parameters['lat'] = (float) $lat;
  2931.         $parameters['long'] = (float) $long;
  2932.         if($attributes != null)
  2933.         {
  2934.             // loop
  2935.             foreach($attributes as $key => $value) $parameters['attribute:' . $key] = (string) $value;
  2936.         }
  2937.  
  2938.         // make the call
  2939.         return (array) $this->doCall('geo/place.json', $parameters, true, 'POST');
  2940.     }
  2941.  
  2942.  
  2943. // legal resources
  2944.     /**
  2945.      * Returns Twitter's' Terms of Service in the requested format. These are not the same as the Developer Terms of Service.
  2946.      *
  2947.      * @return  string
  2948.      */
  2949.     public function legalToS()
  2950.     {
  2951.         // make the call
  2952.         $response = $this->doCall('legal/tos.json');
  2953.  
  2954.         // validate and return
  2955.         if(isset($response['tos'])) return $response['tos'];
  2956.  
  2957.         // fallback
  2958.         return false;
  2959.     }
  2960.  
  2961.  
  2962.     /**
  2963.      * Returns Twitter's Privacy Policy
  2964.      *
  2965.      * @return  string
  2966.      */
  2967.     public function legalPrivacy()
  2968.     {
  2969.         // make the call
  2970.         $response = $this->doCall('legal/privacy.json');
  2971.  
  2972.         // validate and return
  2973.         if(isset($response['privacy'])) return $response['privacy'];
  2974.  
  2975.         // fallback
  2976.         return false;
  2977.     }
  2978.  
  2979.  
  2980. // Help resources
  2981.     /**
  2982.      * Test
  2983.      *
  2984.      * @return  bool
  2985.      */
  2986.     public function helpTest()
  2987.     {
  2988.         // make the call
  2989.         return ($this->doCall('help/test.json', null, null, 'GET', null, false) == '"ok"');
  2990.     }
  2991. }
  2992.  
  2993.  
  2994. /**
  2995.  * Twitter Exception class
  2996.  *
  2997.  * @author  Tijs Verkoyen <php-twitter@verkoyen.eu>
  2998.  */
  2999. class TwitterException extends Exception
  3000. {
  3001. }
  3002.  
  3003. ?>
Add Comment
Please, Sign In to add comment