Twitter.php 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Service
  17. * @subpackage Twitter
  18. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id$
  21. */
  22. /**
  23. * @see Zend_Rest_Client
  24. */
  25. require_once 'Zend/Rest/Client.php';
  26. /**
  27. * @see Zend_Rest_Client_Result
  28. */
  29. require_once 'Zend/Rest/Client/Result.php';
  30. /**
  31. * @see Zend_Oauth_Consumer
  32. */
  33. require_once 'Zend/Oauth/Consumer.php';
  34. /**
  35. * @category Zend
  36. * @package Zend_Service
  37. * @subpackage Twitter
  38. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  39. * @license http://framework.zend.com/license/new-bsd New BSD License
  40. */
  41. class Zend_Service_Twitter extends Zend_Rest_Client
  42. {
  43. /**
  44. * 246 is the current limit for a status message, 140 characters are displayed
  45. * initially, with the remainder linked from the web UI or client. The limit is
  46. * applied to a html encoded UTF-8 string (i.e. entities are counted in the limit
  47. * which may appear unusual but is a security measure).
  48. *
  49. * This should be reviewed in the future...
  50. */
  51. const STATUS_MAX_CHARACTERS = 246;
  52. /**
  53. * OAuth Endpoint
  54. */
  55. const OAUTH_BASE_URI = 'http://twitter.com/oauth';
  56. /**
  57. * @var Zend_Http_CookieJar
  58. */
  59. protected $_cookieJar;
  60. /**
  61. * Date format for 'since' strings
  62. *
  63. * @var string
  64. */
  65. protected $_dateFormat = 'D, d M Y H:i:s T';
  66. /**
  67. * Username
  68. *
  69. * @var string
  70. */
  71. protected $_username;
  72. /**
  73. * Current method type (for method proxying)
  74. *
  75. * @var string
  76. */
  77. protected $_methodType;
  78. /**
  79. * Zend_Oauth Consumer
  80. *
  81. * @var Zend_Oauth_Consumer
  82. */
  83. protected $_oauthConsumer = null;
  84. /**
  85. * Types of API methods
  86. *
  87. * @var array
  88. */
  89. protected $_methodTypes = array(
  90. 'status',
  91. 'user',
  92. 'directMessage',
  93. 'friendship',
  94. 'account',
  95. 'favorite',
  96. 'block'
  97. );
  98. /**
  99. * Options passed to constructor
  100. *
  101. * @var array
  102. */
  103. protected $_options = array();
  104. /**
  105. * Local HTTP Client cloned from statically set client
  106. *
  107. * @var Zend_Http_Client
  108. */
  109. protected $_localHttpClient = null;
  110. /**
  111. * Constructor
  112. *
  113. * @param array $options Optional options array
  114. * @return void
  115. */
  116. public function __construct($options = null, Zend_Oauth_Consumer $consumer = null)
  117. {
  118. $this->setUri('http://api.twitter.com');
  119. if ($options instanceof Zend_Config) {
  120. $options = $options->toArray();
  121. }
  122. if (!is_array($options)) {
  123. $options = array();
  124. }
  125. $options['siteUrl'] = self::OAUTH_BASE_URI;
  126. $this->_options = $options;
  127. if (isset($options['username'])) {
  128. $this->setUsername($options['username']);
  129. }
  130. if (isset($options['accessToken'])
  131. && $options['accessToken'] instanceof Zend_Oauth_Token_Access) {
  132. $this->setLocalHttpClient($options['accessToken']->getHttpClient($options));
  133. } else {
  134. $this->setLocalHttpClient(clone self::getHttpClient());
  135. if ($consumer === null) {
  136. $this->_oauthConsumer = new Zend_Oauth_Consumer($options);
  137. } else {
  138. $this->_oauthConsumer = $consumer;
  139. }
  140. }
  141. }
  142. /**
  143. * Set local HTTP client as distinct from the static HTTP client
  144. * as inherited from Zend_Rest_Client.
  145. *
  146. * @param Zend_Http_Client $client
  147. * @return self
  148. */
  149. public function setLocalHttpClient(Zend_Http_Client $client)
  150. {
  151. $this->_localHttpClient = $client;
  152. $this->_localHttpClient->setHeaders('Accept-Charset', 'ISO-8859-1,utf-8');
  153. return $this;
  154. }
  155. /**
  156. * Get the local HTTP client as distinct from the static HTTP client
  157. * inherited from Zend_Rest_Client
  158. *
  159. * @return Zend_Http_Client
  160. */
  161. public function getLocalHttpClient()
  162. {
  163. return $this->_localHttpClient;
  164. }
  165. /**
  166. * Checks for an authorised state
  167. *
  168. * @return bool
  169. */
  170. public function isAuthorised()
  171. {
  172. if ($this->getLocalHttpClient() instanceof Zend_Oauth_Client) {
  173. return true;
  174. }
  175. return false;
  176. }
  177. /**
  178. * Retrieve username
  179. *
  180. * @return string
  181. */
  182. public function getUsername()
  183. {
  184. return $this->_username;
  185. }
  186. /**
  187. * Set username
  188. *
  189. * @param string $value
  190. * @return Zend_Service_Twitter
  191. */
  192. public function setUsername($value)
  193. {
  194. $this->_username = $value;
  195. return $this;
  196. }
  197. /**
  198. * Proxy service methods
  199. *
  200. * @param string $type
  201. * @return Zend_Service_Twitter
  202. * @throws Zend_Service_Twitter_Exception If method not in method types list
  203. */
  204. public function __get($type)
  205. {
  206. if (!in_array($type, $this->_methodTypes)) {
  207. include_once 'Zend/Service/Twitter/Exception.php';
  208. throw new Zend_Service_Twitter_Exception(
  209. 'Invalid method type "' . $type . '"'
  210. );
  211. }
  212. $this->_methodType = $type;
  213. return $this;
  214. }
  215. /**
  216. * Method overloading
  217. *
  218. * @param string $method
  219. * @param array $params
  220. * @return mixed
  221. * @throws Zend_Service_Twitter_Exception if unable to find method
  222. */
  223. public function __call($method, $params)
  224. {
  225. if (method_exists($this->_oauthConsumer, $method)) {
  226. $return = call_user_func_array(array($this->_oauthConsumer, $method), $params);
  227. if ($return instanceof Zend_Oauth_Token_Access) {
  228. $this->setLocalHttpClient($return->getHttpClient($this->_options));
  229. }
  230. return $return;
  231. }
  232. if (empty($this->_methodType)) {
  233. include_once 'Zend/Service/Twitter/Exception.php';
  234. throw new Zend_Service_Twitter_Exception(
  235. 'Invalid method "' . $method . '"'
  236. );
  237. }
  238. $test = $this->_methodType . ucfirst($method);
  239. if (!method_exists($this, $test)) {
  240. include_once 'Zend/Service/Twitter/Exception.php';
  241. throw new Zend_Service_Twitter_Exception(
  242. 'Invalid method "' . $test . '"'
  243. );
  244. }
  245. return call_user_func_array(array($this, $test), $params);
  246. }
  247. /**
  248. * Initialize HTTP authentication
  249. *
  250. * @return void
  251. */
  252. protected function _init()
  253. {
  254. if (!$this->isAuthorised() && $this->getUsername() !== null) {
  255. require_once 'Zend/Service/Twitter/Exception.php';
  256. throw new Zend_Service_Twitter_Exception(
  257. 'Twitter session is unauthorised. You need to initialize '
  258. . 'Zend_Service_Twitter with an OAuth Access Token or use '
  259. . 'its OAuth functionality to obtain an Access Token before '
  260. . 'attempting any API actions that require authorisation'
  261. );
  262. }
  263. $client = $this->_localHttpClient;
  264. $client->resetParameters();
  265. if (null == $this->_cookieJar) {
  266. $client->setCookieJar();
  267. $this->_cookieJar = $client->getCookieJar();
  268. } else {
  269. $client->setCookieJar($this->_cookieJar);
  270. }
  271. }
  272. /**
  273. * Set date header
  274. *
  275. * @param int|string $value
  276. * @deprecated Not supported by Twitter since April 08, 2009
  277. * @return void
  278. */
  279. protected function _setDate($value)
  280. {
  281. if (is_int($value)) {
  282. $date = date($this->_dateFormat, $value);
  283. } else {
  284. $date = date($this->_dateFormat, strtotime($value));
  285. }
  286. $this->_localHttpClient->setHeaders('If-Modified-Since', $date);
  287. }
  288. /**
  289. * Public Timeline status
  290. *
  291. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  292. * @return Zend_Rest_Client_Result
  293. */
  294. public function statusPublicTimeline()
  295. {
  296. $this->_init();
  297. $path = '/1/statuses/public_timeline.xml';
  298. $response = $this->_get($path);
  299. return new Zend_Rest_Client_Result($response->getBody());
  300. }
  301. /**
  302. * Friend Timeline Status
  303. *
  304. * $params may include one or more of the following keys
  305. * - id: ID of a friend whose timeline you wish to receive
  306. * - count: how many statuses to return
  307. * - since_id: return results only after the specific tweet
  308. * - page: return page X of results
  309. *
  310. * @param array $params
  311. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  312. * @return void
  313. */
  314. public function statusFriendsTimeline(array $params = array())
  315. {
  316. $this->_init();
  317. $path = '/1/statuses/friends_timeline';
  318. $_params = array();
  319. foreach ($params as $key => $value) {
  320. switch (strtolower($key)) {
  321. case 'count':
  322. $count = (int) $value;
  323. if (0 >= $count) {
  324. $count = 1;
  325. } elseif (200 < $count) {
  326. $count = 200;
  327. }
  328. $_params['count'] = (int) $count;
  329. break;
  330. case 'since_id':
  331. $_params['since_id'] = $this->_validInteger($value);
  332. break;
  333. case 'page':
  334. $_params['page'] = (int) $value;
  335. break;
  336. default:
  337. break;
  338. }
  339. }
  340. $path .= '.xml';
  341. $response = $this->_get($path, $_params);
  342. return new Zend_Rest_Client_Result($response->getBody());
  343. }
  344. /**
  345. * User Timeline status
  346. *
  347. * $params may include one or more of the following keys
  348. * - id: ID of a friend whose timeline you wish to receive
  349. * - since_id: return results only after the tweet id specified
  350. * - page: return page X of results
  351. * - count: how many statuses to return
  352. * - max_id: returns only statuses with an ID less than or equal to the specified ID
  353. * - user_id: specifies the ID of the user for whom to return the user_timeline
  354. * - screen_name: specfies the screen name of the user for whom to return the user_timeline
  355. * - include_rts: whether or not to return retweets
  356. * - trim_user: whether to return just the user ID or a full user object; omit to return full object
  357. * - include_entities: whether or not to return entities nodes with tweet metadata
  358. *
  359. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  360. * @return Zend_Rest_Client_Result
  361. */
  362. public function statusUserTimeline(array $params = array())
  363. {
  364. $this->_init();
  365. $path = '/1/statuses/user_timeline';
  366. $_params = array();
  367. foreach ($params as $key => $value) {
  368. switch (strtolower($key)) {
  369. case 'id':
  370. $path .= '/' . $value;
  371. break;
  372. case 'page':
  373. $_params['page'] = (int) $value;
  374. break;
  375. case 'count':
  376. $count = (int) $value;
  377. if (0 >= $count) {
  378. $count = 1;
  379. } elseif (200 < $count) {
  380. $count = 200;
  381. }
  382. $_params['count'] = $count;
  383. break;
  384. case 'user_id':
  385. $_params['user_id'] = $this->_validInteger($value);
  386. break;
  387. case 'screen_name':
  388. $_params['screen_name'] = $this->_validateScreenName($value);
  389. break;
  390. case 'since_id':
  391. $_params['since_id'] = $this->_validInteger($value);
  392. break;
  393. case 'max_id':
  394. $_params['max_id'] = $this->_validInteger($value);
  395. break;
  396. case 'include_rts':
  397. case 'trim_user':
  398. case 'include_entities':
  399. $_params[strtolower($key)] = $value ? '1' : '0';
  400. break;
  401. default:
  402. break;
  403. }
  404. }
  405. $path .= '.xml';
  406. $response = $this->_get($path, $_params);
  407. return new Zend_Rest_Client_Result($response->getBody());
  408. }
  409. /**
  410. * Show a single status
  411. *
  412. * @param int $id Id of status to show
  413. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  414. * @return Zend_Rest_Client_Result
  415. */
  416. public function statusShow($id)
  417. {
  418. $this->_init();
  419. $path = '/1/statuses/show/' . $this->_validInteger($id) . '.xml';
  420. $response = $this->_get($path);
  421. return new Zend_Rest_Client_Result($response->getBody());
  422. }
  423. /**
  424. * Update user's current status
  425. *
  426. * @param string $status
  427. * @param int $in_reply_to_status_id
  428. * @return Zend_Rest_Client_Result
  429. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  430. * @throws Zend_Service_Twitter_Exception if message is too short or too long
  431. */
  432. public function statusUpdate($status, $inReplyToStatusId = null)
  433. {
  434. $this->_init();
  435. $path = '/1/statuses/update.xml';
  436. $len = iconv_strlen(htmlspecialchars($status, ENT_QUOTES, 'UTF-8'), 'UTF-8');
  437. if ($len > self::STATUS_MAX_CHARACTERS) {
  438. include_once 'Zend/Service/Twitter/Exception.php';
  439. throw new Zend_Service_Twitter_Exception(
  440. 'Status must be no more than '
  441. . self::STATUS_MAX_CHARACTERS
  442. . ' characters in length'
  443. );
  444. } elseif (0 == $len) {
  445. include_once 'Zend/Service/Twitter/Exception.php';
  446. throw new Zend_Service_Twitter_Exception(
  447. 'Status must contain at least one character'
  448. );
  449. }
  450. $data = array('status' => $status);
  451. if (is_numeric($inReplyToStatusId) && !empty($inReplyToStatusId)) {
  452. $data['in_reply_to_status_id'] = $inReplyToStatusId;
  453. }
  454. $response = $this->_post($path, $data);
  455. return new Zend_Rest_Client_Result($response->getBody());
  456. }
  457. /**
  458. * Get status replies
  459. *
  460. * $params may include one or more of the following keys
  461. * - since_id: return results only after the specified tweet id
  462. * - page: return page X of results
  463. *
  464. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  465. * @return Zend_Rest_Client_Result
  466. */
  467. public function statusReplies(array $params = array())
  468. {
  469. $this->_init();
  470. $path = '/1/statuses/mentions.xml';
  471. $_params = array();
  472. foreach ($params as $key => $value) {
  473. switch (strtolower($key)) {
  474. case 'since_id':
  475. $_params['since_id'] = $this->_validInteger($value);
  476. break;
  477. case 'page':
  478. $_params['page'] = (int) $value;
  479. break;
  480. default:
  481. break;
  482. }
  483. }
  484. $response = $this->_get($path, $_params);
  485. return new Zend_Rest_Client_Result($response->getBody());
  486. }
  487. /**
  488. * Destroy a status message
  489. *
  490. * @param int $id ID of status to destroy
  491. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  492. * @return Zend_Rest_Client_Result
  493. */
  494. public function statusDestroy($id)
  495. {
  496. $this->_init();
  497. $path = '/1/statuses/destroy/' . $this->_validInteger($id) . '.xml';
  498. $response = $this->_post($path);
  499. return new Zend_Rest_Client_Result($response->getBody());
  500. }
  501. /**
  502. * User friends
  503. *
  504. * @param int|string $id Id or username of user for whom to fetch friends
  505. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  506. * @return Zend_Rest_Client_Result
  507. */
  508. public function userFriends(array $params = array())
  509. {
  510. $this->_init();
  511. $path = '/1/statuses/friends';
  512. $_params = array();
  513. foreach ($params as $key => $value) {
  514. switch (strtolower($key)) {
  515. case 'id':
  516. $path .= '/' . $value;
  517. break;
  518. case 'page':
  519. $_params['page'] = (int) $value;
  520. break;
  521. default:
  522. break;
  523. }
  524. }
  525. $path .= '.xml';
  526. $response = $this->_get($path, $_params);
  527. return new Zend_Rest_Client_Result($response->getBody());
  528. }
  529. /**
  530. * User Followers
  531. *
  532. * @param bool $lite If true, prevents inline inclusion of current status for followers; defaults to false
  533. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  534. * @return Zend_Rest_Client_Result
  535. */
  536. public function userFollowers($lite = false)
  537. {
  538. $this->_init();
  539. $path = '/1/statuses/followers.xml';
  540. if ($lite) {
  541. $this->lite = 'true';
  542. }
  543. $response = $this->_get($path);
  544. return new Zend_Rest_Client_Result($response->getBody());
  545. }
  546. /**
  547. * Show extended information on a user
  548. *
  549. * @param int|string $id User ID or name
  550. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  551. * @return Zend_Rest_Client_Result
  552. */
  553. public function userShow($id)
  554. {
  555. $this->_init();
  556. $path = '/1/users/show.xml';
  557. $response = $this->_get($path, array('id'=>$id));
  558. return new Zend_Rest_Client_Result($response->getBody());
  559. }
  560. /**
  561. * Retrieve direct messages for the current user
  562. *
  563. * $params may include one or more of the following keys
  564. * - since_id: return statuses only greater than the one specified
  565. * - page: return page X of results
  566. *
  567. * @param array $params
  568. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  569. * @return Zend_Rest_Client_Result
  570. */
  571. public function directMessageMessages(array $params = array())
  572. {
  573. $this->_init();
  574. $path = '/1/direct_messages.xml';
  575. $_params = array();
  576. foreach ($params as $key => $value) {
  577. switch (strtolower($key)) {
  578. case 'since_id':
  579. $_params['since_id'] = $this->_validInteger($value);
  580. break;
  581. case 'page':
  582. $_params['page'] = (int) $value;
  583. break;
  584. default:
  585. break;
  586. }
  587. }
  588. $response = $this->_get($path, $_params);
  589. return new Zend_Rest_Client_Result($response->getBody());
  590. }
  591. /**
  592. * Retrieve list of direct messages sent by current user
  593. *
  594. * $params may include one or more of the following keys
  595. * - since_id: return statuses only greater than the one specified
  596. * - page: return page X of results
  597. *
  598. * @param array $params
  599. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  600. * @return Zend_Rest_Client_Result
  601. */
  602. public function directMessageSent(array $params = array())
  603. {
  604. $this->_init();
  605. $path = '/1/direct_messages/sent.xml';
  606. $_params = array();
  607. foreach ($params as $key => $value) {
  608. switch (strtolower($key)) {
  609. case 'since_id':
  610. $_params['since_id'] = $this->_validInteger($value);
  611. break;
  612. case 'page':
  613. $_params['page'] = (int) $value;
  614. break;
  615. default:
  616. break;
  617. }
  618. }
  619. $response = $this->_get($path, $_params);
  620. return new Zend_Rest_Client_Result($response->getBody());
  621. }
  622. /**
  623. * Send a direct message to a user
  624. *
  625. * @param int|string $user User to whom to send message
  626. * @param string $text Message to send to user
  627. * @return Zend_Rest_Client_Result
  628. * @throws Zend_Service_Twitter_Exception if message is too short or too long
  629. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  630. */
  631. public function directMessageNew($user, $text)
  632. {
  633. $this->_init();
  634. $path = '/1/direct_messages/new.xml';
  635. $len = iconv_strlen($text, 'UTF-8');
  636. if (0 == $len) {
  637. throw new Zend_Service_Twitter_Exception(
  638. 'Direct message must contain at least one character'
  639. );
  640. } elseif (140 < $len) {
  641. throw new Zend_Service_Twitter_Exception(
  642. 'Direct message must contain no more than 140 characters'
  643. );
  644. }
  645. $data = array('user' => $user, 'text' => $text);
  646. $response = $this->_post($path, $data);
  647. return new Zend_Rest_Client_Result($response->getBody());
  648. }
  649. /**
  650. * Destroy a direct message
  651. *
  652. * @param int $id ID of message to destroy
  653. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  654. * @return Zend_Rest_Client_Result
  655. */
  656. public function directMessageDestroy($id)
  657. {
  658. $this->_init();
  659. $path = '/1/direct_messages/destroy/' . $this->_validInteger($id) . '.xml';
  660. $response = $this->_post($path);
  661. return new Zend_Rest_Client_Result($response->getBody());
  662. }
  663. /**
  664. * Create friendship
  665. *
  666. * @param int|string $id User ID or name of new friend
  667. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  668. * @return Zend_Rest_Client_Result
  669. */
  670. public function friendshipCreate($id)
  671. {
  672. $this->_init();
  673. $path = '/1/friendships/create/' . $id . '.xml';
  674. $response = $this->_post($path);
  675. return new Zend_Rest_Client_Result($response->getBody());
  676. }
  677. /**
  678. * Destroy friendship
  679. *
  680. * @param int|string $id User ID or name of friend to remove
  681. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  682. * @return Zend_Rest_Client_Result
  683. */
  684. public function friendshipDestroy($id)
  685. {
  686. $this->_init();
  687. $path = '/1/friendships/destroy/' . $id . '.xml';
  688. $response = $this->_post($path);
  689. return new Zend_Rest_Client_Result($response->getBody());
  690. }
  691. /**
  692. * Friendship exists
  693. *
  694. * @param int|string $id User ID or name of friend to see if they are your friend
  695. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  696. * @return Zend_Rest_Client_result
  697. */
  698. public function friendshipExists($id)
  699. {
  700. $this->_init();
  701. $path = '/1/friendships/exists.xml';
  702. $data = array('user_a' => $this->getUsername(), 'user_b' => $id);
  703. $response = $this->_get($path, $data);
  704. return new Zend_Rest_Client_Result($response->getBody());
  705. }
  706. /**
  707. * Verify Account Credentials
  708. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  709. *
  710. * @return Zend_Rest_Client_Result
  711. */
  712. public function accountVerifyCredentials()
  713. {
  714. $this->_init();
  715. $response = $this->_get('/1/account/verify_credentials.xml');
  716. return new Zend_Rest_Client_Result($response->getBody());
  717. }
  718. /**
  719. * End current session
  720. *
  721. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  722. * @return true
  723. */
  724. public function accountEndSession()
  725. {
  726. $this->_init();
  727. $this->_get('/1/account/end_session');
  728. return true;
  729. }
  730. /**
  731. * Returns the number of api requests you have left per hour.
  732. *
  733. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  734. * @return Zend_Rest_Client_Result
  735. */
  736. public function accountRateLimitStatus()
  737. {
  738. $this->_init();
  739. $response = $this->_get('/1/account/rate_limit_status.xml');
  740. return new Zend_Rest_Client_Result($response->getBody());
  741. }
  742. /**
  743. * Fetch favorites
  744. *
  745. * $params may contain one or more of the following:
  746. * - 'id': Id of a user for whom to fetch favorites
  747. * - 'page': Retrieve a different page of resuls
  748. *
  749. * @param array $params
  750. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  751. * @return Zend_Rest_Client_Result
  752. */
  753. public function favoriteFavorites(array $params = array())
  754. {
  755. $this->_init();
  756. $path = '/1/favorites';
  757. $_params = array();
  758. foreach ($params as $key => $value) {
  759. switch (strtolower($key)) {
  760. case 'id':
  761. $path .= '/' . $this->_validInteger($value);
  762. break;
  763. case 'page':
  764. $_params['page'] = (int) $value;
  765. break;
  766. default:
  767. break;
  768. }
  769. }
  770. $path .= '.xml';
  771. $response = $this->_get($path, $_params);
  772. return new Zend_Rest_Client_Result($response->getBody());
  773. }
  774. /**
  775. * Mark a status as a favorite
  776. *
  777. * @param int $id Status ID you want to mark as a favorite
  778. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  779. * @return Zend_Rest_Client_Result
  780. */
  781. public function favoriteCreate($id)
  782. {
  783. $this->_init();
  784. $path = '/1/favorites/create/' . $this->_validInteger($id) . '.xml';
  785. $response = $this->_post($path);
  786. return new Zend_Rest_Client_Result($response->getBody());
  787. }
  788. /**
  789. * Remove a favorite
  790. *
  791. * @param int $id Status ID you want to de-list as a favorite
  792. * @throws Zend_Http_Client_Exception if HTTP request fails or times out
  793. * @return Zend_Rest_Client_Result
  794. */
  795. public function favoriteDestroy($id)
  796. {
  797. $this->_init();
  798. $path = '/1/favorites/destroy/' . $this->_validInteger($id) . '.xml';
  799. $response = $this->_post($path);
  800. return new Zend_Rest_Client_Result($response->getBody());
  801. }
  802. /**
  803. * Blocks the user specified in the ID parameter as the authenticating user.
  804. * Destroys a friendship to the blocked user if it exists.
  805. *
  806. * @param integer|string $id The ID or screen name of a user to block.
  807. * @return Zend_Rest_Client_Result
  808. */
  809. public function blockCreate($id)
  810. {
  811. $this->_init();
  812. $path = '/1/blocks/create/' . $id . '.xml';
  813. $response = $this->_post($path);
  814. return new Zend_Rest_Client_Result($response->getBody());
  815. }
  816. /**
  817. * Un-blocks the user specified in the ID parameter for the authenticating user
  818. *
  819. * @param integer|string $id The ID or screen_name of the user to un-block.
  820. * @return Zend_Rest_Client_Result
  821. */
  822. public function blockDestroy($id)
  823. {
  824. $this->_init();
  825. $path = '/1/blocks/destroy/' . $id . '.xml';
  826. $response = $this->_post($path);
  827. return new Zend_Rest_Client_Result($response->getBody());
  828. }
  829. /**
  830. * Returns if the authenticating user is blocking a target user.
  831. *
  832. * @param string|integer $id The ID or screen_name of the potentially blocked user.
  833. * @param boolean $returnResult Instead of returning a boolean return the rest response from twitter
  834. * @return Boolean|Zend_Rest_Client_Result
  835. */
  836. public function blockExists($id, $returnResult = false)
  837. {
  838. $this->_init();
  839. $path = '/1/blocks/exists/' . $id . '.xml';
  840. $response = $this->_get($path);
  841. $cr = new Zend_Rest_Client_Result($response->getBody());
  842. if ($returnResult === true)
  843. return $cr;
  844. if (!empty($cr->request)) {
  845. return false;
  846. }
  847. return true;
  848. }
  849. /**
  850. * Returns an array of user objects that the authenticating user is blocking
  851. *
  852. * @param integer $page Optional. Specifies the page number of the results beginning at 1. A single page contains 20 ids.
  853. * @param boolean $returnUserIds Optional. Returns only the userid's instead of the whole user object
  854. * @return Zend_Rest_Client_Result
  855. */
  856. public function blockBlocking($page = 1, $returnUserIds = false)
  857. {
  858. $this->_init();
  859. $path = '/1/blocks/blocking';
  860. if ($returnUserIds === true) {
  861. $path .= '/ids';
  862. }
  863. $path .= '.xml';
  864. $response = $this->_get($path, array('page' => $page));
  865. return new Zend_Rest_Client_Result($response->getBody());
  866. }
  867. /**
  868. * Protected function to validate that the integer is valid or return a 0
  869. * @param mixed $int
  870. * @return integer
  871. */
  872. protected function _validInteger($int)
  873. {
  874. if (preg_match("/(\d+)/", $int)) {
  875. return $int;
  876. }
  877. return 0;
  878. }
  879. /**
  880. * Validate a screen name using Twitter rules
  881. *
  882. * @param string $name
  883. * @throws Zend_Service_Twitter_Exception
  884. * @return string
  885. */
  886. protected function _validateScreenName($name)
  887. {
  888. if (!preg_match('/^[a-zA-Z0-9_]{0,15}$/', $name)) {
  889. require_once 'Zend/Service/Twitter/Exception.php';
  890. throw new Zend_Service_Twitter_Exception(
  891. 'Screen name, "' . $name
  892. . '" should only contain alphanumeric characters and'
  893. . ' underscores, and not exceed 15 characters.');
  894. }
  895. return $name;
  896. }
  897. /**
  898. * Call a remote REST web service URI and return the Zend_Http_Response object
  899. *
  900. * @param string $path The path to append to the URI
  901. * @throws Zend_Rest_Client_Exception
  902. * @return void
  903. */
  904. protected function _prepare($path)
  905. {
  906. // Get the URI object and configure it
  907. if (!$this->_uri instanceof Zend_Uri_Http) {
  908. require_once 'Zend/Rest/Client/Exception.php';
  909. throw new Zend_Rest_Client_Exception(
  910. 'URI object must be set before performing call'
  911. );
  912. }
  913. $uri = $this->_uri->getUri();
  914. if ($path[0] != '/' && $uri[strlen($uri) - 1] != '/') {
  915. $path = '/' . $path;
  916. }
  917. $this->_uri->setPath($path);
  918. /**
  919. * Get the HTTP client and configure it for the endpoint URI.
  920. * Do this each time because the Zend_Http_Client instance is shared
  921. * among all Zend_Service_Abstract subclasses.
  922. */
  923. $this->_localHttpClient->resetParameters()->setUri((string) $this->_uri);
  924. }
  925. /**
  926. * Performs an HTTP GET request to the $path.
  927. *
  928. * @param string $path
  929. * @param array $query Array of GET parameters
  930. * @throws Zend_Http_Client_Exception
  931. * @return Zend_Http_Response
  932. */
  933. protected function _get($path, array $query = null)
  934. {
  935. $this->_prepare($path);
  936. $this->_localHttpClient->setParameterGet($query);
  937. return $this->_localHttpClient->request(Zend_Http_Client::GET);
  938. }
  939. /**
  940. * Performs an HTTP POST request to $path.
  941. *
  942. * @param string $path
  943. * @param mixed $data Raw data to send
  944. * @throws Zend_Http_Client_Exception
  945. * @return Zend_Http_Response
  946. */
  947. protected function _post($path, $data = null)
  948. {
  949. $this->_prepare($path);
  950. return $this->_performPost(Zend_Http_Client::POST, $data);
  951. }
  952. /**
  953. * Perform a POST or PUT
  954. *
  955. * Performs a POST or PUT request. Any data provided is set in the HTTP
  956. * client. String data is pushed in as raw POST data; array or object data
  957. * is pushed in as POST parameters.
  958. *
  959. * @param mixed $method
  960. * @param mixed $data
  961. * @return Zend_Http_Response
  962. */
  963. protected function _performPost($method, $data = null)
  964. {
  965. $client = $this->_localHttpClient;
  966. if (is_string($data)) {
  967. $client->setRawData($data);
  968. } elseif (is_array($data) || is_object($data)) {
  969. $client->setParameterPost((array) $data);
  970. }
  971. return $client->request($method);
  972. }
  973. }