PageRenderTime 43ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/library/Zend/Service/Delicious.php

https://bitbucket.org/baruffaldi/webapp-urltube
PHP | 616 lines | 272 code | 79 blank | 265 comment | 41 complexity | d4d36f4ca852087e5e5436c77f4c1c80 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, MIT
  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 Delicious
  18. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id: Delicious.php 9638 2008-06-08 15:58:11Z ghacek $
  21. */
  22. /**
  23. * @see Zend_Rest_Client
  24. */
  25. require_once 'Zend/Rest/Client.php';
  26. /**
  27. * @see Zend_Json_Decoder
  28. */
  29. require_once 'Zend/Json/Decoder.php';
  30. /**
  31. * @see Zend_Service_Delicious_SimplePost
  32. */
  33. require_once 'Zend/Service/Delicious/SimplePost.php';
  34. /**
  35. * @see Zend_Service_Delicious_Post
  36. */
  37. require_once 'Zend/Service/Delicious/Post.php';
  38. /**
  39. * @see Zend_Service_Delicious_PostList
  40. */
  41. require_once 'Zend/Service/Delicious/PostList.php';
  42. /**
  43. * Zend_Service_Delicious is a concrete implementation of the del.icio.us web service
  44. *
  45. * @category Zend
  46. * @package Zend_Service
  47. * @subpackage Delicious
  48. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  49. * @license http://framework.zend.com/license/new-bsd New BSD License
  50. */
  51. class Zend_Service_Delicious
  52. {
  53. const API_URI = 'https://api.del.icio.us';
  54. const PATH_UPDATE = '/v1/posts/update';
  55. const PATH_TAGS = '/v1/tags/get';
  56. const PATH_TAG_RENAME = '/v1/tags/rename';
  57. const PATH_BUNDLES = '/v1/tags/bundles/all';
  58. const PATH_BUNDLE_DELETE = '/v1/tags/bundles/delete';
  59. const PATH_BUNDLE_ADD = '/v1/tags/bundles/set';
  60. const PATH_DATES = '/v1/posts/dates';
  61. const PATH_POST_DELETE = '/v1/posts/delete';
  62. const PATH_POSTS_GET = '/v1/posts/get';
  63. const PATH_POSTS_ALL = '/v1/posts/all';
  64. const PATH_POSTS_ADD = '/v1/posts/add';
  65. const PATH_POSTS_RECENT = '/v1/posts/recent';
  66. const JSON_URI = 'http://del.icio.us';
  67. const JSON_POSTS = '/feeds/json/%s/%s';
  68. const JSON_TAGS = '/feeds/json/tags/%s';
  69. const JSON_NETWORK = '/feeds/json/network/%s';
  70. const JSON_FANS = '/feeds/json/fans/%s';
  71. const JSON_URL = '/feeds/json/url/data';
  72. /**
  73. * Zend_Service_Rest instance
  74. *
  75. * @var Zend_Service_Rest
  76. */
  77. protected $_rest;
  78. /**
  79. * Username
  80. *
  81. * @var string
  82. */
  83. protected $_authUname;
  84. /**
  85. * Password
  86. *
  87. * @var string
  88. */
  89. protected $_authPass;
  90. /**
  91. * Microtime of last request
  92. *
  93. * @var float
  94. */
  95. protected static $_lastRequestTime = 0;
  96. /**
  97. * Constructs a new del.icio.us Web Services Client
  98. *
  99. * @param string $uname Client username
  100. * @param string $pass Client password
  101. * @return void
  102. */
  103. public function __construct($uname = null, $pass = null)
  104. {
  105. $this->_rest = new Zend_Rest_Client();
  106. $this->_rest->getHttpClient()->setConfig(array('ssltransport' => 'ssl'));
  107. $this->setAuth($uname, $pass);
  108. }
  109. /**
  110. * Set client username and password
  111. *
  112. * @param string $uname Client user name
  113. * @param string $pass Client password
  114. * @return Zend_Service_Delicious Provides a fluent interface
  115. */
  116. public function setAuth($uname, $pass)
  117. {
  118. $this->_authUname = $uname;
  119. $this->_authPass = $pass;
  120. return $this;
  121. }
  122. /**
  123. * Get time of the last update
  124. *
  125. * @throws Zend_Service_Delicious_Exception
  126. * @return Zend_Date
  127. */
  128. public function getLastUpdate()
  129. {
  130. $response = $this->makeRequest(self::PATH_UPDATE);
  131. $rootNode = $response->documentElement;
  132. if ($rootNode && $rootNode->nodeName == 'update') {
  133. /**
  134. * @todo replace strtotime() with Zend_Date equivalent
  135. */
  136. return new Zend_Date(strtotime($rootNode->getAttribute('time')));
  137. } else {
  138. /**
  139. * @see Zend_Service_Delicious_Exception
  140. */
  141. require_once 'Zend/Service/Delicious/Exception.php';
  142. throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!');
  143. }
  144. }
  145. /**
  146. * Get all tags, returning an array with tags as keys and number of corresponding posts as values
  147. *
  148. * @return array list of tags
  149. */
  150. public function getTags()
  151. {
  152. $response = $this->makeRequest(self::PATH_TAGS);
  153. return self::_xmlResponseToArray($response, 'tags', 'tag', 'tag', 'count');
  154. }
  155. /**
  156. * Rename a tag
  157. *
  158. * @param string $old Old tag name
  159. * @param string $new New tag name
  160. * @return Zend_Service_Delicious Provides a fluent interface
  161. */
  162. public function renameTag($old, $new)
  163. {
  164. $response = $this->makeRequest(self::PATH_TAG_RENAME, array('old' => $old, 'new' => $new));
  165. self::_evalXmlResult($response);
  166. return $this;
  167. }
  168. /**
  169. * Get all bundles, returning an array with bundles as keys and array of tags as values
  170. *
  171. * @return array list of bundles
  172. */
  173. public function getBundles()
  174. {
  175. $response = $this->makeRequest(self::PATH_BUNDLES);
  176. $bundles = self::_xmlResponseToArray($response, 'bundles', 'bundle', 'name', 'tags');
  177. foreach ($bundles as &$tags) {
  178. $tags = explode(' ', $tags);
  179. }
  180. return $bundles;
  181. }
  182. /**
  183. * Adds a new bundle
  184. *
  185. * @param string $bundle Name of new bundle
  186. * @param array $tags Array of tags
  187. * @return Zend_Service_Delicious Provides a fluent interface
  188. */
  189. public function addBundle($bundle, array $tags)
  190. {
  191. $tags = implode(' ', (array) $tags);
  192. $response = $this->makeRequest(self::PATH_BUNDLE_ADD, array('bundle' => $bundle, 'tags' => $tags));
  193. self::_evalXmlResult($response);
  194. return $this;
  195. }
  196. /**
  197. * Delete a bundle
  198. *
  199. * @param string $bundle Name of bundle to be deleted
  200. * @return Zend_Service_Delicious Provides a fluent interface
  201. */
  202. public function deleteBundle($bundle)
  203. {
  204. $response = $this->makeRequest(self::PATH_BUNDLE_DELETE, array('bundle' => $bundle));
  205. self::_evalXmlResult($response);
  206. return $this;
  207. }
  208. /**
  209. * Delete a post
  210. *
  211. * @param string $url URL of post to be deleted
  212. * @return Zend_Service_Delicious Provides a fluent interface
  213. */
  214. public function deletePost($url)
  215. {
  216. $response = $this->makeRequest(self::PATH_POST_DELETE, array('url' => $url));
  217. self::_evalXmlResult($response);
  218. return $this;
  219. }
  220. /**
  221. * Get number of posts by date
  222. *
  223. * Returns array where keys are dates and values are numbers of posts
  224. *
  225. * @param string $tag Optional filtering by tag
  226. * @return array list of dates
  227. */
  228. public function getDates($tag = null)
  229. {
  230. $parms = array();
  231. if ($tag) {
  232. $parms['tag'] = $tag;
  233. }
  234. $response = $this->makeRequest(self::PATH_DATES, $parms);
  235. return self::_xmlResponseToArray($response, 'dates', 'date', 'date', 'count');
  236. }
  237. /**
  238. * Get posts matching the arguments
  239. *
  240. * If no date or url is given, most recent date will be used
  241. *
  242. * @param string $tag Optional filtering by tag
  243. * @param Zend_Date $dt Optional filtering by date
  244. * @param string $url Optional filtering by url
  245. * @throws Zend_Service_Delicious_Exception
  246. * @return Zend_Service_Delicious_PostList
  247. */
  248. public function getPosts($tag = null, Zend_Date $dt = null, $url = null)
  249. {
  250. $parms = array();
  251. if ($tag) {
  252. $parms['tag'] = $tag;
  253. }
  254. if ($url) {
  255. $parms['url'] = $url;
  256. }
  257. if ($dt) {
  258. $parms['dt'] = $dt->get('Y-m-d\TH:i:s\Z');
  259. }
  260. $response = $this->makeRequest(self::PATH_POSTS_GET, $parms);
  261. return $this->_parseXmlPostList($response);
  262. }
  263. /**
  264. * Get all posts
  265. *
  266. * @param string $tag Optional filtering by tag
  267. * @return Zend_Service_Delicious_PostList
  268. */
  269. public function getAllPosts($tag = null)
  270. {
  271. $parms = array();
  272. if ($tag) {
  273. $parms['tag'] = $tag;
  274. }
  275. $response = $this->makeRequest(self::PATH_POSTS_ALL, $parms);
  276. return $this->_parseXmlPostList($response);
  277. }
  278. /**
  279. * Get recent posts
  280. *
  281. * @param string $tag Optional filtering by tag
  282. * @param string $count Maximum number of posts to be returned (default 15)
  283. * @return Zend_Service_Delicious_PostList
  284. */
  285. public function getRecentPosts($tag = null, $count = 15)
  286. {
  287. $parms = array();
  288. if ($tag) {
  289. $parms['tag'] = $tag;
  290. }
  291. if ($count) {
  292. $parms['count'] = $count;
  293. }
  294. $response = $this->makeRequest(self::PATH_POSTS_RECENT, $parms);
  295. return $this->_parseXmlPostList($response);
  296. }
  297. /**
  298. * Create new post
  299. *
  300. * @return Zend_Service_Delicious_Post
  301. */
  302. public function createNewPost($title, $url)
  303. {
  304. return new Zend_Service_Delicious_Post($this, array('title' => $title, 'url' => $url));
  305. }
  306. /**
  307. * Get posts of a user
  308. *
  309. * @param string $user Owner of the posts
  310. * @param int $count Number of posts (default 15, max. 100)
  311. * @param string $tag Optional filtering by tag
  312. * @return Zend_Service_Delicious_PostList
  313. */
  314. public function getUserPosts($user, $count = null, $tag = null)
  315. {
  316. $parms = array();
  317. if ($count) {
  318. $parms['count'] = $count;
  319. }
  320. $path = sprintf(self::JSON_POSTS, $user, $tag);
  321. $res = $this->makeRequest($path, $parms, 'json');
  322. return new Zend_Service_Delicious_PostList($this, $res);
  323. }
  324. /**
  325. * Get tags of a user
  326. *
  327. * Returned array has tags as keys and number of posts as values
  328. *
  329. * @param string $user Owner of the posts
  330. * @param int $atleast Include only tags for which there are at least ### number of posts
  331. * @param int $count Number of tags to get (default all)
  332. * @param string $sort Order of returned tags ('alpha' || 'count')
  333. * @return array
  334. */
  335. public function getUserTags($user, $atleast = null, $count = null, $sort = 'alpha')
  336. {
  337. $parms = array();
  338. if ($atleast) {
  339. $parms['atleast'] = $atleast;
  340. }
  341. if ($count) {
  342. $parms['count'] = $count;
  343. }
  344. if ($sort) {
  345. $parms['sort'] = $sort;
  346. }
  347. $path = sprintf(self::JSON_TAGS, $user);
  348. return $this->makeRequest($path, $parms, 'json');
  349. }
  350. /**
  351. * Get network of a user
  352. *
  353. * @param string $user Owner of the network
  354. * @return array
  355. */
  356. public function getUserNetwork($user)
  357. {
  358. $path = sprintf(self::JSON_NETWORK, $user);
  359. return $this->makeRequest($path, array(), 'json');
  360. }
  361. /**
  362. * Get fans of a user
  363. *
  364. * @param string $user Owner of the fans
  365. * @return array
  366. */
  367. public function getUserFans($user)
  368. {
  369. $path = sprintf(self::JSON_FANS, $user);
  370. return $this->makeRequest($path, array(), 'json');
  371. }
  372. /**
  373. * Get details on a particular bookmarked URL
  374. *
  375. * Returned array contains four elements:
  376. * - hash - md5 hash of URL
  377. * - top_tags - array of tags and their respective usage counts
  378. * - url - URL for which details were returned
  379. * - total_posts - number of users that have bookmarked URL
  380. *
  381. * If URL hasen't been bookmarked null is returned.
  382. *
  383. * @param string $url URL for which to get details
  384. * @return array
  385. */
  386. public function getUrlDetails($url)
  387. {
  388. $parms = array('hash' => md5($url));
  389. $res = $this->makeRequest(self::JSON_URL, $parms, 'json');
  390. if(isset($res[0])) {
  391. return $res[0];
  392. } else {
  393. return null;
  394. }
  395. }
  396. /**
  397. * Handles all GET requests to a web service
  398. *
  399. * @param string $path Path
  400. * @param array $parms Array of GET parameters
  401. * @param string $type Type of a request ("xml"|"json")
  402. * @return mixed decoded response from web service
  403. * @throws Zend_Service_Delicious_Exception
  404. */
  405. public function makeRequest($path, array $parms = array(), $type = 'xml')
  406. {
  407. // if previous request was made less then 1 sec ago
  408. // wait until we can make a new request
  409. $timeDiff = microtime(true) - self::$_lastRequestTime;
  410. if ($timeDiff < 1) {
  411. usleep((1 - $timeDiff) * 1000000);
  412. }
  413. $this->_rest->getHttpClient()->setAuth($this->_authUname, $this->_authPass);
  414. switch ($type) {
  415. case 'xml':
  416. $this->_rest->setUri(self::API_URI);
  417. break;
  418. case 'json':
  419. $parms['raw'] = true;
  420. $this->_rest->setUri(self::JSON_URI);
  421. break;
  422. default:
  423. /**
  424. * @see Zend_Service_Delicious_Exception
  425. */
  426. require_once 'Zend/Service/Delicious/Exception.php';
  427. throw new Zend_Service_Delicious_Exception('Unknown request type');
  428. }
  429. self::$_lastRequestTime = microtime(true);
  430. $response = $this->_rest->restGet($path, $parms);
  431. if (!$response->isSuccessful()) {
  432. /**
  433. * @see Zend_Service_Delicious_Exception
  434. */
  435. require_once 'Zend/Service/Delicious/Exception.php';
  436. throw new Zend_Service_Delicious_Exception("Http client reported an error: '{$response->getMessage()}'");
  437. }
  438. $responseBody = $response->getBody();
  439. switch ($type) {
  440. case 'xml':
  441. $dom = new DOMDocument() ;
  442. if (!@$dom->loadXML($responseBody)) {
  443. /**
  444. * @see Zend_Service_Delicious_Exception
  445. */
  446. require_once 'Zend/Service/Delicious/Exception.php';
  447. throw new Zend_Service_Delicious_Exception('XML Error');
  448. }
  449. return $dom;
  450. case 'json':
  451. return Zend_Json_Decoder::decode($responseBody);
  452. }
  453. }
  454. /**
  455. * Transform XML string to array
  456. *
  457. * @param DOMDocument $response
  458. * @param string $root Name of root tag
  459. * @param string $child Name of children tags
  460. * @param string $attKey Attribute of child tag to be used as a key
  461. * @param string $attValue Attribute of child tag to be used as a value
  462. * @return array
  463. * @throws Zend_Service_Delicious_Exception
  464. */
  465. private static function _xmlResponseToArray(DOMDocument $response, $root, $child, $attKey, $attValue)
  466. {
  467. $rootNode = $response->documentElement;
  468. $arrOut = array();
  469. if ($rootNode->nodeName == $root) {
  470. $childNodes = $rootNode->childNodes;
  471. for ($i = 0; $i < $childNodes->length; $i++) {
  472. $currentNode = $childNodes->item($i);
  473. if ($currentNode->nodeName == $child) {
  474. $arrOut[$currentNode->getAttribute($attKey)] = $currentNode->getAttribute($attValue);
  475. }
  476. }
  477. } else {
  478. /**
  479. * @see Zend_Service_Delicious_Exception
  480. */
  481. require_once 'Zend/Service/Delicious/Exception.php';
  482. throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!');
  483. }
  484. return $arrOut;
  485. }
  486. /**
  487. * Constructs Zend_Service_Delicious_PostList from XML response
  488. *
  489. * @param DOMDocument $response
  490. * @return Zend_Service_Delicious_PostList
  491. * @throws Zend_Service_Delicious_Exception
  492. */
  493. private function _parseXmlPostList(DOMDocument $response)
  494. {
  495. $rootNode = $response->documentElement;
  496. if ($rootNode->nodeName == 'posts') {
  497. return new Zend_Service_Delicious_PostList($this, $rootNode->childNodes);
  498. } else {
  499. /**
  500. * @see Zend_Service_Delicious_Exception
  501. */
  502. require_once 'Zend/Service/Delicious/Exception.php';
  503. throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!');
  504. }
  505. }
  506. /**
  507. * Evaluates XML response
  508. *
  509. * @param DOMDocument $response
  510. * @return void
  511. * @throws Zend_Service_Delicious_Exception
  512. */
  513. private static function _evalXmlResult(DOMDocument $response)
  514. {
  515. $rootNode = $response->documentElement;
  516. if ($rootNode && $rootNode->nodeName == 'result') {
  517. if ($rootNode->hasAttribute('code')) {
  518. $strResponse = $rootNode->getAttribute('code');
  519. } else {
  520. $strResponse = $rootNode->nodeValue;
  521. }
  522. if ($strResponse != 'done' && $strResponse != 'ok') {
  523. /**
  524. * @see Zend_Service_Delicious_Exception
  525. */
  526. require_once 'Zend/Service/Delicious/Exception.php';
  527. throw new Zend_Service_Delicious_Exception("del.icio.us web service: '{$strResponse}'");
  528. }
  529. } else {
  530. /**
  531. * @see Zend_Service_Delicious_Exception
  532. */
  533. require_once 'Zend/Service/Delicious/Exception.php';
  534. throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!');
  535. }
  536. }
  537. }