Seditio Source
Root |
./othercms/elxis_5.3_atlas_rev2452/includes/libraries/elxis/parser.class.php
<?php
/**
* @version        $Id: parser.class.php 1882 2016-08-25 15:45:03Z sannosi $
* @package        Elxis
* @subpackage    RSS/ATOM feed parser
* @copyright    Copyright (c) 2006-2016 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
elxisParser {

    private
$ttl = 7200;
    private
$type = ''; //rss or atom
   
private $feed = null;
    private
$errormsg = '';


   
/*********************/
    /* MAGIC CONSTRUCTOR */
    /*********************/    
   
public function __construct() {
    }


   
/********************************/
    /* SET TIME TO LIVE CACHED FEED */
    /********************************/
   
public function setTTL($seconds=7200) {
       
$seconds = (int)$seconds;
        if (
$seconds > 0) { $this->ttl = $seconds; }
    }


   
/*******************/
    /* GET REMOTE FEED */
    /*******************/
   
public function getFeed($url, $cache=true, $get_xml_string=false) {
       
$this->errormsg = '';
       
$id = md5($url);

        if (
$cache) {
           
$eCache = eFactory::getCache();
           
$status = $eCache->begin('feed', $id, 'feeds', $this->ttl, false, true, 'xml');
            if (
$status == 1) {
               
$xmldata = $eCache->fetchContents();
                if (
$get_xml_string === true) { return $xmldata; }
               
$ok = $this->parseXML($xmldata);
                if (!
$ok) { //wrong saved feed, try to fetch it again
                   
$this->errormsg = '';
                   
$eCache->clearItems('feeds', $id);
                   
$cache = false;
                } else {
                    return
$this->feed;
                }
            }
        }

        if (
function_exists('curl_init')) {
           
$xmldata = $this->curlget($url);
        } else {
           
$xmldata = $this->httpget($url);
        }

        if ((
$xmldata === false) || (trim($xmldata) == '')) {
            if (
$this->errormsg == '') { $this->errormsg = 'Could not fetch the feed from '.$url; }
            return
false;
        }

        if (!
$get_xml_string) {
           
$ok = $this->parseXML($xmldata);
            if (!
$ok) {
                if (
$this->errormsg == '') { $this->errormsg = 'Could not parse XML feed!'; }
                return
false;
            }
        }

        if (
$cache) {
            if (
$status == 2) { $eCache->store($xmldata); }
        }

        return
$get_xml_string ? $xmldata : $this->feed;
    }


   
/*******************************/
    /* PARSE AN XML STRING OR FILE */
    /*******************************/
   
public function parseXML($xmldata='', $xmlfile='') {
       
$this->errormsg = '';
       
$this->type = '';
       
$this->feed = null;
        if ((
$xmldata == '') && ($xmlfile == '')) {
           
$this->errormsg = 'You must provide an XML string or the absolute path to an XML file!';
            return
false;
        }

       
libxml_use_internal_errors(true);
        if (
$xmldata != '') {
           
$xml = simplexml_load_string($xmldata, 'SimpleXMLElement');
        } else {
            if (!
file_exists($xmlfile)) {
               
$this->errormsg = 'Provided XML file does not exist!';
                return
false;
            }
           
$xml = simplexml_load_file($xmlfile, 'SimpleXMLElement');
        }

        if (!
$xml) {
            foreach (
libxml_get_errors() as $error) {
               
$this->errormsg = 'Could not parse XML file. Error: '.$error->message.'. Line: '.$error->line;
                break;
            }
            return
false;
        }

       
$type = $xml->getName();
        if (
$type == 'feed') { $type = 'atom'; }
        if (!
in_array($type, array('rss', 'atom'))) {
           
$this->errormsg = 'Not supported feed type '.$type;
            return
false;
        }

       
$this->feed = new stdClass();
       
$this->feed->type = $type;

        if (
$this->feed->type == 'rss') {
            if (!isset(
$xml->channel)) {
               
$this->feed = null;
               
$this->errormsg = 'Invalid RSS feed!';
                return
false;
            }

           
$this->feed->title = (string)$xml->channel->title;
           
$this->feed->description = (string)$xml->channel->description;
           
$this->feed->link = (string)$xml->channel->link;
           
$this->feed->date = (isset($xml->channel->lastBuildDate)) ? (string)$xml->channel->lastBuildDate : '';
            if (
$this->feed->date == '') {
               
$this->feed->date = (isset($xml->channel->pubDate)) ? (string)$xml->channel->pubDate : '';
            }
           
$this->feed->copyright = (isset($xml->channel->copyright)) ? (string)$xml->channel->copyright : '';
           
$this->feed->generator = (isset($xml->channel->generator)) ? (string)$xml->channel->generator : '';
           
$this->feed->image = '';
            if (isset(
$xml->channel->image)) {
               
$this->feed->image = (isset($xml->channel->image->url)) ? (string)$xml->channel->image->url : '';
            }
           
$this->feed->items = array();

            if (isset(
$xml->channel->item)) {
                foreach (
$xml->channel->item as $item) {
                   
$iObj = new stdClass;
                   
$iObj->title = (string)$item->title;
                   
$iObj->link = (string)$item->link;
                   
$iObj->date = (isset($item->pubDate)) ? (string)$item->pubDate : '';
                   
$iObj->description = (isset($item->description)) ? (string)$item->description : '';
                   
$this->feed->items[] = $iObj;
                    unset(
$iObj);
                }
            }

            return
true;
        }

        if (
$this->feed->type == 'atom') {
           
$this->feed->title = (string)$xml->title;
           
$this->feed->description = (isset($xml->subtitle)) ? (string)$xml->subtitle : '';
           
//$this->feed->id = (string)$xml->id;
           
$this->feed->link = $this->getAtomLink($xml);
           
$this->feed->date = (isset($xml->updated)) ? (string)$xml->updated : '';
           
$this->feed->copyright = (isset($xml->rights)) ? (string)$xml->rights : '';
           
$this->feed->generator = (isset($xml->generator)) ? (string)$xml->generator : '';
           
$this->feed->image = (isset($xml->logo)) ? (string)$xml->logo : '';
            if (
$this->feed->image == '') {
               
$this->feed->image = (isset($xml->icon)) ? (string)$xml->icon : '';
            }
           
$this->feed->items = array();

            if (isset(
$xml->entry)) {
                foreach (
$xml->entry as $item) {
                   
$iObj = new stdClass;
                   
$iObj->title = (string)$item->title;
                   
$iObj->link = $this->getAtomLink($item);
                   
$iObj->date = (isset($item->published)) ? (string)$item->published : '';
                    if (
$iObj->date == '') {
                       
$iObj->date = (isset($item->updated)) ? (string)$item->updated : '';
                    }
                   
$iObj->description = (isset($item->content)) ? (string)$item->content : '';
                    if (
$iObj->description == '') {
                       
$iObj->description = (isset($item->summary)) ? (string)$item->summary : '';
                    }
                   
$this->feed->items[] = $iObj;
                    unset(
$iObj);
                }
            }

            return
true;
        }

       
$this->feed = null;
       
$this->errormsg = 'Not supported feed type!';
        return
false;
    }


   
/*****************************/
    /* GET PARSED FEED AS OBJECT */
    /*****************************/
   
public function getParsed() {
        return
$this->feed;
    }


   
/*******************/
    /* ERROR GENERATOR */
    /*******************/    
   
public function getError() {
        return
$this->errormsg;
    }


   
/***************************************/
    /* GET THE HTML LINK FROM AN ATOM ITEM */
    /***************************************/
   
private function getAtomLink($xmlitem) {
       
$htmllink = '';
        if (!isset(
$xmlitem->link)) { return ''; }
        if (
is_array($xmlitem->link)) {
            foreach(
$xmlitem->link as $v) {
               
$attr = $v->attributes();
                if (!
$attr) { continue; }
                if (!isset(
$attr['href'])) { continue; }
                if (isset(
$attr['rel']) && ($attr['rel'] == 'self')) { continue; }
                if (isset(
$attr['type']) && ($attr['type'] == 'text/html')) {
                   
$htmllink = trim($attr['href']);
                    break;
                }
                if (
$htmllink == '') {
                   
$htmllink = trim($attr['href']); //add this and continue for a better one
               
}
            }

            return
$htmllink;
        }

       
$attr = $xmlitem->link->attributes();
        if (!
$attr) { return ''; }
        if (!isset(
$attr['href'])) { return ''; }
       
$rel = (isset($attr['rel'])) ? (string)$attr['rel'] : '';
        if (
$rel != 'self') { $htmllink = trim($attr['href']); }

        return
$htmllink;
    }


   
/****************/
    /* GET FEED TYPE */
    /****************/    
   
public function getType() {
        return (
$this->feed) ? $this->feed->type : null;
    }


   
/*******************************/
    /* HTTP GET REQUEST USING CURL */
    /*******************************/
   
private function curlget($url) {
       
$uagent = (isset($_SERVER['HTTP_USER_AGENT'])) ? $_SERVER['HTTP_USER_AGENT'] : 'Mozilla/5.0 (Windows NT 6.0; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0)';

       
$ch = curl_init();
       
curl_setopt($ch, CURLOPT_URL, $url);
       
curl_setopt($ch, CURLOPT_HTTPGET, true);
       
curl_setopt($ch, CURLOPT_HEADER, false);
       
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
       
curl_setopt($ch, CURLOPT_FAILONERROR, true);
       
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
       
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 8);
       
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
       
curl_setopt($ch, CURLOPT_ENCODING, '');
       
curl_setopt($ch, CURLOPT_USERAGENT, $uagent);
       
curl_setopt($ch, CURLOPT_REFERER, eFactory::getElxis()->getConfig('URL'));

       
$xmldata = curl_exec($ch);
        if (
curl_errno($ch) == 0) {
           
curl_close($ch);
            return
$xmldata;
        } else {
           
$this->errormsg = curl_error($ch);
           
curl_close($ch);
            return
false;
        }
    }


   
/************************************/
    /* HTTP GET REQUEST USING FSOCKOPEN */
    /************************************/
   
private function httpget($url) {
       
$parseurl = parse_url($url);
        if (!
$parseurl) {
           
$this->errormsg = 'Given feed URL is invalid!';
            return
false;
        }

       
$uagent = (isset($_SERVER['HTTP_USER_AGENT'])) ? $_SERVER['HTTP_USER_AGENT'] : 'Mozilla/5.0 (Windows NT 6.0; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0)';

       
$getstr = '';
        if (isset(
$parseurl['query']) && ($parseurl['query'] != '')) {
           
$getstr = '?'.$parseurl['query']; //urlencode?
       
}

       
$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: '.$uagent."\r\n";
       
$req .= 'Accept: 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-Encoding: deflate'."\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, 15);
        if (!
$fp) {
           
$this->errormsg = 'Could not access feed '.$url;
            return
false;
        }
       
stream_set_timeout($fp, 10);
       
fputs($fp, $req);
       
$raw = '';
        while(!
feof($fp)) {
           
$raw .= fgets($fp);
           
$info = stream_get_meta_data($fp);
            if (
$info['timed_out']) {
               
fclose($fp);
               
$this->errormsg = 'Connection time out!';
                return
false;
            }
        }
       
fclose($fp);
       
$result = '';
       
$chunked = false;
        if (
$raw != '') {
           
$expl = preg_split("/(\r\n){2,2}/", $raw, 2);
           
$result = isset($expl[1]) ? $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;
    }
   
   
   
/***************************/
    /* DECODE A 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));
    }    

}
   
?>