Seditio Source
Root |
./othercms/elxis_5.3_atlas_rev2452/components/com_search/engines/youtube/youtube.engine.php
<?php
/**
* @version        $Id: youtube.engine.php 2203 2019-04-10 18:34:15Z IOS $
* @package        Elxis
* @subpackage    Component Search
* @copyright    Copyright (c) 2006-2019 Elxis CMS (http://www.elxis.org). All rights reserved.
* @license        Elxis Public License ( http://www.elxis.org/elxis-public-license.html )
* @author        Elxis Team ( http://www.elxis.org )
* @description     Elxis CMS is free software. Read the license for copyright notices and details
*/

defined('_ELXIS_') or die ('Direct access to this location is not allowed');


class
youtubeEngine implements searchEngine {

    private
$options = array('q' => '', 'time' => 0, 'ordering' => 'r');        
    private
$dosearch = false;
    private
$total = 0;
    private
$limit = 10;
    private
$limitstart = 0;
    private
$page = 1;
    private
$maxpage = 1;
    private
$results = array();
    private
$columns = 1;
    private
$safe = 'moderate';
    private
$channelid = '';
    private
$apikey = '';
    private
$apierror = '';
    private
$year = 0; //for internal use only
   
private $month = 0; //for internal use only


    /********************/
    /* MAGIC CONTRUCTOR */
    /********************/
   
public function __construct($params) {
       
$this->limit = (int)$params->get('limit', 10);
        if (
$this->limit < 1) { $this->limit = 10; }
       
$this->columns = (int)$params->get('columns', 1);
        if (
$this->columns < 1) { $this->columns = 1; }
        if (
$this->columns > 2) { $this->columns = 2; }

       
$this->safe = trim($params->get('safe', 'moderate'));
        if ((
$this->safe == '') || !in_array($this->safe, array('none', 'moderate', 'strict'))) {
           
$this->safe = 'moderate';
        }
       
$this->channelid = trim($params->get('channelid', ''));
       
$this->options['ordering'] = $params->get('ordering', 'r');
        if ((
$this->options['ordering'] == '') || !in_array($this->options['ordering'], array('r', 'dd', 'hd', 'vd', 'ta'))) {
           
$this->options['ordering'] = 'r';
        }

       
$this->apikey = trim($params->get('key', ''));

       
$this->setOptions();
    }


   
/***********************************/
    /* SET SEARCH OPTIONS FROM THE URL */
    /***********************************/
   
private function setOptions() {
       
$pat = "#([\']|[\;]|[\.]|[\"]|[\$]|[\/]|[\|]|[\=]|[\#]|[\<]|[\>]|[\*]|[\~]|[\`]|[\^]|[\|]|[\\\])#u";
        if (isset(
$_GET['q'])) {
           
$q = urldecode(filter_input(INPUT_GET, 'q', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW));
           
$q = eUTF::trim(preg_replace($pat, '', $q));
            if (
eUTF::strlen($q) > 3) { $this->options['q'] = $q; $this->dosearch = true; }            
        }

        if (isset(
$_GET['time'])) {
           
$time = (int)$_GET['time'];
            if (
$time > 0) {
                if (
$time < 365) {
                   
$this->options['time'] = $time;
                   
$this->dosearch = true;
                } else {
                   
$t = (string)$time;
                    if (
strlen($t) == 4) {
                        if ((
$time > 1970) && ($time <= date('Y'))) { //valid year
                           
$this->options['time'] = $time;
                           
$this->year = $time;
                           
$this->month = 0;
                           
$this->dosearch = true;
                        }
                    } else if (
strlen($t) == 6) {
                       
$y = intval(substr($t, 0, 4));
                       
$m = intval(substr($t, -2));
                       
$m2 = sprintf("%02d", $m);
                        if ((
$y > 1970) && ($m > 0) && ($m < 13) && ($y.$m2 <= date('Ym'))) { //valid year & month
                           
$this->year = $y;
                           
$this->month = $m2;
                           
$this->options['time'] = $y.$this->month;
                           
$this->dosearch = true;
                        }
                        unset(
$y, $m, $m2);
                    }
                }
            }
        }

        if (isset(
$_GET['ordering'])) {
           
$ordering = trim(filter_input(INPUT_GET, 'ordering', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH));
            if (
in_array($ordering, array('r', 'dd', 'hd', 'vd', 'ta'))) {
               
$this->options['ordering'] = $ordering;
            }
        }
    }


   
/**************************/
    /* GET ENGINE'S META INFO */
    /**************************/
   
public function engineInfo() {
       
$eLang = eFactory::getLang();
       
$info = array(
           
'title' => 'YouTube',
           
'description' => $eLang->get('SEARCH_YOUTUBE'),
           
'metakeys' => array(
               
$eLang->get('SEARCH'),
               
'videos',
               
'youtube',
               
'youtube videos',
               
$eLang->get('KEYWORD'),
               
'OpenSearch',
               
'elxis youtube search'
           
)
        );
        if (
$this->channelid != '') { $info['metakeys'][] = 'Videos by '.$this->channelid; }
        return
$info;
    }


   
/********************/
    /* MAKE SEARCH FORM */
    /********************/
   
public function searchForm() {
       
$eURI = eFactory::getURI();
       
$eLang = eFactory::getLang();

       
$isssl = $eURI->detectSSL();
       
$action = $eURI->makeURL('search:youtube.html', '', $isssl);

       
elxisLoader::loadFile('includes/libraries/elxis/form5.class.php');

       
$form = new elxis5Form(array('idprefix' => 'stub', 'labelclass' => 'elx5_label', 'sideclass' => 'elx5_labelside'));
       
$form->openForm(array('name' => 'fmsearchytube', 'method' => 'get', 'action' => $action, 'id' => 'fmsearchytube'));

       
$form->openFieldset($eLang->get('SEARCH_OPTIONS'));
       
$form->addNote($eLang->get('LEAST_ONE_CRITERIA'), 'elx5_formtext');
       
$form->addText('q', $this->options['q'], $eLang->get('KEYWORD'), array('required' => 'required', 'maxlength' => 80, 'placeholder' => $eLang->get('KEYWORD')));
        if (
$this->columns == 2) {
           
$form->addHTML('<div class="elx5_2colwrap">');
           
$form->addHTML('<div class="elx5_2colbox">');
        }

       
$options = array();
       
$options[] = $form->makeOption(0, $eLang->get('ANY_TIME'));
       
$options[] = $form->makeOption(1, $eLang->get('LAST_24_HOURS'));
       
$options[] = $form->makeOption(2, $eLang->get('LAST_2_DAYS'));
       
$options[] = $form->makeOption(10, $eLang->get('LAST_10_DAYS'));
       
$options[] = $form->makeOption(30, $eLang->get('LAST_30_DAYS'));
       
$options[] = $form->makeOption(90, $eLang->get('LAST_3_MONTHS'));
       
$options[] = $form->makeOption(date('Ym'), $eLang->get('THIS_MONTH'));
       
$years = array();
       
$end = (($this->year > 0) && ($this->year < 2010)) ? $this->year : 2010;
        for (
$i = date('Y'); $i >= $end; $i--) { $years[] = $i; }
        foreach (
$years as $year) {
           
$txt = ($year == date('Y')) ? $eLang->get('THIS_YEAR') : $year;
           
$options[] = $form->makeOption($year, $txt);
            if ((
$this->year == $year) && ($this->month > 0)) {
               
$monthname = eFactory::getDate()->monthName($this->month);
               
$options[] = $form->makeOption($year.$this->month, $monthname.' '.$year);
            }
        }
       
$form->addSelect('time', $eLang->get('DATE'), $this->options['time'], $options);
        unset(
$years, $end, $options);
        if (
$this->columns == 2) {
           
$form->addHTML('</div><div class="elx5_2colbox">');
        }
       
$options = array();
       
$options[] = $form->makeOption('r', $eLang->get('RELEVANCY'));
       
$options[] = $form->makeOption('dd', $eLang->get('NEWER_FIRST'));
       
$options[] = $form->makeOption('hd', $eLang->get('MOST_POPULAR_FIRST'));
       
$options[] = $form->makeOption('vd', $eLang->get('RATING'));
       
$options[] = $form->makeOption('ta', $eLang->get('TITLE'));
       
$form->addSelect('ordering', $eLang->get('ORDERING'), $this->options['ordering'], $options);
        unset(
$options);
        if (
$this->columns == 2) {
           
$form->addHTML('</div></div>');
        }

       
$sidepad = ($this->columns == 2) ? 0 : 1;
       
$form->addHTML('<div class="elx5_vspace">');
       
$form->addButton('sbm', $eLang->get('SEARCH'), 'submit', array('class' => 'elx5_btn elx5_sucbtn', 'sidepad' => $sidepad));
       
$form->addHTML('</div>');

       
$form->closeFieldset();
        unset(
$form);
    }


   
/**************************/
    /* PROCESS SEARCH REQUEST */
    /**************************/
   
public function search($page=1) {
       
$page = (int)$page;
        if (
$page < 1) { $page = 1; }
       
$this->total = 0;
       
$this->limitstart = 0;
       
$this->page = $page;
       
$this->maxpage = 1;
       
$this->results = array();
        if (
$this->dosearch == false) { return false; }
       
$results = $this->request($page);
        if (
$results) {
           
$this->results = $results;
            return
$this->total;
        }
        return
0;
    }


   
/**************************************/
    /* QUERY YOUTUBE AND GET BACK RESULTS */
    /**************************************/
   
private function request($page) {
       
$page = (int)$page;
        if (
$page < 1) { $page = 1; }
       
$start = (($page - 1) * $this->limit) + 1;

       
$params = array();
       
$params['part'] = 'snippet';
       
$params['maxResults'] = 50;//always get 50 (maximum for 1 request) and then split them into pages ($this->limit);
       
$params['safeSearch'] = $this->safe;
       
$params['type'] = 'video';
        switch (
$this->options['ordering']) {
            case
'dd': $params['order'] = 'date'; break;
            case
'hd': $params['order'] = 'viewCount'; break;
            case
'vd': $params['order'] = 'rating'; break;
            case
'ta': $params['order'] = 'title'; break;
            case
'r': default: $params['order'] = 'relevance'; break;
        }

        if (
$this->channelid != '') { $params['channelId'] = $this->channelid; }

        if (
$this->options['time'] > 0) {
            if (
$this->options['time'] < 365) {
               
$ts = time() - ($this->options['time'] * 24 * 3600);
               
$datetime = gmdate('c', $ts); //RFC 3339
               
$params['publishedAfter'] = $datetime;
            } else if (
$this->year > 0) {
                if (
$this->month > 0) {
                   
$ts = mktime(0, 0, 0, $this->month, 1, $this->year);
                   
$datetime = gmdate('c', $ts); //RFC 3339
                   
$params['publishedAfter'] = $datetime;
                   
$y = $this->year;
                   
$m = $this->month + 1;
                    if (
$m == 13) { $m = 1; $y = $y + 1; }
                   
$ts = mktime(0, 0, 0, $m, 1, $y);
                   
$datetime = gmdate('c', $ts); //RFC 3339
                   
$params['publishedBefore'] = $datetime;
                } else {
                   
$ts = mktime(0, 0, 0, 1, 1, $this->year);
                   
$datetime = gmdate('c', $ts); //RFC 3339
                   
$params['publishedAfter'] = $datetime;
                    if (
$this->year == gmdate('Y')) {
                       
$ts = time();
                    } else {
                       
$y = $this->year + 1;
                       
$ts = mktime(0, 0, 0, 1, 1, $y);
                    }
                   
$datetime = gmdate('c', $ts); //RFC 3339
                   
$params['publishedBefore'] = $datetime;
                }
            }
        }
        if (
$this->options['q'] != '') { $params['q'] = $this->options['q']; }
        if (
$this->apikey != '') { $params['key'] = $this->apikey; }

       
$url = 'https://www.googleapis.com/youtube/v3/search';
        if (
function_exists('curl_init')) {
           
$result = $this->curlget($url, $params);
        } else {
           
$result = $this->httpget($url, $params);
        }

        if (!
$result) { return false; }
        return
$this->parsejsondata($result);
    }


   
/*******************************/
    /* HTTP GET REQUEST USING CURL */
    /*******************************/
   
private function curlget($url, $params=null) {
       
$ch = curl_init();
        if (
$params) {
           
curl_setopt($ch, CURLOPT_URL, $url.'?'.http_build_query($params)); //url encodes the data
       
} else {
           
curl_setopt($ch, CURLOPT_URL, $url);
        }

       
curl_setopt($ch, CURLOPT_HEADER, 0);
       
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
       
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
       
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
       
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
       
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 8);
       
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
       
$result = curl_exec($ch);
        if (
0 == curl_errno($ch)) {
           
curl_close($ch);
            return
$result;
        } else {
           
$this->apierror = curl_error($ch);
           
curl_close($ch);
            return
false;
        }
    }


   
/************************************/
    /* HTTP GET REQUEST USING FSOCKOPEN */
    /************************************/
   
private function httpget($url, $params=null) {
       
$parseurl = parse_url($url);
       
$getstr = '';
        if (
$params) {
           
$parr = array();
            foreach(
$params as $key => $val) { $parr[] = $key.'='.urlencode($val); }
           
$getstr = implode('&', $parr);
            unset(
$parr);
        }

       
$req = 'GET '.$parseurl['path'].'?'.$getstr." HTTP/1.1\r\n";
       
$req .= 'Host: '.$parseurl['host']."\r\n";
       
$req .= "Referer: ".eFactory::getElxis()->getConfig('URL')."\r\n";
       
$req .= 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1'."\r\n";
       
$req .= 'Accept: application/json,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,*/*;q=0.6'."\r\n";
       
$req .= 'Accept-Language: en-us,en;q=0.5'."\r\n";
       
$req .= 'Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7'."\r\n";
       
$req .= "Connection: Close\r\n\r\n";

        if (!isset(
$parseurl['port'])) {
           
$parseurl['port'] = ($parseurl['scheme'] == 'https') ? 443 : 80;
        }

       
$fp = fsockopen($parseurl['host'], $parseurl['port'], $errno, $errstr, 20);
        if (!
$fp) { return false; }
       
stream_set_timeout($fp, 15);
       
fputs($fp, $req);
       
$raw = '';
        while(!
feof($fp)) {
           
$raw .= fgets($fp);
           
$info = stream_get_meta_data($fp);
            if (
$info['timed_out']) {
               
fclose($fp);
                return
false;
            }
        }
       
fclose($fp);
       
$result = '';
       
$chunked = false;
        if (
$raw != '') {
           
$expl = preg_split("/(\r\n){2,2}/", $raw, 2);
           
$result = $expl[1];
            if (
preg_match('/Transfer\\-Encoding:\\s+chunked/i',$expl[0])) { $chunked = true; }
            unset(
$expl);
        }
        unset(
$raw);

        if (
$chunked) {
           
$result = $this->decodeChunked($result);
        }
        return
$result;
    }


   
/***********************/
    /* PARSE JSON RESPONSE */
    /***********************/
   
private function parsejsondata($result) {
       
$response = json_decode($result);

        if ((!
is_object($response)) || (!isset($response->items))) { return false; }
        if (!
is_array($response->items)) { return false; }

       
$results = array();
       
$this->total = count($response->items);
       
$maxpage = ($this->total == 0) ? 1 : ceil($this->total/$this->limit);
        if (
$maxpage < 1) { $maxpage = 1; }
        if (
$this->page > $maxpage) { $this->page = $maxpage; }
       
$this->maxpage = $maxpage;
       
$this->limitstart = (($this->page - 1) * $this->limit);

       
$i = 0;
        foreach (
$response->items as $item) {
            if (
$i < $this->limitstart) { $i++; continue; }
            if (
count($results) == $this->limit) { break; }
           
$i++;
           
$video = new stdClass;
           
$video->videoid = $item->id->videoId;
           
$video->url = 'https://www.youtube.com/watch?v='.$item->id->videoId;
           
$video->thumbnail = $item->snippet->thumbnails->medium->url;
           
$video->title = $item->snippet->title;
           
$video->description = $item->snippet->description;
           
$video->time = strtotime($item->snippet->publishedAt);
           
$results[] = $video;
        }

        return
$results;
    }


   
/***********************/
    /* SHOW SEARCH RESULTS */
    /***********************/
   
public function showResults() {
       
$elxis = eFactory::getElxis();
       
$eDate = eFactory::getDate();
       
$eLang = eFactory::getLang();
       
$eDoc = eFactory::getDocument();

        if (
$this->dosearch == false) { return; }

       
eFactory::getDocument()->addStyleLink($elxis->secureBase().'/components/com_search/engines/youtube/css/youtube.engine.css');

        if (
$this->total == 0) {
            if (
$this->apierror != '') {
                echo
'<div class="elx5_error" dir="ltr"><strong>'.$eLang->get('ERROR').'</strong> '.$this->apierror."<br />YouTube API v3</div>\n";
            } else if (
$this->apikey != '') {
                echo
'<div class="elx5_warning">An API key is required to perform search on YouTube!'."</div>\n";
            } else {
                echo
'<div class="elx5_warning">'.$eLang->get('SEARCH_NO_RESULTS')."</div>\n";
            }
            return;
        }

       
$eDoc->loadMediabox();

       
$playimg = $elxis->secureBase().'/components/com_search/engines/youtube/css/play.png';

       
$boxclass = 'elx_yeng_box'.$eLang->getinfo('RTLSFX');

        echo
'<div class="elx_yeng_container">'."\n";
        foreach (
$this->results as $row) {
           
$title = (eUTF::strlen($row->title) > 38) ? eUTF::substr($row->title, 0, 35).'...' : $row->title;
           
$link = 'https://www.youtube.com/v/'.$row->videoid.'&amp;fs=1&amp;rel=0&amp;wmode=transparent';
            echo
'<div class="'.$boxclass.'">'."\n";
            echo
'<div class="elx_yeng_imgbox">'."\n";
            echo
'<img class="elx_yeng_play" src="'.$playimg.'" width="32" height="32" />'."\n";
            echo
'<a href="'.$link.'" title="'.$row->title.'" target="_blank" data-mediabox="resultyoutube">';
            echo
'<img src="'.$row->thumbnail.'" alt="'.$row->title.'" width="160" height="100" /></a>'."\n";
            echo
"</div>\n";
            echo
'<div class="elx_yeng_notes'.$eLang->getinfo('RTLSFX').'">'."\n";
            echo
'<a href="'.$link.'" title="'.$row->title.'" class="elx_yeng_title resultyoutube" target="_blank">'.$title."</a><br />\n";
            echo
$eLang->get('DATE').' <span>'.$eDate->formatTS($row->time, $eLang->get('DATE_FORMAT_2'))."</span>\n";
            echo
"</div>\n";
            echo
"</div>\n";
        }
        echo
'<div class="clear"></div>'."\n";
        echo
"</div>\n";
    }


   
/*******************************/
    /* GET NUMBER OF TOTAL RESULTS */
    /*******************************/
   
public function getTotal() {
        return
$this->total;
    }


   
/********************/
    /* GET SEARCH LIMIT */
    /********************/
   
public function getLimit() {
        return
$this->limit;
    }


   
/**************************/
    /* GET SEARCH LIMIT START */
    /**************************/
   
public function getLimitStart() {
        return
$this->limitstart;
    }


   
/***************************/
    /* GET CURRENT PAGE NUMBER */
    /***************************/
   
public function getPage() {
        return
$this->page;
    }


   
/***************************/
    /* GET MAXIMUM PAGE NUMBER */
    /***************************/
   
public function getMaxPage() {
        return
$this->maxpage;
    }


   
/****************************/
    /* GET SEARCH OPTIONS ARRAY */
    /****************************/
   
public function getOptions() {
        return
$this->options;
    }


   
/******************************************/
    /* GET SEARCH SEARCH FOR THE CURRENT PAGE */
    /******************************************/
   
public function getResults() {
        return
$this->results;
    }


   
/****************************/
    /* DECODE AN CHUNKED STRING */
    /****************************/
   
private function decodeChunked($chunk) {
        if (
function_exists('http_chunked_decode')) {
            return
http_chunked_decode($chunk);
        }

       
$pos = 0;
       
$len = strlen($chunk);
       
$dechunk = null;
        while((
$pos < $len) && ($chunkLenHex = substr($chunk,$pos, ($newlineAt = strpos($chunk,"\n",$pos+1))-$pos))) {
            if (!
$this->is_hex($chunkLenHex)) { return $chunk; }
           
$pos = $newlineAt + 1;
           
$chunkLen = hexdec(rtrim($chunkLenHex,"\r\n"));
           
$dechunk .= substr($chunk, $pos, $chunkLen);
           
$pos = strpos($chunk, "\n", $pos + $chunkLen) + 1;
        }

        return
$dechunk;
    }


   
/****************************/
    /* IS STRING A HEX NUMBER ? */
    /****************************/
   
private function is_hex($hex) {
       
$hex = strtolower(trim(ltrim($hex,"0")));
        if (empty(
$hex)) { $hex = 0; };
       
$dec = hexdec($hex);
        return (
$hex == dechex($dec));
    }

}

?>