Your IP : 216.73.216.158


Current Path : /home/megadansyp/www/components/com_eventgallery/library/Connector/
Upload File :
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;
    }


}