8
* This source file is subject to the new BSD license that is bundled
9
* with this package in the file LICENSE.txt.
10
* It is also available through the world-wide-web at this URL:
11
* http://framework.zend.com/license/new-bsd
12
* If you did not receive a copy of the license and are unable to
13
* obtain it through the world-wide-web, please send an email
14
* to license@zend.com so we can send you a copy immediately.
17
* @package Zend_Service
19
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
20
* @license http://framework.zend.com/license/new-bsd New BSD License
21
* @version $Id: Flickr.php 8733 2008-03-10 15:56:48Z jokke $
27
* @package Zend_Service
29
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
30
* @license http://framework.zend.com/license/new-bsd New BSD License
32
class Zend_Service_Flickr
35
* Base URI for the REST client
37
const URI_BASE = 'http://www.flickr.com';
47
* Reference to REST client object
49
* @var Zend_Rest_Client
51
protected $_restClient = null;
55
* Performs object initializations
57
* # Sets up character encoding
60
* @param string $apiKey Your Flickr API key
63
public function __construct($apiKey)
65
iconv_set_encoding('output_encoding', 'UTF-8');
66
iconv_set_encoding('input_encoding', 'UTF-8');
67
iconv_set_encoding('internal_encoding', 'UTF-8');
69
$this->apiKey = (string) $apiKey;
74
* Find Flickr photos by tag.
76
* Query options include:
78
* # per_page: how many results to return per query
79
* # page: the starting page offset. first result will be (page - 1) * per_page + 1
80
* # tag_mode: Either 'any' for an OR combination of tags,
81
* or 'all' for an AND combination. Default is 'any'.
82
* # min_upload_date: Minimum upload date to search on. Date should be a unix timestamp.
83
* # max_upload_date: Maximum upload date to search on. Date should be a unix timestamp.
84
* # min_taken_date: Minimum upload date to search on. Date should be a MySQL datetime.
85
* # max_taken_date: Maximum upload date to search on. Date should be a MySQL datetime.
87
* @param string|array $query A single tag or an array of tags.
88
* @param array $options Additional parameters to refine your query.
89
* @return Zend_Service_Flickr_ResultSet
90
* @throws Zend_Service_Exception
92
public function tagSearch($query, array $options = array())
94
static $method = 'flickr.photos.search';
95
static $defaultOptions = array('per_page' => 10,
98
'extras' => 'license, date_upload, date_taken, owner_name, icon_server');
100
$options['tags'] = is_array($query) ? implode(',', $query) : $query;
102
$options = $this->_prepareOptions($method, $options, $defaultOptions);
104
$this->_validateTagSearch($options);
106
// now search for photos
107
$restClient = $this->getRestClient();
108
$restClient->getHttpClient()->resetParameters();
109
$response = $restClient->restGet('/services/rest/', $options);
111
if ($response->isError()) {
113
* @see Zend_Service_Exception
115
require_once 'Zend/Service/Exception.php';
116
throw new Zend_Service_Exception('An error occurred sending request. Status code: '
117
. $response->getStatus());
120
$dom = new DOMDocument();
121
$dom->loadXML($response->getBody());
123
self::_checkErrors($dom);
126
* @see Zend_Service_Flickr_ResultSet
128
require_once 'Zend/Service/Flickr/ResultSet.php';
129
return new Zend_Service_Flickr_ResultSet($dom, $this);
134
* Finds photos by a user's username or email.
136
* Additional query options include:
138
* # per_page: how many results to return per query
139
* # page: the starting page offset. first result will be (page - 1) * per_page + 1
140
* # min_upload_date: Minimum upload date to search on. Date should be a unix timestamp.
141
* # max_upload_date: Maximum upload date to search on. Date should be a unix timestamp.
142
* # min_taken_date: Minimum upload date to search on. Date should be a MySQL datetime.
143
* # max_taken_date: Maximum upload date to search on. Date should be a MySQL datetime.
145
* @param string $query username or email
146
* @param array $options Additional parameters to refine your query.
147
* @return Zend_Service_Flickr_ResultSet
148
* @throws Zend_Service_Exception
150
public function userSearch($query, array $options = null)
152
static $method = 'flickr.people.getPublicPhotos';
153
static $defaultOptions = array('per_page' => 10,
155
'extras' => 'license, date_upload, date_taken, owner_name, icon_server');
158
// can't access by username, must get ID first
159
if (strchr($query, '@')) {
160
// optimistically hope this is an email
161
$options['user_id'] = $this->getIdByEmail($query);
163
// we can safely ignore this exception here
164
$options['user_id'] = $this->getIdByUsername($query);
167
$options = $this->_prepareOptions($method, $options, $defaultOptions);
168
$this->_validateUserSearch($options);
170
// now search for photos
171
$restClient = $this->getRestClient();
172
$restClient->getHttpClient()->resetParameters();
173
$response = $restClient->restGet('/services/rest/', $options);
175
if ($response->isError()) {
177
* @see Zend_Service_Exception
179
require_once 'Zend/Service/Exception.php';
180
throw new Zend_Service_Exception('An error occurred sending request. Status code: '
181
. $response->getStatus());
184
$dom = new DOMDocument();
185
$dom->loadXML($response->getBody());
187
self::_checkErrors($dom);
190
* @see Zend_Service_Flickr_ResultSet
192
require_once 'Zend/Service/Flickr/ResultSet.php';
193
return new Zend_Service_Flickr_ResultSet($dom, $this);
197
* Finds photos in a group's pool.
199
* @param string $query group id
200
* @param array $options Additional parameters to refine your query.
201
* @return Zend_Service_Flickr_ResultSet
202
* @throws Zend_Service_Exception
204
public function groupPoolGetPhotos($query, array $options = array())
206
static $method = 'flickr.groups.pools.getPhotos';
207
static $defaultOptions = array('per_page' => 10,
209
'extras' => 'license, date_upload, date_taken, owner_name, icon_server');
211
if (empty($query) || !is_string($query)) {
213
* @see Zend_Service_Exception
215
require_once 'Zend/Service/Exception.php';
216
throw new Zend_Service_Exception('You must supply a group id');
219
$options['group_id'] = $query;
221
$options = $this->_prepareOptions($method, $options, $defaultOptions);
223
$this->_validateGroupPoolGetPhotos($options);
225
// now search for photos
226
$restClient = $this->getRestClient();
227
$restClient->getHttpClient()->resetParameters();
228
$response = $restClient->restGet('/services/rest/', $options);
230
if ($response->isError()) {
232
* @see Zend_Service_Exception
234
require_once 'Zend/Service/Exception.php';
235
throw new Zend_Service_Exception('An error occurred sending request. Status code: '
236
. $response->getStatus());
239
$dom = new DOMDocument();
240
$dom->loadXML($response->getBody());
242
self::_checkErrors($dom);
245
* @see Zend_Service_Flickr_ResultSet
247
require_once 'Zend/Service/Flickr/ResultSet.php';
248
return new Zend_Service_Flickr_ResultSet($dom, $this);
254
* Utility function to find Flickr User IDs for usernames.
256
* (You can only find a user's photo with their NSID.)
258
* @param string $username the username
259
* @return string the NSID (userid)
260
* @throws Zend_Service_Exception
262
public function getIdByUsername($username)
264
static $method = 'flickr.people.findByUsername';
266
$options = array('api_key' => $this->apiKey, 'method' => $method, 'username' => (string) $username);
268
if (empty($username)) {
270
* @see Zend_Service_Exception
272
require_once 'Zend/Service/Exception.php';
273
throw new Zend_Service_Exception('You must supply a username');
276
$restClient = $this->getRestClient();
277
$restClient->getHttpClient()->resetParameters();
278
$response = $restClient->restGet('/services/rest/', $options);
280
if ($response->isError()) {
282
* @see Zend_Service_Exception
284
require_once 'Zend/Service/Exception.php';
285
throw new Zend_Service_Exception('An error occurred sending request. Status code: '
286
. $response->getStatus());
289
$dom = new DOMDocument();
290
$dom->loadXML($response->getBody());
291
self::_checkErrors($dom);
292
$xpath = new DOMXPath($dom);
293
return (string) $xpath->query('//user')->item(0)->getAttribute('id');
298
* Utility function to find Flickr User IDs for emails.
300
* (You can only find a user's photo with their NSID.)
302
* @param string $email the email
303
* @return string the NSID (userid)
304
* @throws Zend_Service_Exception
306
public function getIdByEmail($email)
308
static $method = 'flickr.people.findByEmail';
312
* @see Zend_Service_Exception
314
require_once 'Zend/Service/Exception.php';
315
throw new Zend_Service_Exception('You must supply an e-mail address');
318
$options = array('api_key' => $this->apiKey, 'method' => $method, 'find_email' => (string) $email);
320
$restClient = $this->getRestClient();
321
$restClient->getHttpClient()->resetParameters();
322
$response = $restClient->restGet('/services/rest/', $options);
324
if ($response->isError()) {
326
* @see Zend_Service_Exception
328
require_once 'Zend/Service/Exception.php';
329
throw new Zend_Service_Exception('An error occurred sending request. Status code: '
330
. $response->getStatus());
333
$dom = new DOMDocument();
334
$dom->loadXML($response->getBody());
335
self::_checkErrors($dom);
336
$xpath = new DOMXPath($dom);
337
return (string) $xpath->query('//user')->item(0)->getAttribute('id');
342
* Returns Flickr photo details by for the given photo ID
344
* @param string $id the NSID
345
* @return array of Zend_Service_Flickr_Image, details for the specified image
346
* @throws Zend_Service_Exception
348
public function getImageDetails($id)
350
static $method = 'flickr.photos.getSizes';
354
* @see Zend_Service_Exception
356
require_once 'Zend/Service/Exception.php';
357
throw new Zend_Service_Exception('You must supply a photo ID');
360
$options = array('api_key' => $this->apiKey, 'method' => $method, 'photo_id' => $id);
362
$restClient = $this->getRestClient();
363
$restClient->getHttpClient()->resetParameters();
364
$response = $restClient->restGet('/services/rest/', $options);
366
$dom = new DOMDocument();
367
$dom->loadXML($response->getBody());
368
$xpath = new DOMXPath($dom);
369
self::_checkErrors($dom);
372
* @see Zend_Service_Flickr_Image
374
require_once 'Zend/Service/Flickr/Image.php';
375
foreach ($xpath->query('//size') as $size) {
376
$label = (string) $size->getAttribute('label');
377
$retval[$label] = new Zend_Service_Flickr_Image($size);
385
* Returns a reference to the REST client, instantiating it if necessary
387
* @return Zend_Rest_Client
389
public function getRestClient()
391
if (null === $this->_restClient) {
393
* @see Zend_Rest_Client
395
require_once 'Zend/Rest/Client.php';
396
$this->_restClient = new Zend_Rest_Client(self::URI_BASE);
399
return $this->_restClient;
404
* Validate User Search Options
406
* @param array $options
408
* @throws Zend_Service_Exception
410
protected function _validateUserSearch(array $options)
412
$validOptions = array('api_key', 'method', 'user_id', 'per_page', 'page', 'extras', 'min_upload_date',
413
'min_taken_date', 'max_upload_date', 'max_taken_date');
415
$this->_compareOptions($options, $validOptions);
418
* @see Zend_Validate_Between
420
require_once 'Zend/Validate/Between.php';
421
$between = new Zend_Validate_Between(1, 500, true);
422
if (!$between->isValid($options['per_page'])) {
424
* @see Zend_Service_Exception
426
require_once 'Zend/Service/Exception.php';
427
throw new Zend_Service_Exception($options['per_page'] . ' is not valid for the "per_page" option');
431
* @see Zend_Validate_Int
433
require_once 'Zend/Validate/Int.php';
434
$int = new Zend_Validate_Int();
435
if (!$int->isValid($options['page'])) {
437
* @see Zend_Service_Exception
439
require_once 'Zend/Service/Exception.php';
440
throw new Zend_Service_Exception($options['page'] . ' is not valid for the "page" option');
443
// validate extras, which are delivered in csv format
444
if ($options['extras']) {
445
$extras = explode(',', $options['extras']);
446
$validExtras = array('license', 'date_upload', 'date_taken', 'owner_name', 'icon_server');
447
foreach($extras as $extra) {
449
* @todo The following does not do anything [yet], so it is commented out.
451
//in_array(trim($extra), $validExtras);
458
* Validate Tag Search Options
460
* @param array $options
462
* @throws Zend_Service_Exception
464
protected function _validateTagSearch(array $options)
466
$validOptions = array('method', 'api_key', 'user_id', 'tags', 'tag_mode', 'text', 'min_upload_date',
467
'max_upload_date', 'min_taken_date', 'max_taken_date', 'license', 'sort',
468
'privacy_filter', 'bbox', 'accuracy', 'machine_tags', 'machine_tag_mode', 'group_id',
469
'extras', 'per_page', 'page');
471
$this->_compareOptions($options, $validOptions);
474
* @see Zend_Validate_Between
476
require_once 'Zend/Validate/Between.php';
477
$between = new Zend_Validate_Between(1, 500, true);
478
if (!$between->isValid($options['per_page'])) {
480
* @see Zend_Service_Exception
482
require_once 'Zend/Service/Exception.php';
483
throw new Zend_Service_Exception($options['per_page'] . ' is not valid for the "per_page" option');
487
* @see Zend_Validate_Int
489
require_once 'Zend/Validate/Int.php';
490
$int = new Zend_Validate_Int();
491
if (!$int->isValid($options['page'])) {
493
* @see Zend_Service_Exception
495
require_once 'Zend/Service/Exception.php';
496
throw new Zend_Service_Exception($options['page'] . ' is not valid for the "page" option');
499
// validate extras, which are delivered in csv format
500
if ($options['extras']) {
501
$extras = explode(',', $options['extras']);
502
$validExtras = array('license', 'date_upload', 'date_taken', 'owner_name', 'icon_server');
503
foreach($extras as $extra) {
505
* @todo The following does not do anything [yet], so it is commented out.
507
//in_array(trim($extra), $validExtras);
515
* Validate Group Search Options
517
* @param array $options
518
* @throws Zend_Service_Exception
521
protected function _validateGroupPoolGetPhotos(array $options)
523
$validOptions = array('api_key', 'tags', 'method', 'group_id', 'per_page', 'page', 'extras', 'user_id');
525
$this->_compareOptions($options, $validOptions);
528
* @see Zend_Validate_Between
530
require_once 'Zend/Validate/Between.php';
531
$between = new Zend_Validate_Between(1, 500, true);
532
if (!$between->isValid($options['per_page'])) {
534
* @see Zend_Service_Exception
536
require_once 'Zend/Service/Exception.php';
537
throw new Zend_Service_Exception($options['per_page'] . ' is not valid for the "per_page" option');
541
* @see Zend_Validate_Int
543
require_once 'Zend/Validate/Int.php';
544
$int = new Zend_Validate_Int();
546
if (!$int->isValid($options['page'])) {
548
* @see Zend_Service_Exception
550
require_once 'Zend/Service/Exception.php';
551
throw new Zend_Service_Exception($options['page'] . ' is not valid for the "page" option');
554
// validate extras, which are delivered in csv format
555
if (isset($options['extras'])) {
556
$extras = explode(',', $options['extras']);
557
$validExtras = array('license', 'date_upload', 'date_taken', 'owner_name', 'icon_server');
558
foreach($extras as $extra) {
560
* @todo The following does not do anything [yet], so it is commented out.
562
//in_array(trim($extra), $validExtras);
569
* Throws an exception if and only if the response status indicates a failure
571
* @param DOMDocument $dom
573
* @throws Zend_Service_Exception
575
protected static function _checkErrors(DOMDocument $dom)
577
if ($dom->documentElement->getAttribute('stat') === 'fail') {
578
$xpath = new DOMXPath($dom);
579
$err = $xpath->query('//err')->item(0);
581
* @see Zend_Service_Exception
583
require_once 'Zend/Service/Exception.php';
584
throw new Zend_Service_Exception('Search failed due to error: ' . $err->getAttribute('msg')
585
. ' (error #' . $err->getAttribute('code') . ')');
591
* Prepare options for the request
593
* @param string $method Flickr Method to call
594
* @param array $options User Options
595
* @param array $defaultOptions Default Options
596
* @return array Merged array of user and default/required options
598
protected function _prepareOptions($method, array $options, array $defaultOptions)
600
$options['method'] = (string) $method;
601
$options['api_key'] = $this->apiKey;
603
return array_merge($defaultOptions, $options);
608
* Throws an exception if and only if any user options are invalid
610
* @param array $options User options
611
* @param array $validOptions Valid options
613
* @throws Zend_Service_Exception
615
protected function _compareOptions(array $options, array $validOptions)
617
$difference = array_diff(array_keys($options), $validOptions);
620
* @see Zend_Service_Exception
622
require_once 'Zend/Service/Exception.php';
623
throw new Zend_Service_Exception('The following parameters are invalid: ' . implode(',', $difference));