Source of file FlickrService.php
Size: 11,134 Bytes - Last Modified: 2021-12-23T10:02:40+00:00
/var/www/docs.ssmods.com/process/src/code/services/FlickrService.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 | <?php class FlickrService extends RestfulService { /** * @var int Expiry time for API calls * This determines how long the cache is used before another API request * is made to update the cache, measured in seconds. 3600 == 1 hour. */ private static $flickr_soft_cache_expiry = 3600; /** * @var int Expiry time for SS_Cache * This determines how long the cache is kept before it is permanently cleared. * We need to clear at some point to ensure photosets removed from Flickr are eventually * hidden at the website end, measured in seconds. 86400 == 1 day. */ private static $flickr_hard_cache_expiry = 86400; /** * @var boolean To determine if errors should be logged everytime * This can be turned on when using the getCachedCall method, * so errors are only logged if both the API response and SS_Cache fallback fails. */ private static $skip_error_logging = false; /** * @var string The API key to be used for the next request to the API. This may change between requests (with calls * to {@link self::setApiKey()}), so it's not a config variable. */ private $apiKey; /** * @see self::isApiAvailable() * @var bool true if the API is available, false if not */ private $apiAvailable; /** * @see self::isApiAvailable() * @var Integer The api response code from calling flickr.test.echo */ private $responseCode; /** * @see self::isApiAvailable() * @var String The api response message from calling flickr.test.echo */ private $responseMessage; public function __construct() { parent::__construct('https://www.flickr.com/services/rest/', $this->config()->flickr_soft_cache_expiry); $this->checkErrors = true; } /** * @param string $userId The Flickr user_id to get all photosets for * @todo Currently returns all photosets. Optimisations could be made to only return a single page of results * @return ArrayList<FlickrPhotoset> */ public function getPhotosetsForUser($userId) { if (!$this->isAPIAvailable()) { return null; } $params = array( 'method' => 'flickr.photosets.getList', 'user_id' => $userId, ); $this->setQueryString(array_merge($this->defaultParams(), $params)); try { $rawResponse = $this->request()->getBody(); $response = unserialize($rawResponse); if (!$response || $response['stat'] !== 'ok') { throw new Exception(sprintf('Response from Flickr not expected: %s', var_export($rawResponse, true))); } $results = new ArrayList(); foreach ($response['photosets']['photoset'] as $set) { $obj = FlickrPhotoset::create_from_array($set, $userId); if ($obj) { $results->push($obj); } } return $results; } catch (Exception $e) { if (!$this->config()->skip_error_logging) { SS_Log::log( sprintf( "Couldn't retrieve Flickr photosets for user '%s': Message: %s", $userId, $e->getMessage() ), SS_Log::ERR ); } return null; } } public function getPhotosetById($photosetId, $userId = null) { if (!$this->isAPIAvailable()) { return null; } $params = array( 'method' => 'flickr.photosets.getInfo', 'photoset_id' => $photosetId ); if (!is_null($userId)) { $params['user_id'] = $userId; } $this->setQueryString(array_merge($this->defaultParams(), $params)); try { $rawResponse = $this->request()->getBody(); $response = unserialize($rawResponse); if (!$response || $response['stat'] !== 'ok') { throw new Exception(sprintf('Response from Flickr not expected: %s', var_export($rawResponse, true))); } $result = FlickrPhotoset::create_from_array($response['photoset'], $userId); return $result; } catch (Exception $e) { if (!$this->config()->skip_error_logging) { SS_Log::log( sprintf( "Couldn't retrieve Flickr photoset for user '%s', photoset '%s': Message: %s", $userId, $photosetId, $e->getMessage() ), SS_Log::ERR ); } return null; } } /** * Returns all photos within a given photoset. * * @param int $photosetId * @param int|null $userId Optional, but API will respond faster if this is specified * @return ArrayList<FlickrPhoto> */ public function getPhotosInPhotoset($photosetId, $userId = null) { if (!$this->isAPIAvailable()) { return null; } $params = array( 'method' => 'flickr.photosets.getPhotos', 'photoset_id' => $photosetId, 'extras' => 'description,original_format' ); if ($userId) { $params['user_id'] = $userId; } $this->setQueryString(array_merge($this->defaultParams(), $params)); try { $rawResponse = $this->request()->getBody(); $response = unserialize($rawResponse); if (!$response || !isset($response['stat']) || $response['stat'] !== 'ok') { throw new Exception(sprintf("Response from Flickr not expected: %s", var_export($rawResponse, true))); } $results = new ArrayList(); foreach ($response['photoset']['photo'] as $photo) { $obj = FlickrPhoto::create_from_array($photo); if ($obj) { $results->push($obj); } } return $results; } catch (Exception $e) { if (!$this->config()->skip_error_logging) { SS_Log::log( sprintf( "Couldn't retrieve Flickr photos in photoset '%s' for optional user '%s'", $photosetId, $userId ), SS_Log::ERR ); } return null; } } /** * This returns API responses saved to a SS_Cache file instead of the API response directly * as the Flickr API is often not reliable * * @param String $funcName Name of the function to call if cache expired or does not exist * @param array $args Arguments for the function * @return ArrayList<FlickrPhoto|FlickrPhotoset> */ public function getCachedCall($funcName, $args = array()) { $result = null; $argsCount = count($args); if ($argsCount < 1) { return $result; } // build up a unique cache name $cacheKey = array( $funcName ); foreach ($args as $arg) { $cacheKey[] = $arg; } // to hide api key and remove non alphanumeric characters $cacheKey = md5(implode('_', $cacheKey)); // setup cache $cache = SS_Cache::factory('FlickrService'); $cache->setOption('automatic_serialization', true); SS_Cache::set_cache_lifetime('FlickrService', $this->config()->flickr_hard_cache_expiry); // check if cached response exists or soft expiry has elapsed $metadata = $cache->getBackend()->getMetadatas('FlickrService' . $cacheKey); if (!($result = $cache->load($cacheKey)) || $this->softCacheExpired($metadata['mtime'])) { // try update the cache try { $result = call_user_func_array(array($this, $funcName), $args); // only update cache if result returned if ($result) { $cache->save($result, $cacheKey); } } catch (Exception $e) { SS_Log::log( sprintf( "Couldn't retrieve Flickr photos using '%s': Message: %s", $funcName, $e->getMessage() ), SS_Log::ERR ); } } return $result; } /** * @return bool true if the API is available right now, or false if it isn't */ public function isAPIAvailable() { // Ensure we always query this, so we don't cache stale information, but only query once per request if ($this->apiAvailable) { return $this->apiAvailable; } $oldExpiry = $this->cache_expire; $this->cache_expire = 0; $params = array( 'method' => 'flickr.test.echo' ); $this->setQueryString(array_merge($this->defaultParams(), $params)); try { $rawResponse = $this->request()->getBody(); $response = unserialize($rawResponse); $return = $response['stat'] === "ok"; /* * $response contains an array, e.g. * {"stat":"fail", "code":100, "message":"Invalid API Key (Key has invalid format)"} */ if ($response['stat'] === "ok") { $return = true; } else { // save the error code and message for service consumers to utilise $this->responseCode = $response['code']; $this->responseMessage = $response['message']; $return = false; } } catch (Exception $e) { $return = false; } $this->cache_expire = $oldExpiry; $this->apiAvailable = $return; return $return; } /** * @param int $modifiedTime Timestamp of when cache file was last modified * @return boolean Check to see if the soft cache has expired */ public function softCacheExpired($modifiedTime) { return time() > $modifiedTime + $this->config()->flickr_soft_cache_expiry; } public function setApiKey($key) { $this->apiKey = $key; return $this; } public function getApiKey() { return $this->apiKey; } /** * Get the API response code * @return String */ public function getApiResponseCode() { return $this->responseCode; } /** * Get the API response message * @return String */ public function getApiResponseMessage() { return $this->responseMessage; } private function defaultParams() { return array( 'api_key' => $this->getApiKey(), 'format' => 'php_serial' ); } } |