| Current Path : /home/megadansyp/www/components/com_eventgallery/library/Connector/ |
| Current File : /home/megadansyp/www/components/com_eventgallery/library/Connector/Flickr.php |
<?php
namespace Joomla\Component\Eventgallery\Site\Library\Connector;
use components\com_eventgallery\site\library\Data\Exif;
use Joomla\CMS\Http\HttpFactory;
use Joomla\CMS\Uri\Uri;
/**
* @package Sven.Bluege
* @subpackage com_eventgallery
*
* @copyright Copyright (C) 2005 - 2019 Sven Bluege All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
jimport('joomla.error.log');
require_once JPATH_ROOT.'/components/com_eventgallery/config.php';
require_once JPATH_ROOT.'/components/com_eventgallery/library/common/logger.php';
class Flickr
{
public static $cachebasedir;
public static $cache_life = '86400'; //caching time, in seconds
public static $requesttimeout = 5;
const DEFAULT_FLICKR_API_KEY = '0c6b59cdbf855c6ff1d63fa3f2cbd28e';
public static function initCacheDirs() {
if (!is_dir(JPATH_CACHE)) {
mkdir(JPATH_CACHE);
}
self::$cachebasedir = COM_EVENTGALLERY_FLICKR_CACHE_PATH;
if (!is_dir(self::$cachebasedir)) {
mkdir(self::$cachebasedir);
}
}
/**
* returns the name of the file for this url.
* @param $cachelifetime
* @param $url
* @return WebResult
*/
public static function getWebResult($cachelifetime, $url)
{
\JLog::addLogger(
array(
'text_file' => 'com_eventgallery.log.php',
'logger' => 'Eventgalleryformattedtext'
),
\JLog::ALL,
'com_eventgallery'
);
//\JLog::add('processing url '.$url, \JLog::INFO, 'com_eventgallery');
self::initCacheDirs();
$unsignedUrl = self::removeSignatureUrlParametersFromUrl($url);
$cachefilename = self::$cachebasedir . md5($unsignedUrl) . '.xml';
$dataUpdated = false;
if (file_exists($cachefilename) && (time() - filemtime($cachefilename) <= $cachelifetime)) {
// no need to do anything since the cache is still valid
} else {
//\JLog::add('will write new cache file for '.$url, \JLog::INFO, 'com_eventgallery');
$result = WebResult::url_get_contents($url);
if ($result===false) {
\JLog::add('unable to connect to remote host. Make sure curl is available or allow_url_fopen=On and the server has access to the internet. url: '.$url, \JLog::INFO, 'com_eventgallery');
}
#echo "reloading content from $url <br>";
if (strlen($result) > 0) {
$fh = fopen($cachefilename, 'w') or die("can't open file $cachefilename");
fwrite($fh, $result);
fclose($fh);
}
//\JLog::add('have written new cache file for '.$url, \JLog::INFO, 'com_eventgallery');
$dataUpdated = true;
}
$result = NULL;
return new WebResult($dataUpdated, $cachefilename);
}
/**
* @param $account \EventgalleryLibraryFlickraccount
* @return array
*/
public static function getPhotoSets($account, $pagenumber=1) {
$url = self::createFlickrPhotosetsGetListURL($account, $pagenumber);
$photosets = [];
$response = HttpFactory::getHttp()->get($url, [], self::$requesttimeout);
if ($response->code == 200) {
$data = json_decode($response->body);
$data_photosets = $data->photosets->photoset;
foreach ($data_photosets as $photoset) {
$result = [];
$result['id'] = $photoset->id;
$result['title'] = $photoset->title->_content;
$result['mediaItemsCount'] = $photoset->photos;
$result['coverPhotoBaseUrl'] = "https://live.staticflickr.com/{$photoset->server}/{$photoset->primary}_{$photoset->secret}_m.jpg?";
$result['productUrl'] = "https://www.flickr.com/photos/".urlencode($photoset->owner)."/albums/{$photoset->id}/";
array_push($photosets, $result);
}
if ($data->photosets->pages > $pagenumber) {
$photosets = array_merge($photosets, self::getPhotoSets($account, $pagenumber+1));
}
}
return $photosets;
}
/**
* Updates the photoset with the database
*
* @param $account \EventgalleryLibraryFlickraccount
* @param $cachelifetime
* @param $db \JDatabaseDriver
* @param $photoSetId
* @param $legacy_api_key
*/
public static function updatePhotoSet($account, $cachelifetime, $db, $photoSetId, $legacy_api_key)
{
self::initCacheDirs();
set_time_limit(30);
$url = self::createFlickrPhotosetGetPhotosURL($account, $photoSetId, 1, $legacy_api_key);
$webResult = self::getWebResult($cachelifetime, $url);
if (!$webResult->isDataUpdated()) {
return;
}
$json = $webResult->getFileContentAsJson();
if (!isset($json['stat'])) {
\JLog::add('Flickr answer contains error: '.$webResult->getFileContent(), \JLog::INFO, 'com_eventgallery');
return;
} elseif ($json['stat'] !== 'ok') {
\JLog::add('Flickr answer contains error status: '.$json['stat'], \JLog::INFO, 'com_eventgallery');
return;
}
$photoset = $json['photoset'];
$pages = $photoset['pages'];
$totalCount = $photoset['total'];
$counter = $totalCount;
$perpage = $photoset['perpage'];
$photos = $photoset['photo'];
self::addExif($photos, $account, $cachelifetime);
$db->transactionStart();
try {
$query = $db->getQuery(true);
$query->select('id, file')->from('#__eventgallery_file')
->where('folder='.$db->quote($photoSetId));
$db->setQuery($query);
$oldFiles = $db->loadObjectList();
$oldFileIDs = [];
if (is_iterable($oldFiles)) {
foreach ($oldFiles as $oldFile) {
$oldFileIDs[$oldFile->file] = $oldFile->id;
}
}
$query = $db->getQuery(true);
$query->delete('#__eventgallery_file')
->where('folder='.$db->quote($photoSetId));
$db->setQuery($query);
$db->execute();
self::updatePhotoSetInDatabase($db, $oldFileIDs, $photos, $photoSetId, $counter);
if ($pages>1) {
for ($i = 2; $i<=$pages; $i++) {
$counter = $counter - $perpage;
$url = self::createFlickrPhotosetGetPhotosURL($account, $photoSetId, $i, $legacy_api_key);
$webResult = self::getWebResult($cachelifetime, $url);
$content = file_get_contents($webResult->getCacheFileName());
$json = json_decode($content, true);
$photoset = $json['photoset'];
$photos = $photoset['photo'];
self::addExif($photos, $account, $cachelifetime);
self::updatePhotoSetInDatabase($db, $oldFileIDs, $photos, $photoSetId, $counter);
}
}
$db->transactionCommit();
} catch (\JDatabaseExceptionExecuting $e) {
\JLog::add('Catched database execution while updating Flickr albm. Error message: '. $e->getMessage(), \JLog::INFO, 'com_eventgallery');
$db->transactionRollback();
}
}
public static function addExif(&$photos, $account, $cachelifetime) {
//this is very slow and might trigger Flickr rate limit
return;
foreach($photos as &$photo) {
$url = self::createFlickrPhotoExifUrl($photo['id'], $account);
$webResult = self::getWebResult($cachelifetime, $url);
$content = file_get_contents($webResult->getCacheFileName());
$json = json_decode($content, true);
$exif = [];
if (isset($json['photo'])) {
$exif['model'] = $json['photo']['camera'];
if (isset($json['photo']['exif'])) {
foreach ($json['photo']['exif'] as $exifDataPoint) {
switch ($exifDataPoint['tag']) {
case 'FNumber': $exif['fstop'] = floatval($exifDataPoint['raw']['_content']); break;
case 'FocalLength': $exif['focallength'] = intval($exifDataPoint['clean']['_content']); break;
case 'ExposureTime': $exif['exposuretime'] = $exifDataPoint['raw']['_content']; break;
case 'ISO': $exif['iso'] = $exifDataPoint['raw']['_content']; break;
}
}
}
}
$photo['exif'] = (object)$exif;
}
}
/**
* creates a flickr url for a photoset
*
* @param $account \EventgalleryLibraryFlickraccount|null
* @param $photoSetId
* @param $pageNumber
* @param $legacy_api_key
* @return string
*/
public static function createFlickrPhotosetGetPhotosURL(?\EventgalleryLibraryFlickraccount $account, $photoSetId, $pageNumber, $legacy_api_key): string
{
$perPage = 500;
$api_key = self::DEFAULT_FLICKR_API_KEY;
if (!empty($legacy_api_key)) {
$api_key = $legacy_api_key;
}
$url = 'https://api.flickr.com/services/rest/?';
$url.= 'method=flickr.photosets.getPhotos';
$url.= '&photoset_id='.$photoSetId;
$url.= '&per_page='.$perPage;
$url.= '&page='.$pageNumber;
$url.= '&format=json';
$url.= '&nojsoncallback=1';
$url.= '&extras=o_dims,url_o,url_h,url_k,original_format,media,views,date_taken,description,sizes';
return self::completeFlickrUrlWithMandatoryParametersAndSignedUrl($url, $account);
}
/**
* @param $account \EventgalleryLibraryFlickraccount
* @param int $pageNumber
* @return string
*/
public static function createFlickrPhotosetsGetListURL(\EventgalleryLibraryFlickraccount $account, int $pageNumber): string
{
$perPage = 500;
$url = 'https://api.flickr.com/services/rest/?';
$url.= 'method=flickr.photosets.getList';
$url.= '&per_page='.$perPage;
$url.= '&page='.$pageNumber;
$url.= '&user_id='.urlencode($account->getUserId());
return self::completeFlickrUrlWithMandatoryParametersAndSignedUrl($url, $account);
}
public static function createFlickrPhotoExifUrl($photoid, $account) {
$url = 'https://api.flickr.com/services/rest/?';
$url.= 'method=flickr.photos.getExif';
$url.= '&photo_id='.$photoid;
return self::completeFlickrUrlWithMandatoryParametersAndSignedUrl($url, $account);
}
/**
* Transaction handling needs to happen in the function which uses this function.
*
* @param $db
* @param $photos
* @param $foldername
* @param $position
*/
private static function updatePhotoSetInDatabase($db, $oldFileIDs, $photos, $foldername, $position) {
if (count($photos)>0) {
$query = $db->getQuery(true);
$query->insert($db->quoteName('#__eventgallery_file'))
->columns(
'id,
folder,
file,
width,
height,
title,
caption,
flickr_secret,
flickr_secret_h,
flickr_secret_k,
flickr_secret_o,
flickr_originalformat,
flickr_server,
flickr_farm,
url,
exif,
ordering,
ismainimage,
ismainimageonly,
hits,
published,
userid,
modified,
created,
creation_date'
);
$photoCount = $position;
foreach ($photos as $photo) {
$secret_h = "";
if (isset($photo['url_h'])) {
preg_match("/.*_([^_]+)_h.jpg/", $photo['url_h'], $matches_h);
if (isset($matches_h[1])) {
$secret_h = $matches_h[1];
}
}
$secret_k = "";
if (isset($photo['url_k'])) {
preg_match("/.*_([^_]+)_k.jpg/", $photo['url_k'], $matches_k);
if (isset($matches_k[1])) {
$secret_k = $matches_k[1];
}
}
$query->values(implode(',', array(
isset($oldFileIDs[$photo['id']]) ? $db->quote((int)$oldFileIDs[$photo['id']]):0,
$db->quote($foldername),
$db->quote($photo['id']),
$db->quote($photo['width_o']),
$db->quote($photo['height_o']),
$db->quote($photo['title']),
$db->quote($photo['description']['_content']),
$db->quote($photo['secret']),
$db->quote($secret_h),
$db->quote($secret_k),
$db->quote($photo['originalsecret']),
$db->quote($photo['originalformat']),
$db->quote($photo['server']),
$db->quote($photo['farm']),
$db->quote(''),
$db->quote(isset($photo['exif'])?json_encode($photo['exif']):''),
$db->quote($photoCount--),
$db->quote($photo['isprimary']),
0,
$db->quote($photo['views']),
1,
0,
'now()',
$db->quote($photo['datetaken']),
$db->quote(date('YmdHis', strtotime($photo['datetaken'])))
)));
}
$db->setQuery($query);
$db->execute();
}
}
public static function appendSignaturetoUrl($method, $url, $api_secret, $token_secret): string
{
$url .= '&oauth_signature='.urlencode(self::getSignatureForUrl($method, $url, $api_secret, $token_secret));
return $url;
}
public static function removeSignatureUrlParametersFromUrl($url): string
{
$uri = new Uri($url);
$query = $uri->getQuery(true);
unset($query['oauth_signature']);
unset($query['oauth_timestamp']);
unset($query['oauth_nonce']);
$uri->setQuery($query);
return $uri->toString();
}
public static function getSignatureForUrl($method, $url, $api_secret, $token_secret): string
{
$url = new Uri($url);
$queryParameters = $url->getQuery(true);
ksort($queryParameters);
$signData = [
strtoupper($method),
urlencode($url->getScheme().'://'.$url->getHost().$url->getPath()),
urlencode(http_build_query($queryParameters))
];
$stringToBeSigned = implode('&',$signData);
$key = $api_secret.'&'.$token_secret;
return base64_encode(hash_hmac('sha1', $stringToBeSigned, $key, true));
}
/**
* @param \EventgalleryLibraryFlickraccount|null $account
* @param string $url
* @return string
*/
private static function completeFlickrUrlWithMandatoryParametersAndSignedUrl(string $url, ?\EventgalleryLibraryFlickraccount $account): string
{
$api_key = $account !=null && !empty($account->getAPIKey()) ? $account->getAPIKey():self::DEFAULT_FLICKR_API_KEY;
$url.= '&api_key='.urlencode($api_key);
$url.= '&format=json';
$url.= '&nojsoncallback=1';
if ($account !== null && !empty($account->getAuthTokenSecret())) {
$oauth_nonce = '12345';
$oauth_timestamp = time();
$url .= '&oauth_nonce=' . $oauth_nonce;
$url .= '&oauth_consumer_key=' . urlencode($account->getAPIKey());
$url .= '&oauth_timestamp=' . $oauth_timestamp;
$url .= '&oauth_signature_method=HMAC-SHA1';
$url .= '&oauth_version=1.0';
$url .= '&oauth_token=' . urlencode($account->getAuthToken());
$url = Flickr::appendSignaturetoUrl('GET', $url, $account->getAPISecret(), $account->getAuthTokenSecret());
}
return $url;
}
}