File indexing completed on 2024-12-22 05:37:06
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Service 0017 * @subpackage Twitter 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 /** 0024 * @see Zend_Http_Client 0025 */ 0026 // require_once 'Zend/Http/Client.php'; 0027 0028 /** 0029 * @see Zend_Http_CookieJar 0030 */ 0031 // require_once 'Zend/Http/CookieJar.php'; 0032 0033 /** 0034 * @see Zend_Oauth_Consumer 0035 */ 0036 // require_once 'Zend/Oauth/Consumer.php'; 0037 0038 /** 0039 * @see Zend_Oauth_Token_Access 0040 */ 0041 // require_once 'Zend/Oauth/Token/Access.php'; 0042 0043 /** 0044 * @see Zend_Service_Twitter_Response 0045 */ 0046 // require_once 'Zend/Service/Twitter/Response.php'; 0047 0048 /** 0049 * @category Zend 0050 * @package Zend_Service 0051 * @subpackage Twitter 0052 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0053 * @license http://framework.zend.com/license/new-bsd New BSD License 0054 */ 0055 class Zend_Service_Twitter 0056 { 0057 /** 0058 * Base URI for all API calls 0059 */ 0060 const API_BASE_URI = 'https://api.twitter.com/1.1/'; 0061 0062 /** 0063 * OAuth Endpoint 0064 */ 0065 const OAUTH_BASE_URI = 'https://api.twitter.com/oauth'; 0066 0067 /** 0068 * 246 is the current limit for a status message, 140 characters are displayed 0069 * initially, with the remainder linked from the web UI or client. The limit is 0070 * applied to a html encoded UTF-8 string (i.e. entities are counted in the limit 0071 * which may appear unusual but is a security measure). 0072 * 0073 * This should be reviewed in the future... 0074 */ 0075 const STATUS_MAX_CHARACTERS = 246; 0076 0077 /** 0078 * @var array 0079 */ 0080 protected $cookieJar; 0081 0082 /** 0083 * Date format for 'since' strings 0084 * 0085 * @var string 0086 */ 0087 protected $dateFormat = 'D, d M Y H:i:s T'; 0088 0089 /** 0090 * @var Zend_Http_Client 0091 */ 0092 protected $httpClient = null; 0093 0094 /** 0095 * Current method type (for method proxying) 0096 * 0097 * @var string 0098 */ 0099 protected $methodType; 0100 0101 /** 0102 * Oauth Consumer 0103 * 0104 * @var Zend_Oauth_Consumer 0105 */ 0106 protected $oauthConsumer = null; 0107 0108 /** 0109 * Types of API methods 0110 * 0111 * @var array 0112 */ 0113 protected $methodTypes = array( 0114 'account', 0115 'application', 0116 'blocks', 0117 'directmessages', 0118 'favorites', 0119 'friendships', 0120 'search', 0121 'statuses', 0122 'users', 0123 ); 0124 0125 /** 0126 * Options passed to constructor 0127 * 0128 * @var array 0129 */ 0130 protected $options = array(); 0131 0132 /** 0133 * Username 0134 * 0135 * @var string 0136 */ 0137 protected $username; 0138 0139 /** 0140 * Constructor 0141 * 0142 * @param null|array|Zend_Config $options 0143 * @param null|Zend_Oauth_Consumer $consumer 0144 * @param null|Zend_Http_Client $httpClient 0145 */ 0146 public function __construct($options = null, Zend_Oauth_Consumer $consumer = null, Zend_Http_Client $httpClient = null) 0147 { 0148 if ($options instanceof Zend_Config) { 0149 $options = $options->toArray(); 0150 } 0151 if (!is_array($options)) { 0152 $options = array(); 0153 } 0154 0155 $this->options = $options; 0156 0157 if (isset($options['username'])) { 0158 $this->setUsername($options['username']); 0159 } 0160 0161 $accessToken = false; 0162 if (isset($options['accessToken'])) { 0163 $accessToken = $options['accessToken']; 0164 } elseif (isset($options['access_token'])) { 0165 $accessToken = $options['access_token']; 0166 } 0167 0168 $oauthOptions = array(); 0169 if (isset($options['oauthOptions'])) { 0170 $oauthOptions = $options['oauthOptions']; 0171 } elseif (isset($options['oauth_options'])) { 0172 $oauthOptions = $options['oauth_options']; 0173 } 0174 $oauthOptions['siteUrl'] = self::OAUTH_BASE_URI; 0175 0176 $httpClientOptions = array(); 0177 if (isset($options['httpClientOptions'])) { 0178 $httpClientOptions = $options['httpClientOptions']; 0179 } elseif (isset($options['http_client_options'])) { 0180 $httpClientOptions = $options['http_client_options']; 0181 } 0182 0183 // If we have an OAuth access token, use the HTTP client it provides 0184 if ($accessToken && is_array($accessToken) 0185 && (isset($accessToken['token']) && isset($accessToken['secret'])) 0186 ) { 0187 $token = new Zend_Oauth_Token_Access(); 0188 $token->setToken($accessToken['token']); 0189 $token->setTokenSecret($accessToken['secret']); 0190 $accessToken = $token; 0191 } 0192 if ($accessToken && $accessToken instanceof Zend_Oauth_Token_Access) { 0193 $oauthOptions['token'] = $accessToken; 0194 $this->setHttpClient($accessToken->getHttpClient($oauthOptions, self::OAUTH_BASE_URI, $httpClientOptions)); 0195 return; 0196 } 0197 0198 // See if we were passed an http client 0199 if (isset($options['httpClient']) && null === $httpClient) { 0200 $httpClient = $options['httpClient']; 0201 } elseif (isset($options['http_client']) && null === $httpClient) { 0202 $httpClient = $options['http_client']; 0203 } 0204 if ($httpClient instanceof Zend_Http_Client) { 0205 $this->httpClient = $httpClient; 0206 } else { 0207 $this->setHttpClient(new Zend_Http_Client(null, $httpClientOptions)); 0208 } 0209 0210 // Set the OAuth consumer 0211 if ($consumer === null) { 0212 $consumer = new Zend_Oauth_Consumer($oauthOptions); 0213 } 0214 $this->oauthConsumer = $consumer; 0215 } 0216 0217 /** 0218 * Proxy service methods 0219 * 0220 * @param string $type 0221 * @return Twitter 0222 * @throws Exception\DomainException If method not in method types list 0223 */ 0224 public function __get($type) 0225 { 0226 $type = strtolower($type); 0227 $type = str_replace('_', '', $type); 0228 if (!in_array($type, $this->methodTypes)) { 0229 // require_once 'Zend/Service/Twitter/Exception.php'; 0230 throw new Zend_Service_Twitter_Exception( 0231 'Invalid method type "' . $type . '"' 0232 ); 0233 } 0234 $this->methodType = $type; 0235 return $this; 0236 } 0237 0238 /** 0239 * Method overloading 0240 * 0241 * @param string $method 0242 * @param array $params 0243 * @return mixed 0244 * @throws Exception\BadMethodCallException if unable to find method 0245 */ 0246 public function __call($method, $params) 0247 { 0248 if (method_exists($this->oauthConsumer, $method)) { 0249 $return = call_user_func_array(array($this->oauthConsumer, $method), $params); 0250 if ($return instanceof Zend_Oauth_Token_Access) { 0251 $this->setHttpClient($return->getHttpClient($this->options)); 0252 } 0253 return $return; 0254 } 0255 if (empty($this->methodType)) { 0256 // require_once 'Zend/Service/Twitter/Exception.php'; 0257 throw new Zend_Service_Twitter_Exception( 0258 'Invalid method "' . $method . '"' 0259 ); 0260 } 0261 0262 $test = str_replace('_', '', strtolower($method)); 0263 $test = $this->methodType . $test; 0264 if (!method_exists($this, $test)) { 0265 // require_once 'Zend/Service/Twitter/Exception.php'; 0266 throw new Zend_Service_Twitter_Exception( 0267 'Invalid method "' . $test . '"' 0268 ); 0269 } 0270 0271 return call_user_func_array(array($this, $test), $params); 0272 } 0273 0274 /** 0275 * Set HTTP client 0276 * 0277 * @param Zend_Http_Client $client 0278 * @return self 0279 */ 0280 public function setHttpClient(Zend_Http_Client $client) 0281 { 0282 $this->httpClient = $client; 0283 $this->httpClient->setHeaders(array('Accept-Charset' => 'ISO-8859-1,utf-8')); 0284 return $this; 0285 } 0286 0287 /** 0288 * Get the HTTP client 0289 * 0290 * Lazy loads one if none present 0291 * 0292 * @return Zend_Http_Client 0293 */ 0294 public function getHttpClient() 0295 { 0296 if (null === $this->httpClient) { 0297 $this->setHttpClient(new Zend_Http_Client()); 0298 } 0299 return $this->httpClient; 0300 } 0301 0302 /** 0303 * Retrieve username 0304 * 0305 * @return string 0306 */ 0307 public function getUsername() 0308 { 0309 return $this->username; 0310 } 0311 0312 /** 0313 * Set username 0314 * 0315 * @param string $value 0316 * @return self 0317 */ 0318 public function setUsername($value) 0319 { 0320 $this->username = $value; 0321 return $this; 0322 } 0323 0324 /** 0325 * Checks for an authorised state 0326 * 0327 * @return bool 0328 */ 0329 public function isAuthorised() 0330 { 0331 if ($this->getHttpClient() instanceof Zend_Oauth_Client) { 0332 return true; 0333 } 0334 return false; 0335 } 0336 0337 /** 0338 * Verify Account Credentials 0339 * 0340 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0341 * @throws Exception\DomainException if unable to decode JSON payload 0342 * @return Zend_Service_Twitter_Response 0343 */ 0344 public function accountVerifyCredentials() 0345 { 0346 $this->init(); 0347 $response = $this->get('account/verify_credentials'); 0348 return new Zend_Service_Twitter_Response($response); 0349 } 0350 0351 /** 0352 * Returns the number of api requests you have left per hour. 0353 * 0354 * @todo Have a separate payload object to represent rate limits 0355 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0356 * @throws Exception\DomainException if unable to decode JSON payload 0357 * @return Zend_Service_Twitter_Response 0358 */ 0359 public function applicationRateLimitStatus() 0360 { 0361 $this->init(); 0362 $response = $this->get('application/rate_limit_status'); 0363 return new Zend_Service_Twitter_Response($response); 0364 } 0365 0366 /** 0367 * Blocks the user specified in the ID parameter as the authenticating user. 0368 * Destroys a friendship to the blocked user if it exists. 0369 * 0370 * @param integer|string $id The ID or screen name of a user to block. 0371 * @throws Exception\DomainException if unable to decode JSON payload 0372 * @return Zend_Service_Twitter_Response 0373 */ 0374 public function blocksCreate($id) 0375 { 0376 $this->init(); 0377 $path = 'blocks/create'; 0378 $params = $this->createUserParameter($id, array()); 0379 $response = $this->post($path, $params); 0380 return new Zend_Service_Twitter_Response($response); 0381 } 0382 0383 /** 0384 * Un-blocks the user specified in the ID parameter for the authenticating user 0385 * 0386 * @param integer|string $id The ID or screen_name of the user to un-block. 0387 * @throws Exception\DomainException if unable to decode JSON payload 0388 * @return Zend_Service_Twitter_Response 0389 */ 0390 public function blocksDestroy($id) 0391 { 0392 $this->init(); 0393 $path = 'blocks/destroy'; 0394 $params = $this->createUserParameter($id, array()); 0395 $response = $this->post($path, $params); 0396 return new Zend_Service_Twitter_Response($response); 0397 } 0398 0399 /** 0400 * Returns an array of user ids that the authenticating user is blocking 0401 * 0402 * @param integer $cursor Optional. Specifies the cursor position at which to begin listing ids; defaults to first "page" of results. 0403 * @throws Exception\DomainException if unable to decode JSON payload 0404 * @return Zend_Service_Twitter_Response 0405 */ 0406 public function blocksIds($cursor = -1) 0407 { 0408 $this->init(); 0409 $path = 'blocks/ids'; 0410 $response = $this->get($path, array('cursor' => $cursor)); 0411 return new Zend_Service_Twitter_Response($response); 0412 } 0413 0414 /** 0415 * Returns an array of user objects that the authenticating user is blocking 0416 * 0417 * @param integer $cursor Optional. Specifies the cursor position at which to begin listing ids; defaults to first "page" of results. 0418 * @throws Exception\DomainException if unable to decode JSON payload 0419 * @return Zend_Service_Twitter_Response 0420 */ 0421 public function blocksList($cursor = -1) 0422 { 0423 $this->init(); 0424 $path = 'blocks/list'; 0425 $response = $this->get($path, array('cursor' => $cursor)); 0426 return new Zend_Service_Twitter_Response($response); 0427 } 0428 0429 /** 0430 * Destroy a direct message 0431 * 0432 * @param int $id ID of message to destroy 0433 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0434 * @throws Exception\DomainException if unable to decode JSON payload 0435 * @return Zend_Service_Twitter_Response 0436 */ 0437 public function directMessagesDestroy($id) 0438 { 0439 $this->init(); 0440 $path = 'direct_messages/destroy'; 0441 $params = array('id' => $this->validInteger($id)); 0442 $response = $this->post($path, $params); 0443 return new Zend_Service_Twitter_Response($response); 0444 } 0445 0446 /** 0447 * Retrieve direct messages for the current user 0448 * 0449 * $options may include one or more of the following keys 0450 * - count: return page X of results 0451 * - since_id: return statuses only greater than the one specified 0452 * - max_id: return statuses with an ID less than (older than) or equal to that specified 0453 * - include_entities: setting to false will disable embedded entities 0454 * - skip_status:setting to true, "t", or 1 will omit the status in returned users 0455 * 0456 * @param array $options 0457 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0458 * @throws Exception\DomainException if unable to decode JSON payload 0459 * @return Zend_Service_Twitter_Response 0460 */ 0461 public function directMessagesMessages(array $options = array()) 0462 { 0463 $this->init(); 0464 $path = 'direct_messages'; 0465 $params = array(); 0466 foreach ($options as $key => $value) { 0467 switch (strtolower($key)) { 0468 case 'count': 0469 $params['count'] = (int) $value; 0470 break; 0471 case 'since_id': 0472 $params['since_id'] = $this->validInteger($value); 0473 break; 0474 case 'max_id': 0475 $params['max_id'] = $this->validInteger($value); 0476 break; 0477 case 'include_entities': 0478 $params['include_entities'] = (bool) $value; 0479 break; 0480 case 'skip_status': 0481 $params['skip_status'] = (bool) $value; 0482 break; 0483 default: 0484 break; 0485 } 0486 } 0487 $response = $this->get($path, $params); 0488 return new Zend_Service_Twitter_Response($response); 0489 } 0490 0491 /** 0492 * Send a direct message to a user 0493 * 0494 * @param int|string $user User to whom to send message 0495 * @param string $text Message to send to user 0496 * @throws Exception\InvalidArgumentException if message is empty 0497 * @throws Exception\OutOfRangeException if message is too long 0498 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0499 * @throws Exception\DomainException if unable to decode JSON payload 0500 * @return Zend_Service_Twitter_Response 0501 */ 0502 public function directMessagesNew($user, $text) 0503 { 0504 $this->init(); 0505 $path = 'direct_messages/new'; 0506 0507 $len = iconv_strlen($text, 'UTF-8'); 0508 if (0 == $len) { 0509 // require_once 'Zend/Service/Twitter/Exception.php'; 0510 throw new Zend_Service_Twitter_Exception( 0511 'Direct message must contain at least one character' 0512 ); 0513 } elseif (140 < $len) { 0514 // require_once 'Zend/Service/Twitter/Exception.php'; 0515 throw new Zend_Service_Twitter_Exception( 0516 'Direct message must contain no more than 140 characters' 0517 ); 0518 } 0519 0520 $params = $this->createUserParameter($user, array()); 0521 $params['text'] = $text; 0522 $response = $this->post($path, $params); 0523 return new Zend_Service_Twitter_Response($response); 0524 } 0525 0526 /** 0527 * Retrieve list of direct messages sent by current user 0528 * 0529 * $options may include one or more of the following keys 0530 * - count: return page X of results 0531 * - page: return starting at page 0532 * - since_id: return statuses only greater than the one specified 0533 * - max_id: return statuses with an ID less than (older than) or equal to that specified 0534 * - include_entities: setting to false will disable embedded entities 0535 * 0536 * @param array $options 0537 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0538 * @throws Exception\DomainException if unable to decode JSON payload 0539 * @return Zend_Service_Twitter_Response 0540 */ 0541 public function directMessagesSent(array $options = array()) 0542 { 0543 $this->init(); 0544 $path = 'direct_messages/sent'; 0545 $params = array(); 0546 foreach ($options as $key => $value) { 0547 switch (strtolower($key)) { 0548 case 'count': 0549 $params['count'] = (int) $value; 0550 break; 0551 case 'page': 0552 $params['page'] = (int) $value; 0553 break; 0554 case 'since_id': 0555 $params['since_id'] = $this->validInteger($value); 0556 break; 0557 case 'max_id': 0558 $params['max_id'] = $this->validInteger($value); 0559 break; 0560 case 'include_entities': 0561 $params['include_entities'] = (bool) $value; 0562 break; 0563 default: 0564 break; 0565 } 0566 } 0567 $response = $this->get($path, $params); 0568 return new Zend_Service_Twitter_Response($response); 0569 } 0570 0571 /** 0572 * Mark a status as a favorite 0573 * 0574 * @param int $id Status ID you want to mark as a favorite 0575 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0576 * @throws Exception\DomainException if unable to decode JSON payload 0577 * @return Zend_Service_Twitter_Response 0578 */ 0579 public function favoritesCreate($id) 0580 { 0581 $this->init(); 0582 $path = 'favorites/create'; 0583 $params = array('id' => $this->validInteger($id)); 0584 $response = $this->post($path, $params); 0585 return new Zend_Service_Twitter_Response($response); 0586 } 0587 0588 /** 0589 * Remove a favorite 0590 * 0591 * @param int $id Status ID you want to de-list as a favorite 0592 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0593 * @throws Exception\DomainException if unable to decode JSON payload 0594 * @return Zend_Service_Twitter_Response 0595 */ 0596 public function favoritesDestroy($id) 0597 { 0598 $this->init(); 0599 $path = 'favorites/destroy'; 0600 $params = array('id' => $this->validInteger($id)); 0601 $response = $this->post($path, $params); 0602 return new Zend_Service_Twitter_Response($response); 0603 } 0604 0605 /** 0606 * Fetch favorites 0607 * 0608 * $options may contain one or more of the following: 0609 * - user_id: Id of a user for whom to fetch favorites 0610 * - screen_name: Screen name of a user for whom to fetch favorites 0611 * - count: number of tweets to attempt to retrieve, up to 200 0612 * - since_id: return results only after the specified tweet id 0613 * - max_id: return results with an ID less than (older than) or equal to the specified ID 0614 * - include_entities: when set to false, entities member will be omitted 0615 * 0616 * @param array $params 0617 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0618 * @throws Exception\DomainException if unable to decode JSON payload 0619 * @return Zend_Service_Twitter_Response 0620 */ 0621 public function favoritesList(array $options = array()) 0622 { 0623 $this->init(); 0624 $path = 'favorites/list'; 0625 $params = array(); 0626 foreach ($options as $key => $value) { 0627 switch (strtolower($key)) { 0628 case 'user_id': 0629 $params['user_id'] = $this->validInteger($value); 0630 break; 0631 case 'screen_name': 0632 $params['screen_name'] = $value; 0633 break; 0634 case 'count': 0635 $params['count'] = (int) $value; 0636 break; 0637 case 'since_id': 0638 $params['since_id'] = $this->validInteger($value); 0639 break; 0640 case 'max_id': 0641 $params['max_id'] = $this->validInteger($value); 0642 break; 0643 case 'include_entities': 0644 $params['include_entities'] = (bool) $value; 0645 break; 0646 default: 0647 break; 0648 } 0649 } 0650 $response = $this->get($path, $params); 0651 return new Zend_Service_Twitter_Response($response); 0652 } 0653 0654 /** 0655 * Create friendship 0656 * 0657 * @param int|string $id User ID or name of new friend 0658 * @param array $params Additional parameters to pass 0659 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0660 * @throws Exception\DomainException if unable to decode JSON payload 0661 * @return Zend_Service_Twitter_Response 0662 */ 0663 public function friendshipsCreate($id, array $params = array()) 0664 { 0665 $this->init(); 0666 $path = 'friendships/create'; 0667 $params = $this->createUserParameter($id, $params); 0668 $allowed = array( 0669 'user_id' => null, 0670 'screen_name' => null, 0671 'follow' => null, 0672 ); 0673 $params = array_intersect_key($params, $allowed); 0674 $response = $this->post($path, $params); 0675 return new Zend_Service_Twitter_Response($response); 0676 } 0677 0678 /** 0679 * Destroy friendship 0680 * 0681 * @param int|string $id User ID or name of friend to remove 0682 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0683 * @throws Exception\DomainException if unable to decode JSON payload 0684 * @return Zend_Service_Twitter_Response 0685 */ 0686 public function friendshipsDestroy($id) 0687 { 0688 $this->init(); 0689 $path = 'friendships/destroy'; 0690 $params = $this->createUserParameter($id, array()); 0691 $response = $this->post($path, $params); 0692 return new Zend_Service_Twitter_Response($response); 0693 } 0694 0695 /** 0696 * Search tweets 0697 * 0698 * $options may include any of the following: 0699 * - geocode: a string of the form "latitude, longitude, radius" 0700 * - lang: restrict tweets to the two-letter language code 0701 * - locale: query is in the given two-letter language code 0702 * - result_type: what type of results to receive: mixed, recent, or popular 0703 * - count: number of tweets to return per page; up to 100 0704 * - until: return tweets generated before the given date 0705 * - since_id: return resutls with an ID greater than (more recent than) the given ID 0706 * - max_id: return results with an ID less than (older than) the given ID 0707 * - include_entities: whether or not to include embedded entities 0708 * 0709 * @param string $query 0710 * @param array $options 0711 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0712 * @throws Exception\DomainException if unable to decode JSON payload 0713 * @return Zend_Service_Twitter_Response 0714 */ 0715 public function searchTweets($query, array $options = array()) 0716 { 0717 $this->init(); 0718 $path = 'search/tweets'; 0719 0720 $len = iconv_strlen($query, 'UTF-8'); 0721 if (0 == $len) { 0722 // require_once 'Zend/Service/Twitter/Exception.php'; 0723 throw new Zend_Service_Twitter_Exception( 0724 'Query must contain at least one character' 0725 ); 0726 } 0727 0728 $params = array('q' => $query); 0729 foreach ($options as $key => $value) { 0730 switch (strtolower($key)) { 0731 case 'geocode': 0732 if (!substr_count($value, ',') !== 2) { 0733 // require_once 'Zend/Service/Twitter/Exception.php'; 0734 throw new Zend_Service_Twitter_Exception( 0735 '"geocode" must be of the format "latitude,longitude,radius"' 0736 ); 0737 } 0738 list($latitude, $longitude, $radius) = explode(',', $value); 0739 $radius = trim($radius); 0740 if (!preg_match('/^\d+(mi|km)$/', $radius)) { 0741 // require_once 'Zend/Service/Twitter/Exception.php'; 0742 throw new Zend_Service_Twitter_Exception( 0743 'Radius segment of "geocode" must be of the format "[unit](mi|km)"' 0744 ); 0745 } 0746 $latitude = (float) $latitude; 0747 $longitude = (float) $longitude; 0748 $params['geocode'] = $latitude . ',' . $longitude . ',' . $radius; 0749 break; 0750 case 'lang': 0751 if (strlen($value) > 2) { 0752 // require_once 'Zend/Service/Twitter/Exception.php'; 0753 throw new Zend_Service_Twitter_Exception( 0754 'Query language must be a 2 character string' 0755 ); 0756 } 0757 $params['lang'] = strtolower($value); 0758 break; 0759 case 'locale': 0760 if (strlen($value) > 2) { 0761 // require_once 'Zend/Service/Twitter/Exception.php'; 0762 throw new Zend_Service_Twitter_Exception( 0763 'Query locale must be a 2 character string' 0764 ); 0765 } 0766 $params['locale'] = strtolower($value); 0767 break; 0768 case 'result_type': 0769 $value = strtolower($value); 0770 if (!in_array($value, array('mixed', 'recent', 'popular'))) { 0771 // require_once 'Zend/Service/Twitter/Exception.php'; 0772 throw new Zend_Service_Twitter_Exception( 0773 'result_type must be one of "mixed", "recent", or "popular"' 0774 ); 0775 } 0776 $params['result_type'] = $value; 0777 break; 0778 case 'count': 0779 $value = (int) $value; 0780 if (1 > $value || 100 < $value) { 0781 // require_once 'Zend/Service/Twitter/Exception.php'; 0782 throw new Zend_Service_Twitter_Exception( 0783 'count must be between 1 and 100' 0784 ); 0785 } 0786 $params['count'] = $value; 0787 break; 0788 case 'until': 0789 if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) { 0790 // require_once 'Zend/Service/Twitter/Exception.php'; 0791 throw new Zend_Service_Twitter_Exception( 0792 '"until" must be a date in the format YYYY-MM-DD' 0793 ); 0794 } 0795 $params['until'] = $value; 0796 break; 0797 case 'since_id': 0798 $params['since_id'] = $this->validInteger($value); 0799 break; 0800 case 'max_id': 0801 $params['max_id'] = $this->validInteger($value); 0802 break; 0803 case 'include_entities': 0804 $params['include_entities'] = (bool) $value; 0805 break; 0806 default: 0807 break; 0808 } 0809 } 0810 $response = $this->get($path, $params); 0811 return new Zend_Service_Twitter_Response($response); 0812 } 0813 0814 /** 0815 * Destroy a status message 0816 * 0817 * @param int $id ID of status to destroy 0818 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0819 * @throws Exception\DomainException if unable to decode JSON payload 0820 * @return Zend_Service_Twitter_Response 0821 */ 0822 public function statusesDestroy($id) 0823 { 0824 $this->init(); 0825 $path = 'statuses/destroy/' . $this->validInteger($id); 0826 $response = $this->post($path); 0827 return new Zend_Service_Twitter_Response($response); 0828 } 0829 0830 /** 0831 * Friend Timeline Status 0832 * 0833 * $options may include one or more of the following keys 0834 * - count: number of tweets to attempt to retrieve, up to 200 0835 * - since_id: return results only after the specified tweet id 0836 * - max_id: return results with an ID less than (older than) or equal to the specified ID 0837 * - trim_user: when set to true, "t", or 1, user object in tweets will include only author's ID. 0838 * - contributor_details: when set to true, includes screen_name of each contributor 0839 * - include_entities: when set to false, entities member will be omitted 0840 * - exclude_replies: when set to true, will strip replies appearing in the timeline 0841 * 0842 * @param array $params 0843 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0844 * @throws Exception\DomainException if unable to decode JSON payload 0845 * @return Zend_Service_Twitter_Response 0846 */ 0847 public function statusesHomeTimeline(array $options = array()) 0848 { 0849 $this->init(); 0850 $path = 'statuses/home_timeline'; 0851 $params = array(); 0852 foreach ($options as $key => $value) { 0853 switch (strtolower($key)) { 0854 case 'count': 0855 $params['count'] = (int) $value; 0856 break; 0857 case 'since_id': 0858 $params['since_id'] = $this->validInteger($value); 0859 break; 0860 case 'max_id': 0861 $params['max_id'] = $this->validInteger($value); 0862 break; 0863 case 'trim_user': 0864 if (in_array($value, array(true, 'true', 't', 1, '1'))) { 0865 $value = true; 0866 } else { 0867 $value = false; 0868 } 0869 $params['trim_user'] = $value; 0870 break; 0871 case 'contributor_details:': 0872 $params['contributor_details:'] = (bool) $value; 0873 break; 0874 case 'include_entities': 0875 $params['include_entities'] = (bool) $value; 0876 break; 0877 case 'exclude_replies': 0878 $params['exclude_replies'] = (bool) $value; 0879 break; 0880 default: 0881 break; 0882 } 0883 } 0884 $response = $this->get($path, $params); 0885 return new Zend_Service_Twitter_Response($response); 0886 } 0887 0888 /** 0889 * Get status replies 0890 * 0891 * $options may include one or more of the following keys 0892 * - count: number of tweets to attempt to retrieve, up to 200 0893 * - since_id: return results only after the specified tweet id 0894 * - max_id: return results with an ID less than (older than) or equal to the specified ID 0895 * - trim_user: when set to true, "t", or 1, user object in tweets will include only author's ID. 0896 * - contributor_details: when set to true, includes screen_name of each contributor 0897 * - include_entities: when set to false, entities member will be omitted 0898 * 0899 * @param array $options 0900 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0901 * @throws Exception\DomainException if unable to decode JSON payload 0902 * @return Zend_Service_Twitter_Response 0903 */ 0904 public function statusesMentionsTimeline(array $options = array()) 0905 { 0906 $this->init(); 0907 $path = 'statuses/mentions_timeline'; 0908 $params = array(); 0909 foreach ($options as $key => $value) { 0910 switch (strtolower($key)) { 0911 case 'count': 0912 $params['count'] = (int) $value; 0913 break; 0914 case 'since_id': 0915 $params['since_id'] = $this->validInteger($value); 0916 break; 0917 case 'max_id': 0918 $params['max_id'] = $this->validInteger($value); 0919 break; 0920 case 'trim_user': 0921 if (in_array($value, array(true, 'true', 't', 1, '1'))) { 0922 $value = true; 0923 } else { 0924 $value = false; 0925 } 0926 $params['trim_user'] = $value; 0927 break; 0928 case 'contributor_details:': 0929 $params['contributor_details:'] = (bool) $value; 0930 break; 0931 case 'include_entities': 0932 $params['include_entities'] = (bool) $value; 0933 break; 0934 default: 0935 break; 0936 } 0937 } 0938 $response = $this->get($path, $params); 0939 return new Zend_Service_Twitter_Response($response); 0940 } 0941 0942 /** 0943 * Public Timeline status 0944 * 0945 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0946 * @throws Exception\DomainException if unable to decode JSON payload 0947 * @return Zend_Service_Twitter_Response 0948 */ 0949 public function statusesSample() 0950 { 0951 $this->init(); 0952 $path = 'statuses/sample'; 0953 $response = $this->get($path); 0954 return new Zend_Service_Twitter_Response($response); 0955 } 0956 0957 /** 0958 * Show a single status 0959 * 0960 * @param int $id Id of status to show 0961 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0962 * @throws Exception\DomainException if unable to decode JSON payload 0963 * @return Zend_Service_Twitter_Response 0964 */ 0965 public function statusesShow($id) 0966 { 0967 $this->init(); 0968 $path = 'statuses/show/' . $this->validInteger($id); 0969 $response = $this->get($path); 0970 return new Zend_Service_Twitter_Response($response); 0971 } 0972 0973 /** 0974 * Update user's current status 0975 * 0976 * @todo Support additional parameters supported by statuses/update endpoint 0977 * @param string $status 0978 * @param null|int $inReplyToStatusId 0979 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 0980 * @throws Exception\OutOfRangeException if message is too long 0981 * @throws Exception\InvalidArgumentException if message is empty 0982 * @throws Exception\DomainException if unable to decode JSON payload 0983 * @return Zend_Service_Twitter_Response 0984 */ 0985 public function statusesUpdate($status, $inReplyToStatusId = null) 0986 { 0987 $this->init(); 0988 $path = 'statuses/update'; 0989 $len = iconv_strlen(htmlspecialchars($status, ENT_QUOTES, 'UTF-8'), 'UTF-8'); 0990 if ($len > self::STATUS_MAX_CHARACTERS) { 0991 // require_once 'Zend/Service/Twitter/Exception.php'; 0992 throw new Zend_Service_Twitter_Exception( 0993 'Status must be no more than ' 0994 . self::STATUS_MAX_CHARACTERS 0995 . ' characters in length' 0996 ); 0997 } elseif (0 == $len) { 0998 // require_once 'Zend/Service/Twitter/Exception.php'; 0999 throw new Zend_Service_Twitter_Exception( 1000 'Status must contain at least one character' 1001 ); 1002 } 1003 1004 $params = array('status' => $status); 1005 $inReplyToStatusId = $this->validInteger($inReplyToStatusId); 1006 if ($inReplyToStatusId) { 1007 $params['in_reply_to_status_id'] = $inReplyToStatusId; 1008 } 1009 $response = $this->post($path, $params); 1010 return new Zend_Service_Twitter_Response($response); 1011 } 1012 1013 /** 1014 * User Timeline status 1015 * 1016 * $options may include one or more of the following keys 1017 * - user_id: Id of a user for whom to fetch favorites 1018 * - screen_name: Screen name of a user for whom to fetch favorites 1019 * - count: number of tweets to attempt to retrieve, up to 200 1020 * - since_id: return results only after the specified tweet id 1021 * - max_id: return results with an ID less than (older than) or equal to the specified ID 1022 * - trim_user: when set to true, "t", or 1, user object in tweets will include only author's ID. 1023 * - exclude_replies: when set to true, will strip replies appearing in the timeline 1024 * - contributor_details: when set to true, includes screen_name of each contributor 1025 * - include_rts: when set to false, will strip native retweets 1026 * 1027 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 1028 * @throws Exception\DomainException if unable to decode JSON payload 1029 * @return Zend_Service_Twitter_Response 1030 */ 1031 public function statusesUserTimeline(array $options = array()) 1032 { 1033 $this->init(); 1034 $path = 'statuses/user_timeline'; 1035 $params = array(); 1036 foreach ($options as $key => $value) { 1037 switch (strtolower($key)) { 1038 case 'user_id': 1039 $params['user_id'] = $this->validInteger($value); 1040 break; 1041 case 'screen_name': 1042 $params['screen_name'] = $this->validateScreenName($value); 1043 break; 1044 case 'count': 1045 $params['count'] = (int) $value; 1046 break; 1047 case 'since_id': 1048 $params['since_id'] = $this->validInteger($value); 1049 break; 1050 case 'max_id': 1051 $params['max_id'] = $this->validInteger($value); 1052 break; 1053 case 'trim_user': 1054 if (in_array($value, array(true, 'true', 't', 1, '1'))) { 1055 $value = true; 1056 } else { 1057 $value = false; 1058 } 1059 $params['trim_user'] = $value; 1060 break; 1061 case 'contributor_details:': 1062 $params['contributor_details:'] = (bool) $value; 1063 break; 1064 case 'exclude_replies': 1065 $params['exclude_replies'] = (bool) $value; 1066 break; 1067 case 'include_rts': 1068 $params['include_rts'] = (bool) $value; 1069 break; 1070 default: 1071 break; 1072 } 1073 } 1074 $response = $this->get($path, $params); 1075 return new Zend_Service_Twitter_Response($response); 1076 } 1077 1078 /** 1079 * Search users 1080 * 1081 * $options may include any of the following: 1082 * - page: the page of results to retrieve 1083 * - count: the number of users to retrieve per page; max is 20 1084 * - include_entities: if set to boolean true, include embedded entities 1085 * 1086 * @param string $query 1087 * @param array $options 1088 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 1089 * @throws Exception\DomainException if unable to decode JSON payload 1090 * @return Zend_Service_Twitter_Response 1091 */ 1092 public function usersSearch($query, array $options = array()) 1093 { 1094 $this->init(); 1095 $path = 'users/search'; 1096 1097 $len = iconv_strlen($query, 'UTF-8'); 1098 if (0 == $len) { 1099 // require_once 'Zend/Service/Twitter/Exception.php'; 1100 throw new Zend_Service_Twitter_Exception( 1101 'Query must contain at least one character' 1102 ); 1103 } 1104 1105 $params = array('q' => $query); 1106 foreach ($options as $key => $value) { 1107 switch (strtolower($key)) { 1108 case 'count': 1109 $value = (int) $value; 1110 if (1 > $value || 20 < $value) { 1111 // require_once 'Zend/Service/Twitter/Exception.php'; 1112 throw new Zend_Service_Twitter_Exception( 1113 'count must be between 1 and 20' 1114 ); 1115 } 1116 $params['count'] = $value; 1117 break; 1118 case 'page': 1119 $params['page'] = (int) $value; 1120 break; 1121 case 'include_entities': 1122 $params['include_entities'] = (bool) $value; 1123 break; 1124 default: 1125 break; 1126 } 1127 } 1128 $response = $this->get($path, $params); 1129 return new Zend_Service_Twitter_Response($response); 1130 } 1131 1132 1133 /** 1134 * Show extended information on a user 1135 * 1136 * @param int|string $id User ID or name 1137 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 1138 * @throws Exception\DomainException if unable to decode JSON payload 1139 * @return Zend_Service_Twitter_Response 1140 */ 1141 public function usersShow($id) 1142 { 1143 $this->init(); 1144 $path = 'users/show'; 1145 $params = $this->createUserParameter($id, array()); 1146 $response = $this->get($path, $params); 1147 return new Zend_Service_Twitter_Response($response); 1148 } 1149 1150 /** 1151 * Initialize HTTP authentication 1152 * 1153 * @return void 1154 * @throws Exception\DomainException if unauthorised 1155 */ 1156 protected function init() 1157 { 1158 if (!$this->isAuthorised() && $this->getUsername() !== null) { 1159 // require_once 'Zend/Service/Twitter/Exception.php'; 1160 throw new Zend_Service_Twitter_Exception( 1161 'Twitter session is unauthorised. You need to initialize ' 1162 . __CLASS__ . ' with an OAuth Access Token or use ' 1163 . 'its OAuth functionality to obtain an Access Token before ' 1164 . 'attempting any API actions that require authorisation' 1165 ); 1166 } 1167 $client = $this->getHttpClient(); 1168 $client->resetParameters(); 1169 if (null === $this->cookieJar) { 1170 $cookieJar = $client->getCookieJar(); 1171 if (null === $cookieJar) { 1172 $cookieJar = new Zend_Http_CookieJar(); 1173 } 1174 $this->cookieJar = $cookieJar; 1175 $this->cookieJar->reset(); 1176 } else { 1177 $client->setCookieJar($this->cookieJar); 1178 } 1179 } 1180 1181 /** 1182 * Protected function to validate that the integer is valid or return a 0 1183 * 1184 * @param $int 1185 * @throws Zend_Http_Client_Exception if HTTP request fails or times out 1186 * @return integer 1187 */ 1188 protected function validInteger($int) 1189 { 1190 if (preg_match("/(\d+)/", $int)) { 1191 return $int; 1192 } 1193 return 0; 1194 } 1195 1196 /** 1197 * Validate a screen name using Twitter rules 1198 * 1199 * @param string $name 1200 * @return string 1201 * @throws Exception\InvalidArgumentException 1202 */ 1203 protected function validateScreenName($name) 1204 { 1205 if (!preg_match('/^[a-zA-Z0-9_]{0,20}$/', $name)) { 1206 // require_once 'Zend/Service/Twitter/Exception.php'; 1207 throw new Zend_Service_Twitter_Exception( 1208 'Screen name, "' . $name 1209 . '" should only contain alphanumeric characters and' 1210 . ' underscores, and not exceed 15 characters.'); 1211 } 1212 return $name; 1213 } 1214 1215 /** 1216 * Call a remote REST web service URI 1217 * 1218 * @param string $path The path to append to the URI 1219 * @param Zend_Http_Client $client 1220 * @throws Zend_Http_Client_Exception 1221 * @return void 1222 */ 1223 protected function prepare($path, Zend_Http_Client $client) 1224 { 1225 $client->setUri(self::API_BASE_URI . $path . '.json'); 1226 1227 /** 1228 * Do this each time to ensure oauth calls do not inject new params 1229 */ 1230 $client->resetParameters(); 1231 } 1232 1233 /** 1234 * Performs an HTTP GET request to the $path. 1235 * 1236 * @param string $path 1237 * @param array $query Array of GET parameters 1238 * @throws Zend_Http_Client_Exception 1239 * @return Zend_Http_Response 1240 */ 1241 protected function get($path, array $query = array()) 1242 { 1243 $client = $this->getHttpClient(); 1244 $this->prepare($path, $client); 1245 $client->setParameterGet($query); 1246 $response = $client->request(Zend_Http_Client::GET); 1247 return $response; 1248 } 1249 1250 /** 1251 * Performs an HTTP POST request to $path. 1252 * 1253 * @param string $path 1254 * @param mixed $data Raw data to send 1255 * @throws Zend_Http_Client_Exception 1256 * @return Zend_Http_Response 1257 */ 1258 protected function post($path, $data = null) 1259 { 1260 $client = $this->getHttpClient(); 1261 $this->prepare($path, $client); 1262 $response = $this->performPost(Zend_Http_Client::POST, $data, $client); 1263 return $response; 1264 } 1265 1266 /** 1267 * Perform a POST or PUT 1268 * 1269 * Performs a POST or PUT request. Any data provided is set in the HTTP 1270 * client. String data is pushed in as raw POST data; array or object data 1271 * is pushed in as POST parameters. 1272 * 1273 * @param mixed $method 1274 * @param mixed $data 1275 * @return Zend_Http_Response 1276 */ 1277 protected function performPost($method, $data, Zend_Http_Client $client) 1278 { 1279 if (is_string($data)) { 1280 $client->setRawData($data); 1281 } elseif (is_array($data) || is_object($data)) { 1282 $client->setParameterPost((array) $data); 1283 } 1284 return $client->request($method); 1285 } 1286 1287 /** 1288 * Create a parameter representing the user 1289 * 1290 * Determines if $id is an integer, and, if so, sets the "user_id" parameter. 1291 * If not, assumes the $id is the "screen_name". 1292 * 1293 * @param int|string $id 1294 * @param array $params 1295 * @return array 1296 */ 1297 protected function createUserParameter($id, array $params) 1298 { 1299 if ($this->validInteger($id)) { 1300 $params['user_id'] = $id; 1301 return $params; 1302 } 1303 1304 $params['screen_name'] = $this->validateScreenName($id); 1305 return $params; 1306 } 1307 }