File indexing completed on 2025-01-26 05:25:30
0001 <?php 0002 0003 /** 0004 * Zend Framework 0005 * 0006 * LICENSE 0007 * 0008 * This source file is subject to the new BSD license that is bundled 0009 * with this package in the file LICENSE.txt. 0010 * It is also available through the world-wide-web at this URL: 0011 * http://framework.zend.com/license/new-bsd 0012 * If you did not receive a copy of the license and are unable to 0013 * obtain it through the world-wide-web, please send an email 0014 * to license@zend.com so we can send you a copy immediately. 0015 * 0016 * @category Zend 0017 * @package Zend_Service 0018 * @subpackage Delicious 0019 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0020 * @license http://framework.zend.com/license/new-bsd New BSD License 0021 * @version $Id$ 0022 */ 0023 0024 0025 /** 0026 * @see Zend_Rest_Client 0027 */ 0028 // require_once 'Zend/Rest/Client.php'; 0029 0030 /** 0031 * @see Zend_Json_Decoder 0032 */ 0033 // require_once 'Zend/Json/Decoder.php'; 0034 0035 /** 0036 * @see Zend_Service_Delicious_SimplePost 0037 */ 0038 // require_once 'Zend/Service/Delicious/SimplePost.php'; 0039 0040 /** 0041 * @see Zend_Service_Delicious_Post 0042 */ 0043 // require_once 'Zend/Service/Delicious/Post.php'; 0044 0045 /** 0046 * @see Zend_Service_Delicious_PostList 0047 */ 0048 // require_once 'Zend/Service/Delicious/PostList.php'; 0049 0050 /** @see Zend_Xml_Security */ 0051 // require_once 'Zend/Xml/Security.php'; 0052 0053 /** 0054 * Zend_Service_Delicious is a concrete implementation of the del.icio.us web service 0055 * 0056 * @category Zend 0057 * @package Zend_Service 0058 * @subpackage Delicious 0059 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0060 * @license http://framework.zend.com/license/new-bsd New BSD License 0061 */ 0062 class Zend_Service_Delicious 0063 { 0064 const API_URI = 'https://api.del.icio.us'; 0065 0066 const PATH_UPDATE = '/v1/posts/update'; 0067 const PATH_TAGS = '/v1/tags/get'; 0068 const PATH_TAG_RENAME = '/v1/tags/rename'; 0069 const PATH_BUNDLES = '/v1/tags/bundles/all'; 0070 const PATH_BUNDLE_DELETE = '/v1/tags/bundles/delete'; 0071 const PATH_BUNDLE_ADD = '/v1/tags/bundles/set'; 0072 const PATH_DATES = '/v1/posts/dates'; 0073 const PATH_POST_DELETE = '/v1/posts/delete'; 0074 const PATH_POSTS_GET = '/v1/posts/get'; 0075 const PATH_POSTS_ALL = '/v1/posts/all'; 0076 const PATH_POSTS_ADD = '/v1/posts/add'; 0077 const PATH_POSTS_RECENT = '/v1/posts/recent'; 0078 0079 const JSON_URI = 'http://del.icio.us'; 0080 const JSON_POSTS = '/feeds/json/%s/%s'; 0081 const JSON_TAGS = '/feeds/json/tags/%s'; 0082 const JSON_NETWORK = '/feeds/json/network/%s'; 0083 const JSON_FANS = '/feeds/json/fans/%s'; 0084 const JSON_URL = '/feeds/json/url/data'; 0085 0086 /** 0087 * Zend_Service_Rest instance 0088 * 0089 * @var Zend_Service_Rest 0090 */ 0091 protected $_rest; 0092 0093 /** 0094 * Username 0095 * 0096 * @var string 0097 */ 0098 protected $_authUname; 0099 0100 /** 0101 * Password 0102 * 0103 * @var string 0104 */ 0105 protected $_authPass; 0106 0107 /** 0108 * Microtime of last request 0109 * 0110 * @var float 0111 */ 0112 protected static $_lastRequestTime = 0; 0113 0114 /** 0115 * Constructs a new del.icio.us Web Services Client 0116 * 0117 * @param string $uname Client username 0118 * @param string $pass Client password 0119 * @return void 0120 */ 0121 public function __construct($uname = null, $pass = null) 0122 { 0123 $this->_rest = new Zend_Rest_Client(); 0124 $this->_rest->getHttpClient()->setConfig(array('ssltransport' => 'ssl')); 0125 $this->setAuth($uname, $pass); 0126 } 0127 0128 /** 0129 * Set client username and password 0130 * 0131 * @param string $uname Client user name 0132 * @param string $pass Client password 0133 * @return Zend_Service_Delicious Provides a fluent interface 0134 */ 0135 public function setAuth($uname, $pass) 0136 { 0137 $this->_authUname = $uname; 0138 $this->_authPass = $pass; 0139 0140 return $this; 0141 } 0142 0143 /** 0144 * Get time of the last update 0145 * 0146 * @throws Zend_Service_Delicious_Exception 0147 * @return Zend_Date 0148 */ 0149 public function getLastUpdate() 0150 { 0151 $response = $this->makeRequest(self::PATH_UPDATE); 0152 0153 $rootNode = $response->documentElement; 0154 if ($rootNode && $rootNode->nodeName == 'update') { 0155 /** 0156 * @todo replace strtotime() with Zend_Date equivalent 0157 */ 0158 return new Zend_Date(strtotime($rootNode->getAttribute('time'))); 0159 } else { 0160 /** 0161 * @see Zend_Service_Delicious_Exception 0162 */ 0163 // require_once 'Zend/Service/Delicious/Exception.php'; 0164 throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!'); 0165 } 0166 } 0167 0168 /** 0169 * Get all tags, returning an array with tags as keys and number of corresponding posts as values 0170 * 0171 * @return array list of tags 0172 */ 0173 public function getTags() 0174 { 0175 $response = $this->makeRequest(self::PATH_TAGS); 0176 0177 return self::_xmlResponseToArray($response, 'tags', 'tag', 'tag', 'count'); 0178 } 0179 0180 /** 0181 * Rename a tag 0182 * 0183 * @param string $old Old tag name 0184 * @param string $new New tag name 0185 * @return Zend_Service_Delicious Provides a fluent interface 0186 */ 0187 public function renameTag($old, $new) 0188 { 0189 $response = $this->makeRequest(self::PATH_TAG_RENAME, array('old' => $old, 'new' => $new)); 0190 0191 self::_evalXmlResult($response); 0192 0193 return $this; 0194 } 0195 0196 /** 0197 * Get all bundles, returning an array with bundles as keys and array of tags as values 0198 * 0199 * @return array list of bundles 0200 */ 0201 public function getBundles() 0202 { 0203 $response = $this->makeRequest(self::PATH_BUNDLES); 0204 0205 $bundles = self::_xmlResponseToArray($response, 'bundles', 'bundle', 'name', 'tags'); 0206 foreach ($bundles as &$tags) { 0207 $tags = explode(' ', $tags); 0208 } 0209 return $bundles; 0210 } 0211 0212 /** 0213 * Adds a new bundle 0214 * 0215 * @param string $bundle Name of new bundle 0216 * @param array $tags Array of tags 0217 * @return Zend_Service_Delicious Provides a fluent interface 0218 */ 0219 public function addBundle($bundle, array $tags) 0220 { 0221 $tags = implode(' ', (array) $tags); 0222 $response = $this->makeRequest(self::PATH_BUNDLE_ADD, array('bundle' => $bundle, 'tags' => $tags)); 0223 0224 self::_evalXmlResult($response); 0225 0226 return $this; 0227 } 0228 0229 /** 0230 * Delete a bundle 0231 * 0232 * @param string $bundle Name of bundle to be deleted 0233 * @return Zend_Service_Delicious Provides a fluent interface 0234 */ 0235 public function deleteBundle($bundle) 0236 { 0237 $response = $this->makeRequest(self::PATH_BUNDLE_DELETE, array('bundle' => $bundle)); 0238 0239 self::_evalXmlResult($response); 0240 0241 return $this; 0242 } 0243 0244 /** 0245 * Delete a post 0246 * 0247 * @param string $url URL of post to be deleted 0248 * @return Zend_Service_Delicious Provides a fluent interface 0249 */ 0250 public function deletePost($url) 0251 { 0252 $response = $this->makeRequest(self::PATH_POST_DELETE, array('url' => $url)); 0253 0254 self::_evalXmlResult($response); 0255 0256 return $this; 0257 } 0258 0259 /** 0260 * Get number of posts by date 0261 * 0262 * Returns array where keys are dates and values are numbers of posts 0263 * 0264 * @param string $tag Optional filtering by tag 0265 * @return array list of dates 0266 */ 0267 public function getDates($tag = null) 0268 { 0269 $parms = array(); 0270 if ($tag) { 0271 $parms['tag'] = $tag; 0272 } 0273 0274 $response = $this->makeRequest(self::PATH_DATES, $parms); 0275 0276 return self::_xmlResponseToArray($response, 'dates', 'date', 'date', 'count'); 0277 } 0278 0279 /** 0280 * Get posts matching the arguments 0281 * 0282 * If no date or url is given, most recent date will be used 0283 * 0284 * @param string $tag Optional filtering by tag 0285 * @param Zend_Date $dt Optional filtering by date 0286 * @param string $url Optional filtering by url 0287 * @throws Zend_Service_Delicious_Exception 0288 * @return Zend_Service_Delicious_PostList 0289 */ 0290 public function getPosts($tag = null, Zend_Date $dt = null, $url = null) 0291 { 0292 $parms = array(); 0293 if ($tag) { 0294 $parms['tag'] = $tag; 0295 } 0296 if ($url) { 0297 $parms['url'] = $url; 0298 } 0299 if ($dt) { 0300 $parms['dt'] = $dt->get('Y-m-d\TH:i:s\Z'); 0301 } 0302 0303 $response = $this->makeRequest(self::PATH_POSTS_GET, $parms); 0304 0305 return $this->_parseXmlPostList($response); 0306 } 0307 0308 /** 0309 * Get all posts 0310 * 0311 * @param string $tag Optional filtering by tag 0312 * @return Zend_Service_Delicious_PostList 0313 */ 0314 public function getAllPosts($tag = null) 0315 { 0316 $parms = array(); 0317 if ($tag) { 0318 $parms['tag'] = $tag; 0319 } 0320 0321 $response = $this->makeRequest(self::PATH_POSTS_ALL, $parms); 0322 0323 return $this->_parseXmlPostList($response); 0324 } 0325 0326 /** 0327 * Get recent posts 0328 * 0329 * @param string $tag Optional filtering by tag 0330 * @param string $count Maximum number of posts to be returned (default 15) 0331 * @return Zend_Service_Delicious_PostList 0332 */ 0333 public function getRecentPosts($tag = null, $count = 15) 0334 { 0335 $parms = array(); 0336 if ($tag) { 0337 $parms['tag'] = $tag; 0338 } 0339 if ($count) { 0340 $parms['count'] = $count; 0341 } 0342 0343 $response = $this->makeRequest(self::PATH_POSTS_RECENT, $parms); 0344 0345 return $this->_parseXmlPostList($response); 0346 } 0347 0348 /** 0349 * Create new post 0350 * 0351 * @return Zend_Service_Delicious_Post 0352 */ 0353 public function createNewPost($title, $url) 0354 { 0355 return new Zend_Service_Delicious_Post($this, array('title' => $title, 'url' => $url)); 0356 } 0357 0358 /** 0359 * Get posts of a user 0360 * 0361 * @param string $user Owner of the posts 0362 * @param int $count Number of posts (default 15, max. 100) 0363 * @param string $tag Optional filtering by tag 0364 * @return Zend_Service_Delicious_PostList 0365 */ 0366 public function getUserPosts($user, $count = null, $tag = null) 0367 { 0368 $parms = array(); 0369 if ($count) { 0370 $parms['count'] = $count; 0371 } 0372 0373 $path = sprintf(self::JSON_POSTS, $user, $tag); 0374 $res = $this->makeRequest($path, $parms, 'json'); 0375 0376 return new Zend_Service_Delicious_PostList($this, $res); 0377 } 0378 0379 /** 0380 * Get tags of a user 0381 * 0382 * Returned array has tags as keys and number of posts as values 0383 * 0384 * @param string $user Owner of the posts 0385 * @param int $atleast Include only tags for which there are at least ### number of posts 0386 * @param int $count Number of tags to get (default all) 0387 * @param string $sort Order of returned tags ('alpha' || 'count') 0388 * @return array 0389 */ 0390 public function getUserTags($user, $atleast = null, $count = null, $sort = 'alpha') 0391 { 0392 $parms = array(); 0393 if ($atleast) { 0394 $parms['atleast'] = $atleast; 0395 } 0396 if ($count) { 0397 $parms['count'] = $count; 0398 } 0399 if ($sort) { 0400 $parms['sort'] = $sort; 0401 } 0402 0403 $path = sprintf(self::JSON_TAGS, $user); 0404 0405 return $this->makeRequest($path, $parms, 'json'); 0406 } 0407 0408 /** 0409 * Get network of a user 0410 * 0411 * @param string $user Owner of the network 0412 * @return array 0413 */ 0414 public function getUserNetwork($user) 0415 { 0416 $path = sprintf(self::JSON_NETWORK, $user); 0417 return $this->makeRequest($path, array(), 'json'); 0418 } 0419 0420 /** 0421 * Get fans of a user 0422 * 0423 * @param string $user Owner of the fans 0424 * @return array 0425 */ 0426 public function getUserFans($user) 0427 { 0428 $path = sprintf(self::JSON_FANS, $user); 0429 return $this->makeRequest($path, array(), 'json'); 0430 } 0431 0432 /** 0433 * Get details on a particular bookmarked URL 0434 * 0435 * Returned array contains four elements: 0436 * - hash - md5 hash of URL 0437 * - top_tags - array of tags and their respective usage counts 0438 * - url - URL for which details were returned 0439 * - total_posts - number of users that have bookmarked URL 0440 * 0441 * If URL hasen't been bookmarked null is returned. 0442 * 0443 * @param string $url URL for which to get details 0444 * @return array 0445 */ 0446 public function getUrlDetails($url) 0447 { 0448 $parms = array('hash' => md5($url)); 0449 0450 $res = $this->makeRequest(self::JSON_URL, $parms, 'json'); 0451 0452 if(isset($res[0])) { 0453 return $res[0]; 0454 } else { 0455 return null; 0456 } 0457 } 0458 0459 /** 0460 * Handles all GET requests to a web service 0461 * 0462 * @param string $path Path 0463 * @param array $parms Array of GET parameters 0464 * @param string $type Type of a request ("xml"|"json") 0465 * @return mixed decoded response from web service 0466 * @throws Zend_Service_Delicious_Exception 0467 */ 0468 public function makeRequest($path, array $parms = array(), $type = 'xml') 0469 { 0470 // if previous request was made less then 1 sec ago 0471 // wait until we can make a new request 0472 $timeDiff = microtime(true) - self::$_lastRequestTime; 0473 if ($timeDiff < 1) { 0474 usleep((1 - $timeDiff) * 1000000); 0475 } 0476 0477 $this->_rest->getHttpClient()->setAuth($this->_authUname, $this->_authPass); 0478 0479 switch ($type) { 0480 case 'xml': 0481 $this->_rest->setUri(self::API_URI); 0482 break; 0483 case 'json': 0484 $parms['raw'] = true; 0485 $this->_rest->setUri(self::JSON_URI); 0486 break; 0487 default: 0488 /** 0489 * @see Zend_Service_Delicious_Exception 0490 */ 0491 // require_once 'Zend/Service/Delicious/Exception.php'; 0492 throw new Zend_Service_Delicious_Exception('Unknown request type'); 0493 } 0494 0495 self::$_lastRequestTime = microtime(true); 0496 $response = $this->_rest->restGet($path, $parms); 0497 0498 if (!$response->isSuccessful()) { 0499 /** 0500 * @see Zend_Service_Delicious_Exception 0501 */ 0502 // require_once 'Zend/Service/Delicious/Exception.php'; 0503 throw new Zend_Service_Delicious_Exception("Http client reported an error: '{$response->getMessage()}'"); 0504 } 0505 0506 $responseBody = $response->getBody(); 0507 0508 switch ($type) { 0509 case 'xml': 0510 $dom = new DOMDocument() ; 0511 0512 if (!$dom = @Zend_Xml_Security::scan($responseBody, $dom)) { 0513 /** 0514 * @see Zend_Service_Delicious_Exception 0515 */ 0516 // require_once 'Zend/Service/Delicious/Exception.php'; 0517 throw new Zend_Service_Delicious_Exception('XML Error'); 0518 } 0519 0520 return $dom; 0521 case 'json': 0522 return Zend_Json_Decoder::decode($responseBody); 0523 } 0524 } 0525 0526 /** 0527 * Transform XML string to array 0528 * 0529 * @param DOMDocument $response 0530 * @param string $root Name of root tag 0531 * @param string $child Name of children tags 0532 * @param string $attKey Attribute of child tag to be used as a key 0533 * @param string $attValue Attribute of child tag to be used as a value 0534 * @return array 0535 * @throws Zend_Service_Delicious_Exception 0536 */ 0537 private static function _xmlResponseToArray(DOMDocument $response, $root, $child, $attKey, $attValue) 0538 { 0539 $rootNode = $response->documentElement; 0540 $arrOut = array(); 0541 0542 if ($rootNode->nodeName == $root) { 0543 $childNodes = $rootNode->childNodes; 0544 0545 for ($i = 0; $i < $childNodes->length; $i++) { 0546 $currentNode = $childNodes->item($i); 0547 if ($currentNode->nodeName == $child) { 0548 $arrOut[$currentNode->getAttribute($attKey)] = $currentNode->getAttribute($attValue); 0549 } 0550 } 0551 } else { 0552 /** 0553 * @see Zend_Service_Delicious_Exception 0554 */ 0555 // require_once 'Zend/Service/Delicious/Exception.php'; 0556 throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!'); 0557 } 0558 0559 return $arrOut; 0560 } 0561 0562 /** 0563 * Constructs Zend_Service_Delicious_PostList from XML response 0564 * 0565 * @param DOMDocument $response 0566 * @return Zend_Service_Delicious_PostList 0567 * @throws Zend_Service_Delicious_Exception 0568 */ 0569 private function _parseXmlPostList(DOMDocument $response) 0570 { 0571 $rootNode = $response->documentElement; 0572 0573 if ($rootNode->nodeName == 'posts') { 0574 return new Zend_Service_Delicious_PostList($this, $rootNode->childNodes); 0575 } else { 0576 /** 0577 * @see Zend_Service_Delicious_Exception 0578 */ 0579 // require_once 'Zend/Service/Delicious/Exception.php'; 0580 throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!'); 0581 } 0582 } 0583 0584 /** 0585 * Evaluates XML response 0586 * 0587 * @param DOMDocument $response 0588 * @return void 0589 * @throws Zend_Service_Delicious_Exception 0590 */ 0591 private static function _evalXmlResult(DOMDocument $response) 0592 { 0593 $rootNode = $response->documentElement; 0594 0595 if ($rootNode && $rootNode->nodeName == 'result') { 0596 0597 if ($rootNode->hasAttribute('code')) { 0598 $strResponse = $rootNode->getAttribute('code'); 0599 } else { 0600 $strResponse = $rootNode->nodeValue; 0601 } 0602 0603 if ($strResponse != 'done' && $strResponse != 'ok') { 0604 /** 0605 * @see Zend_Service_Delicious_Exception 0606 */ 0607 // require_once 'Zend/Service/Delicious/Exception.php'; 0608 throw new Zend_Service_Delicious_Exception("del.icio.us web service: '{$strResponse}'"); 0609 } 0610 } else { 0611 /** 0612 * @see Zend_Service_Delicious_Exception 0613 */ 0614 // require_once 'Zend/Service/Delicious/Exception.php'; 0615 throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!'); 0616 } 0617 } 0618 }