asChannel = $asChannel; //Items $this->asItems = array(); array_walk($asItems, array($this, 'addItem')); } public function loadRss($sUrl) { $oCurl = curl_init(); curl_setopt($oCurl, CURLOPT_URL, $sUrl); curl_setopt($oCurl, CURLOPT_HEADER, false); curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, true); curl_setopt($oCurl, CURLOPT_USERAGENT, array_key_exists('HTTP_USER_AGENT', $_SERVER)?$_SERVER['HTTP_USER_AGENT']:'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0'); $fCookieJar = tempnam('/tmp','cookie'); curl_setopt($oCurl, CURLOPT_COOKIESESSION, true); curl_setopt($oCurl, CURLOPT_COOKIEJAR, $fCookieJar); curl_setopt($oCurl, CURLOPT_COOKIEFILE, $fCookieJar); //curl_setopt($oCurl, CURLOPT_ENCODING, 'gzip'); $sRssContent = curl_exec($oCurl); curl_close($oCurl); //Parse document encoding (useless) $sEncoding = $this->getPregMatch("'encoding=[\'\"](.*?)[\'\"]'si", $sRssContent); //Parse Channel info if(preg_match("'(.*?)'si", $sRssContent, $sChannelContent)) { foreach(self::CHANNEL_TAGS as $sChannelTag) { $sTagContent = $this->getPregMatch("'<$sChannelTag.*?>(.*?)'si", $sChannelContent[1]); if($sTagContent != '') $this->asChannel[$sChannelTag] = $sTagContent; } } //Parse Text Input info /*preg_match("']*[^/])>(.*?)'si", $sRssContent, $out_textinfo); if (isset($out_textinfo[2])) { foreach($this->textinputtags as $textinputtag) { $temp = $this->getPregMatch("'<$textinputtag.*?>(.*?)'si", $out_textinfo[2]); if ($temp != '') $result['textinput_'.$textinputtag] = $temp; // Set only if not empty } }*/ //Parse Image info /*preg_match("'(.*?)'si", $sRssContent, $out_imageinfo); if (isset($out_imageinfo[1])) { foreach($this->imagetags as $imagetag) { $temp = $this->getPregMatch("'<$imagetag.*?>(.*?)'si", $out_imageinfo[1]); if ($temp != '') $result['image_'.$imagetag] = $temp; // Set only if not empty } }*/ //Parse Items preg_match_all("'(.*?)'si", $sRssContent, $asItems); //$i = 0; foreach($asItems[2] as $asItem) { $asItemTags = array(); foreach(self::ITEM_TAGS as $sItemTag) { $sTagContent = $this->getPregMatch("'<$sItemTag.*?>(.*?)'si", $asItem); if($sTagContent != '') $asItemTags[$sItemTag] = $sTagContent; } //Strip HTML tags and other bullshit from DESCRIPTION //if($this->stripHTML && $this->asItems[$i]['description']) $this->asItems[$i]['description'] = strip_tags($this->unhtmlentities(strip_tags($this->asItems[$i]['description']))); //Strip HTML tags and other bullshit from TITLE //if($this->stripHTML && $this->asItems[$i]['title']) $this->asItems[$i]['title'] = strip_tags($this->unhtmlentities(strip_tags($this->asItems[$i]['title']))); //Fix for author if(!array_key_exists('author', $asItemTags)) { $sTagContent = $this->getPregMatch("'(.*?)'si", $asItem); if($sTagContent != '') $asItemTags['author'] = $sTagContent; } $this->addItem($asItemTags); } } public function addItem($asItem) { $this->asItems[] = $asItem; return count($this->asItems) - 1; } public function removeItem($iItemId) { $bExist = array_key_exists($iItemId, $this->asItems); if($bExist) unset($this->asItems[$iItemId]); return $bExist; } public function filterItems($sField, $sRegex) { $this->asItems = array_filter($this->asItems, function($asItem) use ($sField, $sRegex) { return preg_match($sRegex, $asItem[$sField]); }); } public function getItems() { return $this->asItems; } private function getGlobalPubDate() { $iGlobalPubDate = 0; foreach($this->asItems as $asItem) { $iItemPubDate = strtotime($asItem['pubDate']); if($iItemPubDate>$iGlobalPubDate) { $iGlobalPubDate = $iItemPubDate; } } return self::cleanRss(self::getDate($iGlobalPubDate)); } public function getFeed($bSetMime=true) { //Feed Channel $sRssChannel = array_key_exists('title', $this->asChannel)?self::getHtml($this->asChannel['title'], 'title'):''; $sRssChannel .= array_key_exists('link', $this->asChannel)?self::getHtml($this->asChannel['link'], 'link'):''; $sRssChannel .= array_key_exists('copyright', $this->asChannel)?self::getHtml($this->asChannel['copyright'], 'copyright'):''; $sRssChannel .= array_key_exists('description', $this->asChannel)?self::getHtml($this->asChannel['description'], 'description'):''; $sRssChannel .= array_key_exists('link', $this->asChannel)?self::getHtml('', 'atom:link', '', '', array('href'=>$this->asChannel['link'], 'rel'=>'self', 'type'=>'application/atom+xml'), true):''; $sRssChannel .= array_key_exists('language', $this->asChannel)?self::getHtml($this->asChannel['language'], 'language'):''; $sRssChannel .= self::getHtml($this->getGlobalPubDate(), 'lastBuildDate'); $sRssChannel .= self::getHtml('Lutran.fr RSS Feed Generator', 'generator'); $sRssChannel .= array_key_exists('webMaster', $this->asChannel)?self::getHtml($this->asChannel['webMaster'].' (Webmaster)', 'webMaster'):''; //Feed Items $asSortedItems = $this->rSortTimeMatrix($this->asItems, 'pubDate'); $sItems = implode("\n", array_map(array($this, 'buildItem'), $asSortedItems)); //Global Feed $sFeed = ''; $sFeed .= self::getHtml(self::getHtml($sRssChannel.$sItems, 'channel'), 'rss', '', '', array('version'=>'2.0', 'xmlns:atom'=>'http://www.w3.org/2005/Atom')); if($bSetMime) header('Content-type: application/rss+xml'); return $sFeed; } private static function getDate($sDate) { if(!is_numeric($sDate)) { $sDate = strtotime($sDate); } return date('r', $sDate); } private function buildItem($asItem) { $sRssItem = self::getHtml(self::cleanRss($asItem['title']), 'title'); $sRssItem .= array_key_exists('author', $asItem)?self::getHtml(self::cleanRss($asItem['author']), 'author'):''; $sRssItem .= array_key_exists('link', $asItem)?self::getHtml($asItem['link'], 'link'):''; $sRssItem .= array_key_exists('category', $asItem)?self::getHtml($asItem['category'], 'category'):''; $sRssItem .= self::getHtml(self::cleanRss($asItem['description']), 'description'); $sRssItem .= array_key_exists('pubDate', $asItem)?self::getHtml(self::getDate($asItem['pubDate']), 'pubDate'):''; $sRssItem .= array_key_exists('guid', $asItem)?self::getHtml($asItem['guid'], 'guid', '', '', array('isPermaLink'=>'true')):''; return self::getHtml($sRssItem, 'item'); } private function getPregMatch($pattern, $subject) { preg_match($pattern, $subject, $out); //if there is some result... process it and return it if(isset($out[1])) { //If code page is set convert character encoding to required //if ($this->cp != '') $out[1] = iconv($this->rsscp, $this->cp.'//TRANSLIT', $out[1]); return str_replace(array(''), '', trim($out[1])); } else return ''; } private static function getHtml($oText, $sTag, $sClass='', $sStyle='', $asExtraAttr=array(), $bAutoClose=false, $sInter='') { $sHtmlAttr = ''; if($sClass!='') { $asExtraAttr['class'] = $sClass; } if($sStyle!='') { $asExtraAttr['style'] = $sStyle; } foreach($asExtraAttr as $sAttrName=>$sAttrValue) { $sHtmlAttr .= ' '.$sAttrName.'="'.$sAttrValue.'"'; } if($bAutoClose) { $sHtml = self::encapsulate('', "\n".'<'.$sTag.$sHtmlAttr, ' />'); } else { $sHtml = self::encapsulate($oText, "\n".'<'.$sTag.$sHtmlAttr.'>', '', $sInter); } return $sHtml; } private static function cleanRss($oText) { $asForbiddenChars = array('&', '<', '>', '"', "'"); $asReplacementCode = array('&', '<', '>', '"', '''); if(!is_array($oText)) { return str_replace($asForbiddenChars, $asReplacementCode, $oText); } elseif(count($oText)>0) { $oTextKeys = array_map(array($this, 'cleanRss'), array_keys($oText)); $oTextValues = array_map(array($this, 'cleanRss'), array_values($oText)); return array_combine($oTextKeys, $oTextValues); } else { return $oText; } } private static function encapsulate($oText, $sPre='', $sPost=false, $sInter='') { if($sPost===false) { $sPost = $sPre; } if(is_array($oText)) { $oText = implode($sPost.$sInter.$sPre, $oText); } return $sPre.$oText.$sPost; } private static function rSortTimeMatrix($asMatrix, $sTimeCol) { $asResult = array(); foreach($asMatrix as $iRowId=>$asLine) $asKeys[$iRowId] = strtotime($asLine[$sTimeCol]); arsort($asKeys); foreach($asKeys as $iRowId=>$iTimeStamp) $asResult[$iRowId] = $asMatrix[$iRowId]; return $asResult; } }