File indexing completed on 2024-05-12 06:03:06

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 Flickr
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 /** @see Zend_Xml_Security */
0025 // require_once 'Zend/Xml/Security.php';
0026 
0027 /**
0028  * @category   Zend
0029  * @package    Zend_Service
0030  * @subpackage Flickr
0031  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0032  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0033  */
0034 class Zend_Service_Flickr
0035 {
0036     /**
0037      * Base URI for the REST client
0038      */
0039     const URI_BASE = 'https://www.flickr.com';
0040 
0041     /**
0042      * Your Flickr API key
0043      *
0044      * @var string
0045      */
0046     public $apiKey;
0047 
0048     /**
0049      * Reference to REST client object
0050      *
0051      * @var Zend_Rest_Client
0052      */
0053     protected $_restClient = null;
0054 
0055 
0056     /**
0057      * Performs object initializations
0058      *
0059      *  # Sets up character encoding
0060      *  # Saves the API key
0061      *
0062      * @param  string $apiKey Your Flickr API key
0063      * @return void
0064      */
0065     public function __construct($apiKey)
0066     {
0067         $this->apiKey = (string) $apiKey;
0068     }
0069 
0070 
0071     /**
0072      * Find Flickr photos by tag.
0073      *
0074      * Query options include:
0075      *
0076      *  # per_page:        how many results to return per query
0077      *  # page:            the starting page offset.  first result will be (page - 1) * per_page + 1
0078      *  # tag_mode:        Either 'any' for an OR combination of tags,
0079      *                     or 'all' for an AND combination. Default is 'any'.
0080      *  # min_upload_date: Minimum upload date to search on.  Date should be a unix timestamp.
0081      *  # max_upload_date: Maximum upload date to search on.  Date should be a unix timestamp.
0082      *  # min_taken_date:  Minimum upload date to search on.  Date should be a MySQL datetime.
0083      *  # max_taken_date:  Maximum upload date to search on.  Date should be a MySQL datetime.
0084      *
0085      * @param  string|array $query   A single tag or an array of tags.
0086      * @param  array        $options Additional parameters to refine your query.
0087      * @return Zend_Service_Flickr_ResultSet
0088      * @throws Zend_Service_Exception
0089      */
0090     public function tagSearch($query, array $options = array())
0091     {
0092         static $method = 'flickr.photos.search';
0093         static $defaultOptions = array('per_page' => 10,
0094                                        'page'     => 1,
0095                                        'tag_mode' => 'or',
0096                                        'extras'   => 'license, date_upload, date_taken, owner_name, icon_server');
0097 
0098         $options['tags'] = is_array($query) ? implode(',', $query) : $query;
0099 
0100         $options = $this->_prepareOptions($method, $options, $defaultOptions);
0101 
0102         $this->_validateTagSearch($options);
0103 
0104         // now search for photos
0105         $restClient = $this->getRestClient();
0106         $restClient->getHttpClient()->resetParameters();
0107         $response = $restClient->restGet('/services/rest/', $options);
0108 
0109         if ($response->isError()) {
0110             /**
0111              * @see Zend_Service_Exception
0112              */
0113             // require_once 'Zend/Service/Exception.php';
0114             throw new Zend_Service_Exception('An error occurred sending request. Status code: '
0115                                            . $response->getStatus());
0116         }
0117 
0118         $dom = new DOMDocument();
0119         $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
0120         self::_checkErrors($dom);
0121 
0122         /**
0123          * @see Zend_Service_Flickr_ResultSet
0124          */
0125         // require_once 'Zend/Service/Flickr/ResultSet.php';
0126         return new Zend_Service_Flickr_ResultSet($dom, $this);
0127     }
0128 
0129 
0130     /**
0131      * Finds photos by a user's username or email.
0132      *
0133      * Additional query options include:
0134      *
0135      *  # per_page:        how many results to return per query
0136      *  # page:            the starting page offset.  first result will be (page - 1) * per_page + 1
0137      *  # min_upload_date: Minimum upload date to search on.  Date should be a unix timestamp.
0138      *  # max_upload_date: Maximum upload date to search on.  Date should be a unix timestamp.
0139      *  # min_taken_date:  Minimum upload date to search on.  Date should be a MySQL datetime.
0140      *  # max_taken_date:  Maximum upload date to search on.  Date should be a MySQL datetime.
0141      *
0142      * @param  string $query   username or email
0143      * @param  array  $options Additional parameters to refine your query.
0144      * @return Zend_Service_Flickr_ResultSet
0145      * @throws Zend_Service_Exception
0146      */
0147     public function userSearch($query, array $options = null)
0148     {
0149         static $method = 'flickr.people.getPublicPhotos';
0150         static $defaultOptions = array('per_page' => 10,
0151                                        'page'     => 1,
0152                                        'extras'   => 'license, date_upload, date_taken, owner_name, icon_server');
0153 
0154 
0155         // can't access by username, must get ID first
0156         if (strchr($query, '@')) {
0157             // optimistically hope this is an email
0158             $options['user_id'] = $this->getIdByEmail($query);
0159         } else {
0160             // we can safely ignore this exception here
0161             $options['user_id'] = $this->getIdByUsername($query);
0162         }
0163 
0164         $options = $this->_prepareOptions($method, $options, $defaultOptions);
0165         $this->_validateUserSearch($options);
0166 
0167         // now search for photos
0168         $restClient = $this->getRestClient();
0169         $restClient->getHttpClient()->resetParameters();
0170         $response = $restClient->restGet('/services/rest/', $options);
0171 
0172         if ($response->isError()) {
0173             /**
0174              * @see Zend_Service_Exception
0175              */
0176             // require_once 'Zend/Service/Exception.php';
0177             throw new Zend_Service_Exception('An error occurred sending request. Status code: '
0178                                            . $response->getStatus());
0179         }
0180 
0181         $dom = new DOMDocument();
0182         $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
0183         self::_checkErrors($dom);
0184 
0185         /**
0186          * @see Zend_Service_Flickr_ResultSet
0187          */
0188         // require_once 'Zend/Service/Flickr/ResultSet.php';
0189         return new Zend_Service_Flickr_ResultSet($dom, $this);
0190     }
0191 
0192     /**
0193      * Finds photos in a group's pool.
0194      *
0195      * @param  string $query   group id
0196      * @param  array  $options Additional parameters to refine your query.
0197      * @return Zend_Service_Flickr_ResultSet
0198      * @throws Zend_Service_Exception
0199      */
0200     public function groupPoolGetPhotos($query, array $options = array())
0201     {
0202         static $method = 'flickr.groups.pools.getPhotos';
0203         static $defaultOptions = array('per_page' => 10,
0204                                        'page'     => 1,
0205                                        'extras'   => 'license, date_upload, date_taken, owner_name, icon_server');
0206 
0207         if (empty($query) || !is_string($query)) {
0208             /**
0209              * @see Zend_Service_Exception
0210              */
0211             // require_once 'Zend/Service/Exception.php';
0212             throw new Zend_Service_Exception('You must supply a group id');
0213         }
0214 
0215         $options['group_id'] = $query;
0216 
0217         $options = $this->_prepareOptions($method, $options, $defaultOptions);
0218 
0219         $this->_validateGroupPoolGetPhotos($options);
0220 
0221         // now search for photos
0222         $restClient = $this->getRestClient();
0223         $restClient->getHttpClient()->resetParameters();
0224         $response = $restClient->restGet('/services/rest/', $options);
0225 
0226         if ($response->isError()) {
0227             /**
0228             * @see Zend_Service_Exception
0229             */
0230             // require_once 'Zend/Service/Exception.php';
0231             throw new Zend_Service_Exception('An error occurred sending request. Status code: '
0232                                            . $response->getStatus());
0233         }
0234 
0235         $dom = new DOMDocument();
0236         $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
0237         self::_checkErrors($dom);
0238 
0239         /**
0240         * @see Zend_Service_Flickr_ResultSet
0241         */
0242         // require_once 'Zend/Service/Flickr/ResultSet.php';
0243         return new Zend_Service_Flickr_ResultSet($dom, $this);
0244     }
0245 
0246 
0247 
0248     /**
0249      * Utility function to find Flickr User IDs for usernames.
0250      *
0251      * (You can only find a user's photo with their NSID.)
0252      *
0253      * @param  string $username the username
0254      * @return string the NSID (userid)
0255      * @throws Zend_Service_Exception
0256      */
0257     public function getIdByUsername($username)
0258     {
0259         static $method = 'flickr.people.findByUsername';
0260 
0261         $options = array('api_key' => $this->apiKey, 'method' => $method, 'username' => (string) $username);
0262 
0263         if (empty($username)) {
0264             /**
0265              * @see Zend_Service_Exception
0266              */
0267             // require_once 'Zend/Service/Exception.php';
0268             throw new Zend_Service_Exception('You must supply a username');
0269         }
0270 
0271         $restClient = $this->getRestClient();
0272         $restClient->getHttpClient()->resetParameters();
0273         $response = $restClient->restGet('/services/rest/', $options);
0274 
0275         if ($response->isError()) {
0276             /**
0277              * @see Zend_Service_Exception
0278              */
0279             // require_once 'Zend/Service/Exception.php';
0280             throw new Zend_Service_Exception('An error occurred sending request. Status code: '
0281                                            . $response->getStatus());
0282         }
0283 
0284         $dom = new DOMDocument();
0285         $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
0286         self::_checkErrors($dom);
0287         $xpath = new DOMXPath($dom);
0288         return (string) $xpath->query('//user')->item(0)->getAttribute('id');
0289     }
0290 
0291 
0292     /**
0293      * Utility function to find Flickr User IDs for emails.
0294      *
0295      * (You can only find a user's photo with their NSID.)
0296      *
0297      * @param  string $email the email
0298      * @return string the NSID (userid)
0299      * @throws Zend_Service_Exception
0300      */
0301     public function getIdByEmail($email)
0302     {
0303         static $method = 'flickr.people.findByEmail';
0304 
0305         if (empty($email)) {
0306             /**
0307              * @see Zend_Service_Exception
0308              */
0309             // require_once 'Zend/Service/Exception.php';
0310             throw new Zend_Service_Exception('You must supply an e-mail address');
0311         }
0312 
0313         $options = array('api_key' => $this->apiKey, 'method' => $method, 'find_email' => (string) $email);
0314 
0315         $restClient = $this->getRestClient();
0316         $restClient->getHttpClient()->resetParameters();
0317         $response = $restClient->restGet('/services/rest/', $options);
0318 
0319         if ($response->isError()) {
0320             /**
0321              * @see Zend_Service_Exception
0322              */
0323             // require_once 'Zend/Service/Exception.php';
0324             throw new Zend_Service_Exception('An error occurred sending request. Status code: '
0325                                            . $response->getStatus());
0326         }
0327 
0328         $dom = new DOMDocument();
0329         $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
0330         self::_checkErrors($dom);
0331         $xpath = new DOMXPath($dom);
0332         return (string) $xpath->query('//user')->item(0)->getAttribute('id');
0333     }
0334 
0335 
0336     /**
0337      * Returns Flickr photo details by for the given photo ID
0338      *
0339      * @param  string $id the NSID
0340      * @return array of Zend_Service_Flickr_Image, details for the specified image
0341      * @throws Zend_Service_Exception
0342      */
0343     public function getImageDetails($id)
0344     {
0345         static $method = 'flickr.photos.getSizes';
0346 
0347         if (empty($id)) {
0348             /**
0349              * @see Zend_Service_Exception
0350              */
0351             // require_once 'Zend/Service/Exception.php';
0352             throw new Zend_Service_Exception('You must supply a photo ID');
0353         }
0354 
0355         $options = array('api_key' => $this->apiKey, 'method' => $method, 'photo_id' => $id);
0356 
0357         $restClient = $this->getRestClient();
0358         $restClient->getHttpClient()->resetParameters();
0359         $response = $restClient->restGet('/services/rest/', $options);
0360 
0361         $dom = new DOMDocument();
0362         $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
0363         $xpath = new DOMXPath($dom);
0364         self::_checkErrors($dom);
0365         $retval = array();
0366         /**
0367          * @see Zend_Service_Flickr_Image
0368          */
0369         // require_once 'Zend/Service/Flickr/Image.php';
0370         foreach ($xpath->query('//size') as $size) {
0371             $label = (string) $size->getAttribute('label');
0372             $retval[$label] = new Zend_Service_Flickr_Image($size);
0373         }
0374 
0375         return $retval;
0376     }
0377 
0378 
0379     /**
0380      * Returns a reference to the REST client, instantiating it if necessary
0381      *
0382      * @return Zend_Rest_Client
0383      */
0384     public function getRestClient()
0385     {
0386         if (null === $this->_restClient) {
0387             /**
0388              * @see Zend_Rest_Client
0389              */
0390             // require_once 'Zend/Rest/Client.php';
0391             $this->_restClient = new Zend_Rest_Client(self::URI_BASE);
0392         }
0393 
0394         return $this->_restClient;
0395     }
0396 
0397 
0398     /**
0399      * Validate User Search Options
0400      *
0401      * @param  array $options
0402      * @return void
0403      * @throws Zend_Service_Exception
0404      */
0405     protected function _validateUserSearch(array $options)
0406     {
0407         $validOptions = array('api_key', 'method', 'user_id', 'per_page', 'page', 'extras', 'min_upload_date',
0408                               'min_taken_date', 'max_upload_date', 'max_taken_date', 'safe_search');
0409 
0410         $this->_compareOptions($options, $validOptions);
0411 
0412         /**
0413          * @see Zend_Validate_Between
0414          */
0415         // require_once 'Zend/Validate/Between.php';
0416         $between = new Zend_Validate_Between(1, 500, true);
0417         if (!$between->isValid($options['per_page'])) {
0418             /**
0419              * @see Zend_Service_Exception
0420              */
0421             // require_once 'Zend/Service/Exception.php';
0422             throw new Zend_Service_Exception($options['per_page'] . ' is not valid for the "per_page" option');
0423         }
0424 
0425         /**
0426          * @see Zend_Validate_Int
0427          */
0428         // require_once 'Zend/Validate/Int.php';
0429         $int = new Zend_Validate_Int();
0430         if (!$int->isValid($options['page'])) {
0431             /**
0432              * @see Zend_Service_Exception
0433              */
0434             // require_once 'Zend/Service/Exception.php';
0435             throw new Zend_Service_Exception($options['page'] . ' is not valid for the "page" option');
0436         }
0437 
0438         // validate extras, which are delivered in csv format
0439         if ($options['extras']) {
0440             $extras = explode(',', $options['extras']);
0441             $validExtras = array('license', 'date_upload', 'date_taken', 'owner_name', 'icon_server');
0442             foreach($extras as $extra) {
0443                 /**
0444                  * @todo The following does not do anything [yet], so it is commented out.
0445                  */
0446                 //in_array(trim($extra), $validExtras);
0447             }
0448         }
0449     }
0450 
0451 
0452     /**
0453      * Validate Tag Search Options
0454      *
0455      * @param  array $options
0456      * @return void
0457      * @throws Zend_Service_Exception
0458      */
0459     protected function _validateTagSearch(array $options)
0460     {
0461         $validOptions = array('method', 'api_key', 'user_id', 'tags', 'tag_mode', 'text', 'min_upload_date',
0462                               'max_upload_date', 'min_taken_date', 'max_taken_date', 'license', 'sort',
0463                               'privacy_filter', 'bbox', 'accuracy', 'safe_search', 'content_type', 'machine_tags',
0464                               'machine_tag_mode', 'group_id', 'contacts', 'woe_id', 'place_id', 'media', 'has_geo',
0465                               'geo_context', 'lat', 'lon', 'radius', 'radius_units', 'is_commons', 'is_gallery',
0466                               'extras', 'per_page', 'page');
0467 
0468         $this->_compareOptions($options, $validOptions);
0469 
0470         /**
0471          * @see Zend_Validate_Between
0472          */
0473         // require_once 'Zend/Validate/Between.php';
0474         $between = new Zend_Validate_Between(1, 500, true);
0475         if (!$between->isValid($options['per_page'])) {
0476             /**
0477              * @see Zend_Service_Exception
0478              */
0479             // require_once 'Zend/Service/Exception.php';
0480             throw new Zend_Service_Exception($options['per_page'] . ' is not valid for the "per_page" option');
0481         }
0482 
0483         /**
0484          * @see Zend_Validate_Int
0485          */
0486         // require_once 'Zend/Validate/Int.php';
0487         $int = new Zend_Validate_Int();
0488         if (!$int->isValid($options['page'])) {
0489             /**
0490              * @see Zend_Service_Exception
0491              */
0492             // require_once 'Zend/Service/Exception.php';
0493             throw new Zend_Service_Exception($options['page'] . ' is not valid for the "page" option');
0494         }
0495 
0496         // validate extras, which are delivered in csv format
0497         if ($options['extras']) {
0498             $extras = explode(',', $options['extras']);
0499             $validExtras = array('license', 'date_upload', 'date_taken', 'owner_name', 'icon_server');
0500             foreach($extras as $extra) {
0501                 /**
0502                  * @todo The following does not do anything [yet], so it is commented out.
0503                  */
0504                 //in_array(trim($extra), $validExtras);
0505             }
0506         }
0507 
0508     }
0509 
0510 
0511     /**
0512     * Validate Group Search Options
0513     *
0514     * @param  array $options
0515     * @throws Zend_Service_Exception
0516     * @return void
0517     */
0518     protected function _validateGroupPoolGetPhotos(array $options)
0519     {
0520         $validOptions = array('api_key', 'tags', 'method', 'group_id', 'per_page', 'page', 'extras', 'user_id');
0521 
0522         $this->_compareOptions($options, $validOptions);
0523 
0524         /**
0525         * @see Zend_Validate_Between
0526         */
0527         // require_once 'Zend/Validate/Between.php';
0528         $between = new Zend_Validate_Between(1, 500, true);
0529         if (!$between->isValid($options['per_page'])) {
0530             /**
0531             * @see Zend_Service_Exception
0532             */
0533             // require_once 'Zend/Service/Exception.php';
0534             throw new Zend_Service_Exception($options['per_page'] . ' is not valid for the "per_page" option');
0535         }
0536 
0537         /**
0538         * @see Zend_Validate_Int
0539         */
0540         // require_once 'Zend/Validate/Int.php';
0541         $int = new Zend_Validate_Int();
0542 
0543         if (!$int->isValid($options['page'])) {
0544             /**
0545             * @see Zend_Service_Exception
0546             */
0547             // require_once 'Zend/Service/Exception.php';
0548             throw new Zend_Service_Exception($options['page'] . ' is not valid for the "page" option');
0549         }
0550 
0551         // validate extras, which are delivered in csv format
0552         if (isset($options['extras'])) {
0553             $extras = explode(',', $options['extras']);
0554             $validExtras = array('license', 'date_upload', 'date_taken', 'owner_name', 'icon_server');
0555             foreach($extras as $extra) {
0556                 /**
0557                 * @todo The following does not do anything [yet], so it is commented out.
0558                 */
0559                 //in_array(trim($extra), $validExtras);
0560             }
0561         }
0562     }
0563 
0564 
0565     /**
0566      * Throws an exception if and only if the response status indicates a failure
0567      *
0568      * @param  DOMDocument $dom
0569      * @return void
0570      * @throws Zend_Service_Exception
0571      */
0572     protected static function _checkErrors(DOMDocument $dom)
0573     {
0574         if ($dom->documentElement->getAttribute('stat') === 'fail') {
0575             $xpath = new DOMXPath($dom);
0576             $err = $xpath->query('//err')->item(0);
0577             /**
0578              * @see Zend_Service_Exception
0579              */
0580             // require_once 'Zend/Service/Exception.php';
0581             throw new Zend_Service_Exception('Search failed due to error: ' . $err->getAttribute('msg')
0582                                            . ' (error #' . $err->getAttribute('code') . ')');
0583         }
0584     }
0585 
0586 
0587     /**
0588      * Prepare options for the request
0589      *
0590      * @param  string $method         Flickr Method to call
0591      * @param  array  $options        User Options
0592      * @param  array  $defaultOptions Default Options
0593      * @return array Merged array of user and default/required options
0594      */
0595     protected function _prepareOptions($method, array $options, array $defaultOptions)
0596     {
0597         $options['method']  = (string) $method;
0598         $options['api_key'] = $this->apiKey;
0599 
0600         return array_merge($defaultOptions, $options);
0601     }
0602 
0603 
0604     /**
0605      * Throws an exception if and only if any user options are invalid
0606      *
0607      * @param  array $options      User options
0608      * @param  array $validOptions Valid options
0609      * @return void
0610      * @throws Zend_Service_Exception
0611      */
0612     protected function _compareOptions(array $options, array $validOptions)
0613     {
0614         $difference = array_diff(array_keys($options), $validOptions);
0615         if ($difference) {
0616             /**
0617              * @see Zend_Service_Exception
0618              */
0619             // require_once 'Zend/Service/Exception.php';
0620             throw new Zend_Service_Exception('The following parameters are invalid: ' . implode(',', $difference));
0621         }
0622     }
0623 }
0624