PageRenderTime 66ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Service/Twitter/Twitter.php

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