From 62eec43980a3b85134606383996b81084d8fa32c Mon Sep 17 00:00:00 2001 From: logmanoriginal Date: Sat, 10 Sep 2016 20:41:11 +0200 Subject: [PATCH] [core] Apply common indentation All files are now using tabs for indentation --- caches/FileCache.php | 133 +++--- formats/AtomFormat.php | 113 ++--- formats/HtmlFormat.php | 81 ++-- formats/JsonFormat.php | 23 +- formats/MrssFormat.php | 106 ++--- formats/PlaintextFormat.php | 24 +- lib/Bridge.php | 160 +++---- lib/BridgeAbstract.php | 881 ++++++++++++++++++------------------ lib/BridgeInterface.php | 8 +- lib/Cache.php | 134 +++--- lib/CacheAbstract.php | 12 +- lib/CacheInterface.php | 8 +- lib/Exceptions.php | 97 ++-- lib/FeedExpander.php | 297 ++++++------ lib/Format.php | 103 ++--- lib/FormatAbstract.php | 168 +++---- lib/FormatInterface.php | 6 +- lib/HTMLUtils.php | 222 ++++++--- lib/RssBridge.php | 39 +- 19 files changed, 1365 insertions(+), 1250 deletions(-) diff --git a/caches/FileCache.php b/caches/FileCache.php index b6e04c3..a8ab88d 100644 --- a/caches/FileCache.php +++ b/caches/FileCache.php @@ -2,93 +2,88 @@ /** * Cache with file system */ -class FileCache extends CacheAbstract{ - protected $cacheDirCreated; // boolean to avoid always chck dir cache existance +class FileCache extends CacheAbstract { + protected $cacheDirCreated; // boolean to avoid always chck dir cache existance - public function loadData(){ - $this->isPrepareCache(); + public function loadData(){ + $this->isPrepareCache(); + $datas = unserialize(file_get_contents($this->getCacheFile())); + return $datas; + } - $datas = unserialize(file_get_contents($this->getCacheFile())); + public function saveData($datas){ + $this->isPrepareCache(); - return $datas; - } - - public function saveData($datas){ - $this->isPrepareCache(); - - //Re-encode datas to UTF-8 - //$datas = Cache::utf8_encode_deep($datas); - - $writeStream = file_put_contents($this->getCacheFile(), serialize($datas)); + //Re-encode datas to UTF-8 + //$datas = Cache::utf8_encode_deep($datas); + $writeStream = file_put_contents($this->getCacheFile(), serialize($datas)); if(!$writeStream) { - throw new \Exception("Cannot write the cache... Do you have the right permissions ?"); - } - return $this; - } + return $this; + } - public function getTime(){ - $this->isPrepareCache(); + public function getTime(){ + $this->isPrepareCache(); - $cacheFile = $this->getCacheFile(); - if( file_exists($cacheFile) ){ - return filemtime($cacheFile); - } + $cacheFile = $this->getCacheFile(); + if(file_exists($cacheFile)){ + return filemtime($cacheFile); + } - return false; - } + return false; + } - /** - * Cache is prepared ? - * Note : Cache name is based on request information, then cache must be prepare before use - * @return \Exception|true - */ - protected function isPrepareCache(){ - if( is_null($this->param) ){ - throw new \Exception('Please feed "prepare" method before try to load'); - } + /** + * Cache is prepared ? + * Note : Cache name is based on request information, then cache must be prepare before use + * @return \Exception|true + */ + protected function isPrepareCache(){ + if(is_null($this->param)){ + throw new \Exception('Please feed "prepare" method before try to load'); + } - return true; - } + return true; + } - /** - * Return cache path (and create if not exist) - * @return string Cache path - */ - protected function getCachePath(){ - $cacheDir = __DIR__ . '/../cache/'; // FIXME : configuration ? + /** + * Return cache path (and create if not exist) + * @return string Cache path + */ + protected function getCachePath(){ + $cacheDir = __DIR__ . '/../cache/'; // FIXME : configuration ? - // FIXME : implement recursive dir creation - if( is_null($this->cacheDirCreated) && !is_dir($cacheDir) ){ - $this->cacheDirCreated = true; + // FIXME : implement recursive dir creation + if(is_null($this->cacheDirCreated) && !is_dir($cacheDir)){ + $this->cacheDirCreated = true; - mkdir($cacheDir,0705); - chmod($cacheDir,0705); - } + mkdir($cacheDir,0705); + chmod($cacheDir,0705); + } - return $cacheDir; - } + return $cacheDir; + } - /** - * Get the file name use for cache store - * @return string Path to the file cache - */ - protected function getCacheFile(){ - return $this->getCachePath() . $this->getCacheName(); - } + /** + * Get the file name use for cache store + * @return string Path to the file cache + */ + protected function getCacheFile(){ + return $this->getCachePath() . $this->getCacheName(); + } - /** - * Determines file name for store the cache - * return string - */ - protected function getCacheName(){ - $this->isPrepareCache(); + /** + * Determines file name for store the cache + * return string + */ + protected function getCacheName(){ + $this->isPrepareCache(); - $stringToEncode = $_SERVER['REQUEST_URI'] . http_build_query($this->param); - $stringToEncode = preg_replace('/(\?|&)format=[^&]*/i', '$1', $stringToEncode); - return hash('sha1', $stringToEncode) . '.cache'; - } + $stringToEncode = $_SERVER['REQUEST_URI'] . http_build_query($this->param); + $stringToEncode = preg_replace('/(\?|&)format=[^&]*/i', '$1', $stringToEncode); + return hash('sha1', $stringToEncode) . '.cache'; + } } diff --git a/formats/AtomFormat.php b/formats/AtomFormat.php index 238dc88..fd2016b 100644 --- a/formats/AtomFormat.php +++ b/formats/AtomFormat.php @@ -1,79 +1,80 @@ xml_encode($_SERVER['REQUEST_URI']); + $serverRequestUri = $this->xml_encode($_SERVER['REQUEST_URI']); - $extraInfos = $this->getExtraInfos(); - $title = $this->xml_encode($extraInfos['name']); - $uri = !empty($extraInfos['uri']) ? $extraInfos['uri'] : 'https://github.com/sebsauvage/rss-bridge'; - $icon = $this->xml_encode('http://icons.better-idea.org/icon?url='. $uri .'&size=64'); - $uri = $this->xml_encode($uri); + $extraInfos = $this->getExtraInfos(); + $title = $this->xml_encode($extraInfos['name']); + $uri = !empty($extraInfos['uri']) ? $extraInfos['uri'] : 'https://github.com/sebsauvage/rss-bridge'; + $icon = $this->xml_encode('http://icons.better-idea.org/icon?url='. $uri .'&size=64'); + $uri = $this->xml_encode($uri); - $entries = ''; - foreach($this->getItems() as $item){ - $entryAuthor = isset($item['author']) ? $this->xml_encode($item['author']) : ''; - $entryTitle = isset($item['title']) ? $this->xml_encode($item['title']) : ''; - $entryUri = isset($item['uri']) ? $this->xml_encode($item['uri']) : ''; - $entryTimestamp = isset($item['timestamp']) ? $this->xml_encode(date(DATE_ATOM, $item['timestamp'])) : ''; - $entryContent = isset($item['content']) ? $this->xml_encode($this->sanitizeHtml($item['content'])) : ''; - $entries .= <<getItems() as $item){ + $entryAuthor = isset($item['author']) ? $this->xml_encode($item['author']) : ''; + $entryTitle = isset($item['title']) ? $this->xml_encode($item['title']) : ''; + $entryUri = isset($item['uri']) ? $this->xml_encode($item['uri']) : ''; + $entryTimestamp = isset($item['timestamp']) ? $this->xml_encode(date(DATE_ATOM, $item['timestamp'])) : ''; + $entryContent = isset($item['content']) ? $this->xml_encode($this->sanitizeHtml($item['content'])) : ''; + $entries .= << - - {$entryAuthor} - - <![CDATA[{$entryTitle}]]> - - {$entryUri} - {$entryTimestamp} - {$entryContent} - + + + {$entryAuthor} + + <![CDATA[{$entryTitle}]]> + + {$entryUri} + {$entryTimestamp} + {$entryContent} + EOD; - } + } - $feedTimestamp = date(DATE_ATOM, time()); + $feedTimestamp = date(DATE_ATOM, time()); - /* Data are prepared, now let's begin the "MAGIE !!!" */ - $toReturn = ''; - $toReturn .= << - {$title} - http{$https}://{$httpHost}{$httpInfo}/ - {$icon} - {$icon} - {$feedTimestamp} - - + {$title} + http{$https}://{$httpHost}{$httpInfo}/ + {$icon} + {$icon} + {$feedTimestamp} + + {$entries} EOD; - - // Remove invalid non-UTF8 characters - ini_set('mbstring.substitute_character', 'none'); - $toReturn= mb_convert_encoding($toReturn, 'UTF-8', 'UTF-8'); - return $toReturn; - } - public function display(){ - $this - ->setContentType('application/atom+xml; charset=UTF-8') - ->callContentType(); + // Remove invalid non-UTF8 characters + ini_set('mbstring.substitute_character', 'none'); + $toReturn = mb_convert_encoding($toReturn, 'UTF-8', 'UTF-8'); + return $toReturn; + } - return parent::display(); - } + public function display(){ + $this + ->setContentType('application/atom+xml; charset=UTF-8') + ->callContentType(); - private function xml_encode($text) { - return htmlspecialchars($text, ENT_XML1); - } + return parent::display(); + } + + private function xml_encode($text){ + return htmlspecialchars($text, ENT_XML1); + } } diff --git a/formats/HtmlFormat.php b/formats/HtmlFormat.php index d7c927b..1001acf 100644 --- a/formats/HtmlFormat.php +++ b/formats/HtmlFormat.php @@ -1,63 +1,62 @@ getExtraInfos(); - $title = htmlspecialchars($extraInfos['name']); - $uri = htmlspecialchars($extraInfos['uri']); - $atomquery = str_replace('format=Html', 'format=Atom', htmlentities($_SERVER['QUERY_STRING'])); - $mrssquery = str_replace('format=Html', 'format=Mrss', htmlentities($_SERVER['QUERY_STRING'])); + public function stringify(){ + $extraInfos = $this->getExtraInfos(); + $title = htmlspecialchars($extraInfos['name']); + $uri = htmlspecialchars($extraInfos['uri']); + $atomquery = str_replace('format=Html', 'format=Atom', htmlentities($_SERVER['QUERY_STRING'])); + $mrssquery = str_replace('format=Html', 'format=Mrss', htmlentities($_SERVER['QUERY_STRING'])); - $entries = ''; - foreach($this->getItems() as $item){ - $entryAuthor = isset($item['author']) ? '

by: ' . $item['author'] . '

' : ''; - $entryTitle = isset($item['title']) ? $this->sanitizeHtml(strip_tags($item['title'])) : ''; - $entryUri = isset($item['uri']) ? $item['uri'] : $uri; - $entryTimestamp = isset($item['timestamp']) ? '' : ''; - $entryContent = isset($item['content']) ? '
' . $this->sanitizeHtml($item['content']). '
' : ''; - $entries .= <<getItems() as $item){ + $entryAuthor = isset($item['author']) ? '

by: ' . $item['author'] . '

' : ''; + $entryTitle = isset($item['title']) ? $this->sanitizeHtml(strip_tags($item['title'])) : ''; + $entryUri = isset($item['uri']) ? $item['uri'] : $uri; + $entryTimestamp = isset($item['timestamp']) ? '' : ''; + $entryContent = isset($item['content']) ? '
' . $this->sanitizeHtml($item['content']). '
' : ''; + $entries .= << -

{$entryTitle}

- {$entryTimestamp} - {$entryAuthor} - {$entryContent} +

{$entryTitle}

+ {$entryTimestamp} + {$entryAuthor} + {$entryContent} EOD; - } + } - - /* Data are prepared, now let's begin the "MAGIE !!!" */ - $toReturn = << - - {$title} - - + + {$title} + + -

{$title}

- +

{$title}

+ {$entries} EOD; - return $toReturn; - } + return $toReturn; + } - public function display() { - $this - ->setContentType('text/html; charset=' . $this->getCharset()) - ->callContentType(); + public function display() { + $this + ->setContentType('text/html; charset=' . $this->getCharset()) + ->callContentType(); - return parent::display(); - } + return parent::display(); + } } diff --git a/formats/JsonFormat.php b/formats/JsonFormat.php index e173f23..ac6e450 100644 --- a/formats/JsonFormat.php +++ b/formats/JsonFormat.php @@ -3,19 +3,18 @@ * Json * Builds a JSON string from $this->items and return it to browser. */ -class JsonFormat extends FormatAbstract{ +class JsonFormat extends FormatAbstract { - public function stringify(){ - $items = $this->getItems(); + public function stringify(){ + $items = $this->getItems(); + return json_encode($items, JSON_PRETTY_PRINT); + } - return json_encode($items, JSON_PRETTY_PRINT); - } + public function display(){ + $this + ->setContentType('application/json') + ->callContentType(); - public function display(){ - $this - ->setContentType('application/json') - ->callContentType(); - - return parent::display(); - } + return parent::display(); + } } diff --git a/formats/MrssFormat.php b/formats/MrssFormat.php index ddbd5d3..fddbf0a 100644 --- a/formats/MrssFormat.php +++ b/formats/MrssFormat.php @@ -3,72 +3,72 @@ * Mrss * Documentation Source http://www.rssboard.org/media-rss */ -class MrssFormat extends FormatAbstract{ +class MrssFormat extends FormatAbstract { - public function stringify(){ - $https = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? 's' : ''; - $httpHost = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ''; - $httpInfo = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : ''; + public function stringify(){ + $https = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? 's' : ''; + $httpHost = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ''; + $httpInfo = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : ''; - $serverRequestUri = $this->xml_encode($_SERVER['REQUEST_URI']); + $serverRequestUri = $this->xml_encode($_SERVER['REQUEST_URI']); - $extraInfos = $this->getExtraInfos(); - $title = $this->xml_encode($extraInfos['name']); - $uri = $this->xml_encode(!empty($extraInfos['uri']) ? $extraInfos['uri'] : 'https://github.com/sebsauvage/rss-bridge'); - $icon = $this->xml_encode('http://icons.better-idea.org/icon?url='. $uri .'&size=64'); + $extraInfos = $this->getExtraInfos(); + $title = $this->xml_encode($extraInfos['name']); + $uri = $this->xml_encode(!empty($extraInfos['uri']) ? $extraInfos['uri'] : 'https://github.com/sebsauvage/rss-bridge'); + $icon = $this->xml_encode('http://icons.better-idea.org/icon?url='. $uri .'&size=64'); - $items = ''; - foreach($this->getItems() as $item){ - $itemAuthor = isset($item['author']) ? $this->xml_encode($item['author']) : ''; - $itemTitle = strip_tags(isset($item['title']) ? $this->xml_encode($item['title']) : ''); - $itemUri = isset($item['uri']) ? $this->xml_encode($item['uri']) : ''; - $itemTimestamp = isset($item['timestamp']) ? $this->xml_encode(date(DATE_RFC2822, $item['timestamp'])) : ''; - $itemContent = isset($item['content']) ? $this->xml_encode($this->sanitizeHtml($item['content'])) : ''; - $items .= <<getItems() as $item){ + $itemAuthor = isset($item['author']) ? $this->xml_encode($item['author']) : ''; + $itemTitle = strip_tags(isset($item['title']) ? $this->xml_encode($item['title']) : ''); + $itemUri = isset($item['uri']) ? $this->xml_encode($item['uri']) : ''; + $itemTimestamp = isset($item['timestamp']) ? $this->xml_encode(date(DATE_RFC2822, $item['timestamp'])) : ''; + $itemContent = isset($item['content']) ? $this->xml_encode($this->sanitizeHtml($item['content'])) : ''; + $items .= << - {$itemTitle} - {$itemUri} - {$itemUri} - {$itemTimestamp} - {$itemContent} - {$itemAuthor} - + + {$itemTitle} + {$itemUri} + {$itemUri} + {$itemTimestamp} + {$itemContent} + {$itemAuthor} + EOD; - } + } - /* Data are prepared, now let's begin the "MAGIE !!!" */ - $toReturn = ''; - $toReturn .= << - - {$title} - http{$https}://{$httpHost}{$httpInfo}/ - {$title} - - - - {$items} - + + {$title} + http{$https}://{$httpHost}{$httpInfo}/ + {$title} + + + + {$items} + EOD; - // Remove invalid non-UTF8 characters - ini_set('mbstring.substitute_character', 'none'); - $toReturn= mb_convert_encoding($toReturn, 'UTF-8', 'UTF-8'); - return $toReturn; - } + // Remove invalid non-UTF8 characters + ini_set('mbstring.substitute_character', 'none'); + $toReturn = mb_convert_encoding($toReturn, 'UTF-8', 'UTF-8'); + return $toReturn; + } - public function display(){ - $this - ->setContentType('application/rss+xml; charset=UTF-8') - ->callContentType(); + public function display(){ + $this + ->setContentType('application/rss+xml; charset=UTF-8') + ->callContentType(); - return parent::display(); - } + return parent::display(); + } - private function xml_encode($text) { - return htmlspecialchars($text, ENT_XML1); - } + private function xml_encode($text){ + return htmlspecialchars($text, ENT_XML1); + } } diff --git a/formats/PlaintextFormat.php b/formats/PlaintextFormat.php index e2cf0b9..593e938 100644 --- a/formats/PlaintextFormat.php +++ b/formats/PlaintextFormat.php @@ -3,18 +3,18 @@ * Plaintext * Returns $this->items as raw php data. */ -class PlaintextFormat extends FormatAbstract{ +class PlaintextFormat extends FormatAbstract { - public function stringify(){ - $items = $this->getItems(); - return print_r($items, true); - } + public function stringify(){ + $items = $this->getItems(); + return print_r($items, true); + } - public function display(){ - $this - ->setContentType('text/plain;charset=' . $this->getCharset()) - ->callContentType(); + public function display(){ + $this + ->setContentType('text/plain;charset=' . $this->getCharset()) + ->callContentType(); - return parent::display(); - } -} \ No newline at end of file + return parent::display(); + } +} diff --git a/lib/Bridge.php b/lib/Bridge.php index bacb77a..a964581 100644 --- a/lib/Bridge.php +++ b/lib/Bridge.php @@ -2,103 +2,105 @@ require_once(__DIR__ . '/BridgeInterface.php'); class Bridge { - static protected $dirBridge; + static protected $dirBridge; - public function __construct(){ - throw new \LogicException('Please use ' . __CLASS__ . '::create for new object.'); - } + public function __construct(){ + throw new \LogicException('Please use ' . __CLASS__ . '::create for new object.'); + } - /** - * Checks if a bridge is an instantiable bridge. - * @param string $nameBridge name of the bridge that you want to use - * @return true if it is an instantiable bridge, false otherwise. - */ - static public function isInstantiable($nameBridge){ - $re = new ReflectionClass($nameBridge); - return $re->IsInstantiable(); - } + /** + * Checks if a bridge is an instantiable bridge. + * @param string $nameBridge name of the bridge that you want to use + * @return true if it is an instantiable bridge, false otherwise. + */ + static public function isInstantiable($nameBridge){ + $re = new ReflectionClass($nameBridge); + return $re->IsInstantiable(); + } - /** - * Create a new bridge object - * @param string $nameBridge Defined bridge name you want use - * @return Bridge object dedicated - */ - static public function create($nameBridge){ - if(!preg_match('@^[A-Z][a-zA-Z0-9-]*$@', $nameBridge)){ - $message = <<returnError($message, 400); - } - - protected function returnServerError($message){ - $this->returnError($message, 500); - } - - /** - * Return items stored in the bridge - * @return mixed - */ - public function getItems(){ - return $this->items; - } - - protected function validateTextValue($value, $pattern = null){ - if(!is_null($pattern)){ - $filteredValue = filter_var($value, FILTER_VALIDATE_REGEXP, - array('options' => array( - 'regexp' => '/^' . $pattern . '$/' - )) - ); - } else { - $filteredValue = filter_var($value); - } - - if($filteredValue === false) - return null; - - return $filteredValue; - } - - protected function validateNumberValue($value){ - $filteredValue = filter_var($value, FILTER_VALIDATE_INT); - - if($filteredValue === false && !empty($value)) - return null; - - return $filteredValue; - } - - protected function validateCheckboxValue($value){ - $filteredValue = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); - - if(is_null($filteredValue)) - return null; - - return $filteredValue; - } - - protected function validateListValue($value, $expectedValues){ - $filteredValue = filter_var($value); - - if($filteredValue === false) - return null; - - if(!in_array($filteredValue, $expectedValues)){ // Check sub-values? - foreach($expectedValues as $subName => $subValue){ - if(is_array($subValue) && in_array($filteredValue, $subValue)) - return $filteredValue; - } - return null; - } - - return $filteredValue; - } - - protected function validateData(&$data){ - if(!is_array($data)) - return false; - - foreach($data as $name=>$value){ - $registered = false; - foreach(static::PARAMETERS as $context=>$set){ - if(array_key_exists($name,$set)){ - $registered = true; - if(!isset($set[$name]['type'])){ - $set[$name]['type']='text'; - } - - switch($set[$name]['type']){ - case 'number': - $data[$name] = $this->validateNumberValue($value); - break; - case 'checkbox': - $data[$name] = $this->validateCheckboxValue($value); - break; - case 'list': - $data[$name] = $this->validateListValue($value, $set[$name]['values']); - break; - default: - case 'text': - if(isset($set[$name]['pattern'])){ - $data[$name] = $this->validateTextValue($value, $set[$name]['pattern']); - } else { - $data[$name] = $this->validateTextValue($value); - } - break; - } - - if(is_null($data[$name])){ - echo 'Parameter \'' . $name . '\' is invalid!' . PHP_EOL; - return false; - } - } - } - - if(!$registered) - return false; - } - - return true; - } - - protected function setInputs(array $inputs, $queriedContext){ - // Import and assign all inputs to their context - foreach($inputs as $name => $value){ - foreach(static::PARAMETERS as $context => $set){ - if(array_key_exists($name, static::PARAMETERS[$context])){ - $this->inputs[$context][$name]['value'] = $value; - } - } - } - - // Apply default values to missing data - $contexts = array($queriedContext); - if(array_key_exists('global', static::PARAMETERS)){ - $contexts[] = 'global'; - } - - foreach($contexts as $context){ - foreach(static::PARAMETERS[$context] as $name => $properties){ - if(isset($this->inputs[$context][$name]['value'])){ - continue; - } - - $type = isset($properties['type']) ? $properties['type'] : 'text'; - - switch($type){ - case 'checkbox': - if(!isset($properties['defaultValue'])){ - $this->inputs[$context][$name]['value'] = false; - } else { - $this->inputs[$context][$name]['value'] = $properties['defaultValue']; - } - break; - case 'list': - if(!isset($properties['defaultValue'])){ - $firstItem = reset($properties['values']); - if(is_array($firstItem)){ - $firstItem = reset($firstItem); - } - $this->inputs[$context][$name]['value'] = $firstItem; - } else { - $this->inputs[$context][$name]['value'] = $properties['defaultValue']; - } - break; - default: - if(isset($properties['defaultValue'])){ - $this->inputs[$context][$name]['value'] = $properties['defaultValue']; - } - break; - } - } - } - - // Copy global parameter values to the guessed context - if(array_key_exists('global', static::PARAMETERS)){ - foreach(static::PARAMETERS['global'] as $name => $properties){ - if(isset($inputs[$name])){ - $value = $inputs[$name]; - } elseif (isset($properties['value'])){ - $value = $properties['value']; - } else { - continue; - } - $this->inputs[$queriedContext][$name]['value'] = $value; - } - } - - // Only keep guessed context parameters values - if(isset($this->inputs[$queriedContext])){ - $this->inputs = array($queriedContext => $this->inputs[$queriedContext]); - } else { - $this->inputs = array(); - } - } - - protected function getQueriedContext(array $inputs){ - $queriedContexts=array(); - foreach(static::PARAMETERS as $context=>$set){ - $queriedContexts[$context]=null; - foreach($set as $id=>$properties){ - if(isset($inputs[$id]) && !empty($inputs[$id])){ - $queriedContexts[$context]=true; - }elseif(isset($properties['required']) && - $properties['required']===true){ - $queriedContexts[$context]=false; - break; - } - } - } - - if(array_key_exists('global',static::PARAMETERS) && - $queriedContexts['global']===false){ - return null; - } - unset($queriedContexts['global']); - - switch(array_sum($queriedContexts)){ - case 0: - foreach($queriedContexts as $context=>$queried){ - if (is_null($queried)){ - return $context; - } - } - return null; - case 1: return array_search(true,$queriedContexts); - default: return false; - } - } - - /** - * Defined datas with parameters depending choose bridge - * Note : you can define a cache with "setCache" - * @param array array with expected bridge paramters - */ - public function setDatas(array $inputs){ - if(!is_null($this->cache)){ - $this->cache->prepare($inputs); - $time = $this->cache->getTime(); - if($time !== false && (time() - $this->getCacheDuration() < $time)){ - $this->items = $this->cache->loadData(); - return; - } - } - - if(empty(static::PARAMETERS)){ - if(!empty($inputs)){ - $this->returnClientError('Invalid parameters value(s)'); - } - - $this->collectData(); - if(!is_null($this->cache)){ - $this->cache->saveData($this->getItems()); - } - return; - } - - if(!$this->validateData($inputs)){ - $this->returnClientError('Invalid parameters value(s)'); - } - - // Guess the paramter context from input data - $this->queriedContext = $this->getQueriedContext($inputs); - if(is_null($this->queriedContext)){ - $this->returnClientError('Required parameter(s) missing'); - } elseif($this->queriedContext === false){ - $this->returnClientError('Mixed context parameters'); - } - - $this->setInputs($inputs, $this->queriedContext); - - $this->collectData(); - - if(!is_null($this->cache)){ - $this->cache->saveData($this->getItems()); - } - } - - function getInput($input){ - if(!isset($this->inputs[$this->queriedContext][$input]['value'])){ - return null; - } - return $this->inputs[$this->queriedContext][$input]['value']; - } - - public function getName(){ - return static::NAME; - } - - public function getURI(){ - return static::URI; - } - - public function getCacheDuration(){ - return 3600; - } - - public function setCache(\CacheAbstract $cache){ - $this->cache = $cache; - } - - public function debugMessage($text){ - if(!file_exists('DEBUG')) { - return; - } - - $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3); - $calling = $backtrace[2]; - $message = $calling['file'] . ':' - . $calling['line'] . ' class ' - . get_class($this) . '->' - . $calling['function'] . ' - ' - . $text; - - error_log($message); - } - - protected function getContents($url - , $use_include_path = false - , $context = null - , $offset = 0 - , $maxlen = null){ - $contextOptions = array( - 'http' => array( - 'user_agent' => ini_get('user_agent') - ), - ); - - if(defined('PROXY_URL') && $this->useProxy){ - $contextOptions['http']['proxy'] = PROXY_URL; - $contextOptions['http']['request_fulluri'] = true; - - if(is_null($context)){ - $context = stream_context_create($contextOptions); - } else { - $prevContext=$context; - if(!stream_context_set_option($context, $contextOptions)){ - $context = $prevContext; - } - } - } - - if(is_null($maxlen)){ - $content = @file_get_contents($url, $use_include_path, $context, $offset); - } else { - $content = @file_get_contents($url, $use_include_path, $context, $offset, $maxlen); - } - - if($content === false) - $this->debugMessage('Cant\'t download ' . $url); - - return $content; - } - - protected function getSimpleHTMLDOM($url - , $use_include_path = false - , $context = null - , $offset = 0 - , $maxLen = null - , $lowercase = true - , $forceTagsClosed = true - , $target_charset = DEFAULT_TARGET_CHARSET - , $stripRN = true - , $defaultBRText = DEFAULT_BR_TEXT - , $defaultSpanText = DEFAULT_SPAN_TEXT){ - $content = $this->getContents($url, $use_include_path, $context, $offset, $maxLen); - return str_get_html($content - , $lowercase - , $forceTagsClosed - , $target_charset - , $stripRN - , $defaultBRText - , $defaultSpanText); - } - - /** - * Maintain locally cached versions of pages to avoid multiple downloads. - * @param url url to cache - * @param duration duration of the cache file in seconds (default: 24h/86400s) - * @return content of the file as string - */ - public function getSimpleHTMLDOMCached($url - , $duration = 86400 - , $use_include_path = false - , $context = null - , $offset = 0 - , $maxLen = null - , $lowercase = true - , $forceTagsClosed = true - , $target_charset = DEFAULT_TARGET_CHARSET - , $stripRN = true - , $defaultBRText = DEFAULT_BR_TEXT - , $defaultSpanText = DEFAULT_SPAN_TEXT){ - $this->debugMessage('Caching url ' . $url . ', duration ' . $duration); - - $filepath = __DIR__ . '/../cache/pages/' . sha1($url) . '.cache'; - $this->debugMessage('Cache file ' . $filepath); - - if(file_exists($filepath) && filectime($filepath) < time() - $duration){ - unlink ($filepath); - $this->debugMessage('Cached file deleted: ' . $filepath); - } - - if(file_exists($filepath)){ - $this->debugMessage('Loading cached file ' . $filepath); - touch($filepath); - $content = file_get_contents($filepath); - } else { - $this->debugMessage('Caching ' . $url . ' to ' . $filepath); - $dir = substr($filepath, 0, strrpos($filepath, '/')); - - if(!is_dir($dir)){ - $this->debugMessage('Creating directory ' . $dir); - mkdir($dir, 0777, true); - } - - $content = $this->getContents($url, $use_include_path, $context, $offset, $maxLen); - if($content !== false){ - file_put_contents($filepath, $content); - } - } - - return str_get_html($content - , $lowercase - , $forceTagsClosed - , $target_charset - , $stripRN - , $defaultBRText - , $defaultSpanText); - } + const NAME = 'Unnamed bridge'; + const URI = ''; + const DESCRIPTION = 'No description provided'; + const MAINTAINER = 'No maintainer'; + const PARAMETERS = array(); + + public $useProxy = true; + + protected $cache; + protected $items = array(); + protected $inputs = array(); + protected $queriedContext = ''; + + protected function returnError($message, $code){ + throw new \HttpException($message, $code); + } + + protected function returnClientError($message){ + $this->returnError($message, 400); + } + + protected function returnServerError($message){ + $this->returnError($message, 500); + } + + /** + * Return items stored in the bridge + * @return mixed + */ + public function getItems(){ + return $this->items; + } + + protected function validateTextValue($value, $pattern = null){ + if(!is_null($pattern)){ + $filteredValue = filter_var($value + , FILTER_VALIDATE_REGEXP + , array('options' => array( + 'regexp' => '/^' . $pattern . '$/' + )) + ); + } else { + $filteredValue = filter_var($value); + } + + if($filteredValue === false) + return null; + + return $filteredValue; + } + + protected function validateNumberValue($value){ + $filteredValue = filter_var($value, FILTER_VALIDATE_INT); + + if($filteredValue === false && !empty($value)) + return null; + + return $filteredValue; + } + + protected function validateCheckboxValue($value){ + $filteredValue = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); + + if(is_null($filteredValue)) + return null; + + return $filteredValue; + } + + protected function validateListValue($value, $expectedValues){ + $filteredValue = filter_var($value); + + if($filteredValue === false) + return null; + + if(!in_array($filteredValue, $expectedValues)){ // Check sub-values? + foreach($expectedValues as $subName => $subValue){ + if(is_array($subValue) && in_array($filteredValue, $subValue)) + return $filteredValue; + } + return null; + } + + return $filteredValue; + } + + protected function validateData(&$data){ + if(!is_array($data)) + return false; + + foreach($data as $name => $value){ + $registered = false; + foreach(static::PARAMETERS as $context => $set){ + if(array_key_exists($name, $set)){ + $registered = true; + if(!isset($set[$name]['type'])){ + $set[$name]['type'] = 'text'; + } + + switch($set[$name]['type']){ + case 'number': + $data[$name] = $this->validateNumberValue($value); + break; + case 'checkbox': + $data[$name] = $this->validateCheckboxValue($value); + break; + case 'list': + $data[$name] = $this->validateListValue($value, $set[$name]['values']); + break; + default: + case 'text': + if(isset($set[$name]['pattern'])){ + $data[$name] = $this->validateTextValue($value, $set[$name]['pattern']); + } else { + $data[$name] = $this->validateTextValue($value); + } + break; + } + + if(is_null($data[$name])){ + echo 'Parameter \'' . $name . '\' is invalid!' . PHP_EOL; + return false; + } + } + } + + if(!$registered) + return false; + } + + return true; + } + + protected function setInputs(array $inputs, $queriedContext){ + // Import and assign all inputs to their context + foreach($inputs as $name => $value){ + foreach(static::PARAMETERS as $context => $set){ + if(array_key_exists($name, static::PARAMETERS[$context])){ + $this->inputs[$context][$name]['value'] = $value; + } + } + } + + // Apply default values to missing data + $contexts = array($queriedContext); + if(array_key_exists('global', static::PARAMETERS)){ + $contexts[] = 'global'; + } + + foreach($contexts as $context){ + foreach(static::PARAMETERS[$context] as $name => $properties){ + if(isset($this->inputs[$context][$name]['value'])){ + continue; + } + + $type = isset($properties['type']) ? $properties['type'] : 'text'; + + switch($type){ + case 'checkbox': + if(!isset($properties['defaultValue'])){ + $this->inputs[$context][$name]['value'] = false; + } else { + $this->inputs[$context][$name]['value'] = $properties['defaultValue']; + } + break; + case 'list': + if(!isset($properties['defaultValue'])){ + $firstItem = reset($properties['values']); + if(is_array($firstItem)){ + $firstItem = reset($firstItem); + } + $this->inputs[$context][$name]['value'] = $firstItem; + } else { + $this->inputs[$context][$name]['value'] = $properties['defaultValue']; + } + break; + default: + if(isset($properties['defaultValue'])){ + $this->inputs[$context][$name]['value'] = $properties['defaultValue']; + } + break; + } + } + } + + // Copy global parameter values to the guessed context + if(array_key_exists('global', static::PARAMETERS)){ + foreach(static::PARAMETERS['global'] as $name => $properties){ + if(isset($inputs[$name])){ + $value = $inputs[$name]; + } elseif (isset($properties['value'])){ + $value = $properties['value']; + } else { + continue; + } + $this->inputs[$queriedContext][$name]['value'] = $value; + } + } + + // Only keep guessed context parameters values + if(isset($this->inputs[$queriedContext])){ + $this->inputs = array($queriedContext => $this->inputs[$queriedContext]); + } else { + $this->inputs = array(); + } + } + + protected function getQueriedContext(array $inputs){ + $queriedContexts = array(); + foreach(static::PARAMETERS as $context => $set){ + $queriedContexts[$context] = null; + foreach($set as $id => $properties){ + if(isset($inputs[$id]) && !empty($inputs[$id])){ + $queriedContexts[$context] = true; + } elseif(isset($properties['required']) + && $properties['required'] === true){ + $queriedContexts[$context] = false; + break; + } + } + } + + if(array_key_exists('global', static::PARAMETERS) + && $queriedContexts['global'] === false){ + return null; + } + unset($queriedContexts['global']); + + switch(array_sum($queriedContexts)){ + case 0: + foreach($queriedContexts as $context => $queried){ + if (is_null($queried)){ + return $context; + } + } + return null; + case 1: return array_search(true, $queriedContexts); + default: return false; + } + } + + /** + * Defined datas with parameters depending choose bridge + * Note : you can define a cache with "setCache" + * @param array array with expected bridge paramters + */ + public function setDatas(array $inputs){ + if(!is_null($this->cache)){ + $this->cache->prepare($inputs); + $time = $this->cache->getTime(); + if($time !== false && (time() - $this->getCacheDuration() < $time)){ + $this->items = $this->cache->loadData(); + return; + } + } + + if(empty(static::PARAMETERS)){ + if(!empty($inputs)){ + $this->returnClientError('Invalid parameters value(s)'); + } + + $this->collectData(); + if(!is_null($this->cache)){ + $this->cache->saveData($this->getItems()); + } + return; + } + + if(!$this->validateData($inputs)){ + $this->returnClientError('Invalid parameters value(s)'); + } + + // Guess the paramter context from input data + $this->queriedContext = $this->getQueriedContext($inputs); + if(is_null($this->queriedContext)){ + $this->returnClientError('Required parameter(s) missing'); + } elseif($this->queriedContext === false){ + $this->returnClientError('Mixed context parameters'); + } + + $this->setInputs($inputs, $this->queriedContext); + + $this->collectData(); + + if(!is_null($this->cache)){ + $this->cache->saveData($this->getItems()); + } + } + + function getInput($input){ + if(!isset($this->inputs[$this->queriedContext][$input]['value'])){ + return null; + } + return $this->inputs[$this->queriedContext][$input]['value']; + } + + public function getName(){ + return static::NAME; + } + + public function getURI(){ + return static::URI; + } + + public function getCacheDuration(){ + return 3600; + } + + public function setCache(\CacheAbstract $cache){ + $this->cache = $cache; + } + + public function debugMessage($text){ + if(!file_exists('DEBUG')) { + return; + } + + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3); + $calling = $backtrace[2]; + $message = $calling['file'] . ':' + . $calling['line'] . ' class ' + . get_class($this) . '->' + . $calling['function'] . ' - ' + . $text; + + error_log($message); + } + + protected function getContents($url + , $use_include_path = false + , $context = null + , $offset = 0 + , $maxlen = null){ + $contextOptions = array( + 'http' => array( + 'user_agent' => ini_get('user_agent') + ) + ); + + if(defined('PROXY_URL') && $this->useProxy){ + $contextOptions['http']['proxy'] = PROXY_URL; + $contextOptions['http']['request_fulluri'] = true; + + if(is_null($context)){ + $context = stream_context_create($contextOptions); + } else { + $prevContext=$context; + if(!stream_context_set_option($context, $contextOptions)){ + $context = $prevContext; + } + } + } + + if(is_null($maxlen)){ + $content = @file_get_contents($url, $use_include_path, $context, $offset); + } else { + $content = @file_get_contents($url, $use_include_path, $context, $offset, $maxlen); + } + + if($content === false) + $this->debugMessage('Cant\'t download ' . $url); + + return $content; + } + + protected function getSimpleHTMLDOM($url + , $use_include_path = false + , $context = null + , $offset = 0 + , $maxLen = null + , $lowercase = true + , $forceTagsClosed = true + , $target_charset = DEFAULT_TARGET_CHARSET + , $stripRN = true + , $defaultBRText = DEFAULT_BR_TEXT + , $defaultSpanText = DEFAULT_SPAN_TEXT){ + $content = $this->getContents($url, $use_include_path, $context, $offset, $maxLen); + return str_get_html($content + , $lowercase + , $forceTagsClosed + , $target_charset + , $stripRN + , $defaultBRText + , $defaultSpanText); + } + + /** + * Maintain locally cached versions of pages to avoid multiple downloads. + * @param url url to cache + * @param duration duration of the cache file in seconds (default: 24h/86400s) + * @return content of the file as string + */ + public function getSimpleHTMLDOMCached($url + , $duration = 86400 + , $use_include_path = false + , $context = null + , $offset = 0 + , $maxLen = null + , $lowercase = true + , $forceTagsClosed = true + , $target_charset = DEFAULT_TARGET_CHARSET + , $stripRN = true + , $defaultBRText = DEFAULT_BR_TEXT + , $defaultSpanText = DEFAULT_SPAN_TEXT){ + $this->debugMessage('Caching url ' . $url . ', duration ' . $duration); + + $filepath = __DIR__ . '/../cache/pages/' . sha1($url) . '.cache'; + $this->debugMessage('Cache file ' . $filepath); + + if(file_exists($filepath) && filectime($filepath) < time() - $duration){ + unlink ($filepath); + $this->debugMessage('Cached file deleted: ' . $filepath); + } + + if(file_exists($filepath)){ + $this->debugMessage('Loading cached file ' . $filepath); + touch($filepath); + $content = file_get_contents($filepath); + } else { + $this->debugMessage('Caching ' . $url . ' to ' . $filepath); + $dir = substr($filepath, 0, strrpos($filepath, '/')); + + if(!is_dir($dir)){ + $this->debugMessage('Creating directory ' . $dir); + mkdir($dir, 0777, true); + } + + $content = $this->getContents($url, $use_include_path, $context, $offset, $maxLen); + if($content !== false){ + file_put_contents($filepath, $content); + } + } + + return str_get_html($content + , $lowercase + , $forceTagsClosed + , $target_charset + , $stripRN + , $defaultBRText + , $defaultSpanText); + } } diff --git a/lib/BridgeInterface.php b/lib/BridgeInterface.php index 5054d10..a63b63f 100644 --- a/lib/BridgeInterface.php +++ b/lib/BridgeInterface.php @@ -1,7 +1,7 @@ $var); - } - } - } + foreach($vars as $var){ + Cache::utf8_encode_deep($input->$var); + } + } + } - - static public function purge() { - $cacheTimeLimit = time() - 60*60*24 ; + + static public function purge(){ + $cacheTimeLimit = time() - 60*60*24; $cachePath = 'cache'; - if(file_exists($cachePath)) { - $cacheIterator = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator($cachePath), - RecursiveIteratorIterator::CHILD_FIRST - ); - foreach ($cacheIterator as $cacheFile) { - if (in_array($cacheFile->getBasename(), array('.', '..'))) - continue; - elseif ($cacheFile->isFile()) { - if( filemtime($cacheFile->getPathname()) < $cacheTimeLimit ) - unlink( $cacheFile->getPathname() ); - } - } + if(file_exists($cachePath)){ + $cacheIterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($cachePath), + RecursiveIteratorIterator::CHILD_FIRST + ); + + foreach($cacheIterator as $cacheFile){ + if(in_array($cacheFile->getBasename(), array('.', '..'))) + continue; + elseif($cacheFile->isFile()){ + if(filemtime($cacheFile->getPathname()) < $cacheTimeLimit) + unlink($cacheFile->getPathname()); + } + } } } diff --git a/lib/CacheAbstract.php b/lib/CacheAbstract.php index 98608b2..e6c39d8 100644 --- a/lib/CacheAbstract.php +++ b/lib/CacheAbstract.php @@ -1,11 +1,11 @@ param = $param; + public function prepare(array $param){ + $this->param = $param; - return $this; - } + return $this; + } } diff --git a/lib/CacheInterface.php b/lib/CacheInterface.php index 89d78ec..4c59df3 100644 --- a/lib/CacheInterface.php +++ b/lib/CacheInterface.php @@ -1,6 +1,6 @@ 'OK', - 201 => 'Created', - 202 => 'Accepted', - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Moved Temporarily', - 307 => 'Temporary Redirect', - 310 => 'Too many Redirects', - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Time-out', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested range unsatisfiable', - 417 => 'Expectation failed', - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Time-out', - 508 => 'Loop detected', - ); - } + /** + * List of common Http code + */ + static public function getCodes(){ + return array( + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Moved Temporarily', + 307 => 'Temporary Redirect', + 310 => 'Too many Redirects', + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Time-out', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested range unsatisfiable', + 417 => 'Expectation failed', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Time-out', + 508 => 'Loop detected', + ); + } } diff --git a/lib/FeedExpander.php b/lib/FeedExpander.php index 5566f7c..f0ec4c6 100644 --- a/lib/FeedExpander.php +++ b/lib/FeedExpander.php @@ -2,175 +2,178 @@ require_once(__DIR__ . '/BridgeInterface.php'); abstract class FeedExpander extends BridgeAbstract { - private $name; - private $uri; - private $description; + private $name; + private $uri; + private $description; - public function collectExpandableDatas($url, $maxItems = -1){ - if(empty($url)){ - $this->returnServerError('There is no $url for this RSS expander'); - } + public function collectExpandableDatas($url, $maxItems = -1){ + if(empty($url)){ + $this->returnServerError('There is no $url for this RSS expander'); + } - $this->debugMessage('Loading from ' . $url); + $this->debugMessage('Loading from ' . $url); - /* Notice we do not use cache here on purpose: - * we want a fresh view of the RSS stream each time - */ - $content = $this->getContents($url) - or $this->returnServerError('Could not request ' . $url); - $rssContent = simplexml_load_string($content); + /* Notice we do not use cache here on purpose: + * we want a fresh view of the RSS stream each time + */ + $content = $this->getContents($url) + or $this->returnServerError('Could not request ' . $url); + $rssContent = simplexml_load_string($content); - $this->debugMessage('Detecting feed format/version'); - if(isset($rssContent->channel[0])){ - $this->debugMessage('Detected RSS format'); - if(isset($rssContent->item[0])){ - $this->debugMessage('Detected RSS 1.0 format'); - $this->collect_RSS_1_0_data($rssContent, $maxItems); - } else { - $this->debugMessage('Detected RSS 0.9x or 2.0 format'); - $this->collect_RSS_2_0_data($rssContent, $maxItems); - } - } elseif(isset($rssContent->entry[0])){ - $this->debugMessage('Detected ATOM format'); - $this->collect_ATOM_data($rssContent, $maxItems); - } else { - $this->debugMessage('Unknown feed format/version'); - $this->returnServerError('The feed format is unknown!'); - } - } + $this->debugMessage('Detecting feed format/version'); + if(isset($rssContent->channel[0])){ + $this->debugMessage('Detected RSS format'); + if(isset($rssContent->item[0])){ + $this->debugMessage('Detected RSS 1.0 format'); + $this->collect_RSS_1_0_data($rssContent, $maxItems); + } else { + $this->debugMessage('Detected RSS 0.9x or 2.0 format'); + $this->collect_RSS_2_0_data($rssContent, $maxItems); + } + } elseif(isset($rssContent->entry[0])){ + $this->debugMessage('Detected ATOM format'); + $this->collect_ATOM_data($rssContent, $maxItems); + } else { + $this->debugMessage('Unknown feed format/version'); + $this->returnServerError('The feed format is unknown!'); + } + } - protected function collect_RSS_1_0_data($rssContent, $maxItems){ - $this->load_RSS_2_0_feed_data($rssContent->channel[0]); - foreach($rssContent->item as $item){ - $this->debugMessage('parsing item ' . var_export($item, true)); - $this->items[] = $this->parseItem($item); - if($maxItems !== -1 && count($this->items) >= $maxItems) break; - } - } + protected function collect_RSS_1_0_data($rssContent, $maxItems){ + $this->load_RSS_2_0_feed_data($rssContent->channel[0]); + foreach($rssContent->item as $item){ + $this->debugMessage('parsing item ' . var_export($item, true)); + $this->items[] = $this->parseItem($item); + if($maxItems !== -1 && count($this->items) >= $maxItems) break; + } + } - protected function collect_RSS_2_0_data($rssContent, $maxItems){ - $rssContent = $rssContent->channel[0]; - $this->debugMessage('RSS content is ===========\n' . var_export($rssContent, true) . '==========='); - $this->load_RSS_2_0_feed_data($rssContent); - foreach($rssContent->item as $item){ - $this->debugMessage('parsing item ' . var_export($item, true)); - $this->items[] = $this->parseItem($item); - if($maxItems !== -1 && count($this->items) >= $maxItems) break; - } - } + protected function collect_RSS_2_0_data($rssContent, $maxItems){ + $rssContent = $rssContent->channel[0]; + $this->debugMessage('RSS content is ===========\n' + . var_export($rssContent, true) + . '==========='); - protected function collect_ATOM_data($content, $maxItems){ - $this->load_ATOM_feed_data($content); - foreach($content->entry as $item){ - $this->debugMessage('parsing item ' . var_export($item, true)); - $this->items[] = $this->parseItem($item); - if($maxItems !== -1 && count($this->items) >= $maxItems) break; - } - } + $this->load_RSS_2_0_feed_data($rssContent); + foreach($rssContent->item as $item){ + $this->debugMessage('parsing item ' . var_export($item, true)); + $this->items[] = $this->parseItem($item); + if($maxItems !== -1 && count($this->items) >= $maxItems) break; + } + } - protected function RSS_2_0_time_to_timestamp($item){ - return DateTime::createFromFormat('D, d M Y H:i:s e', $item->pubDate)->getTimestamp(); - } + protected function collect_ATOM_data($content, $maxItems){ + $this->load_ATOM_feed_data($content); + foreach($content->entry as $item){ + $this->debugMessage('parsing item ' . var_export($item, true)); + $this->items[] = $this->parseItem($item); + if($maxItems !== -1 && count($this->items) >= $maxItems) break; + } + } - // TODO set title, link, description, language, and so on - protected function load_RSS_2_0_feed_data($rssContent){ - $this->name = trim($rssContent->title); - $this->uri = trim($rssContent->link); - $this->description = trim($rssContent->description); - } + protected function RSS_2_0_time_to_timestamp($item){ + return DateTime::createFromFormat('D, d M Y H:i:s e', $item->pubDate)->getTimestamp(); + } - protected function load_ATOM_feed_data($content){ - $this->name = $content->title; + // TODO set title, link, description, language, and so on + protected function load_RSS_2_0_feed_data($rssContent){ + $this->name = trim($rssContent->title); + $this->uri = trim($rssContent->link); + $this->description = trim($rssContent->description); + } - // Find best link (only one, or first of 'alternate') - if(!isset($content->link)){ - $this->uri = ''; - } elseif (count($content->link) === 1){ - $this->uri = $content->link[0]['href']; - } else { - $this->uri = ''; - foreach($content->link as $link){ - if(strtolower($link['rel']) === 'alternate'){ - $this->uri = $link['href']; - break; - } - } - } + protected function load_ATOM_feed_data($content){ + $this->name = $content->title; - if(isset($content->subtitle)) - $this->description = $content->subtitle; - } + // Find best link (only one, or first of 'alternate') + if(!isset($content->link)){ + $this->uri = ''; + } elseif (count($content->link) === 1){ + $this->uri = $content->link[0]['href']; + } else { + $this->uri = ''; + foreach($content->link as $link){ + if(strtolower($link['rel']) === 'alternate'){ + $this->uri = $link['href']; + break; + } + } + } - protected function parseATOMItem($feedItem){ - $item = array(); - if(isset($feedItem->id)) $item['uri'] = $feedItem->id; - if(isset($feedItem->title)) $item['title'] = $feedItem->title; - if(isset($feedItem->updated)) $item['timestamp'] = strtotime($feedItem->updated); - if(isset($feedItem->author)) $item['author'] = $feedItem->author->name; - if(isset($feedItem->content)) $item['content'] = $feedItem->content; - return $item; - } + if(isset($content->subtitle)) + $this->description = $content->subtitle; + } - protected function parseRSS_0_9_1_Item($feedItem){ - $item = array(); - if(isset($feedItem->link)) $item['uri'] = $feedItem->link; - if(isset($feedItem->title)) $item['title'] = $feedItem->title; - // rss 0.91 doesn't support timestamps - // rss 0.91 doesn't support authors - if(isset($feedItem->description)) $item['content'] = $feedItem->description; - return $item; - } + protected function parseATOMItem($feedItem){ + $item = array(); + if(isset($feedItem->id)) $item['uri'] = $feedItem->id; + if(isset($feedItem->title)) $item['title'] = $feedItem->title; + if(isset($feedItem->updated)) $item['timestamp'] = strtotime($feedItem->updated); + if(isset($feedItem->author)) $item['author'] = $feedItem->author->name; + if(isset($feedItem->content)) $item['content'] = $feedItem->content; + return $item; + } - protected function parseRSS_1_0_Item($feedItem){ - // 1.0 adds optional elements around the 0.91 standard - $item = $this->parseRSS_0_9_1_Item($feedItem); + protected function parseRSS_0_9_1_Item($feedItem){ + $item = array(); + if(isset($feedItem->link)) $item['uri'] = $feedItem->link; + if(isset($feedItem->title)) $item['title'] = $feedItem->title; + // rss 0.91 doesn't support timestamps + // rss 0.91 doesn't support authors + if(isset($feedItem->description)) $item['content'] = $feedItem->description; + return $item; + } - $namespaces = $feedItem->getNamespaces(true); - if(isset($namespaces['dc'])){ - $dc = $feedItem->children($namespaces['dc']); - if(isset($dc->date)) $item['timestamp'] = strtotime($dc->date); - if(isset($dc->creator)) $item['author'] = $dc->creator; - } + protected function parseRSS_1_0_Item($feedItem){ + // 1.0 adds optional elements around the 0.91 standard + $item = $this->parseRSS_0_9_1_Item($feedItem); - return $item; - } + $namespaces = $feedItem->getNamespaces(true); + if(isset($namespaces['dc'])){ + $dc = $feedItem->children($namespaces['dc']); + if(isset($dc->date)) $item['timestamp'] = strtotime($dc->date); + if(isset($dc->creator)) $item['author'] = $dc->creator; + } - protected function parseRSS_2_0_Item($feedItem){ - // Primary data is compatible to 0.91 with some additional data - $item = $this->parseRSS_0_9_1_Item($feedItem); + return $item; + } - $namespaces = $feedItem->getNamespaces(true); - if(isset($namespaces['dc'])) $dc = $feedItem->children($namespaces['dc']); + protected function parseRSS_2_0_Item($feedItem){ + // Primary data is compatible to 0.91 with some additional data + $item = $this->parseRSS_0_9_1_Item($feedItem); - if(isset($feedItem->pubDate)){ - $item['timestamp'] = strtotime($feedItem->pubDate); - } elseif(isset($dc->date)){ - $item['timestamp'] = strtotime($dc->date); - } - if(isset($feedItem->author)){ - $item['author'] = $feedItem->author; - } elseif(isset($dc->creator)){ - $item['author'] = $dc->creator; - } - return $item; - } + $namespaces = $feedItem->getNamespaces(true); + if(isset($namespaces['dc'])) $dc = $feedItem->children($namespaces['dc']); - /** - * Method should return, from a source RSS item given by lastRSS, one of our Items objects - * @param $item the input rss item - * @return a RSS-Bridge Item, with (hopefully) the whole content) - */ - abstract protected function parseItem($item); + if(isset($feedItem->pubDate)){ + $item['timestamp'] = strtotime($feedItem->pubDate); + } elseif(isset($dc->date)){ + $item['timestamp'] = strtotime($dc->date); + } + if(isset($feedItem->author)){ + $item['author'] = $feedItem->author; + } elseif(isset($dc->creator)){ + $item['author'] = $dc->creator; + } + return $item; + } - public function getURI(){ - return $this->uri; - } + /** + * Method should return, from a source RSS item given by lastRSS, one of our Items objects + * @param $item the input rss item + * @return a RSS-Bridge Item, with (hopefully) the whole content) + */ + abstract protected function parseItem($item); - public function getName(){ - return $this->name; - } + public function getURI(){ + return $this->uri; + } - public function getDescription(){ - return $this->description; - } + public function getName(){ + return $this->name; + } + + public function getDescription(){ + return $this->description; + } } diff --git a/lib/Format.php b/lib/Format.php index 618c0a3..182bf0b 100644 --- a/lib/Format.php +++ b/lib/Format.php @@ -1,72 +1,73 @@ charset = $charset; + public function setCharset($charset){ + $this->charset = $charset; - return $this; - } + return $this; + } - public function getCharset(){ - $charset = $this->charset; + public function getCharset(){ + $charset = $this->charset; - return is_null($charset) ? self::DEFAULT_CHARSET : $charset; - } + return is_null($charset) ? self::DEFAULT_CHARSET : $charset; + } - protected function setContentType($contentType){ - $this->contentType = $contentType; + protected function setContentType($contentType){ + $this->contentType = $contentType; - return $this; - } + return $this; + } - protected function callContentType(){ - header('Content-Type: ' . $this->contentType); - } + protected function callContentType(){ + header('Content-Type: ' . $this->contentType); + } - public function display(){ - echo $this->stringify(); + public function display(){ + echo $this->stringify(); - return $this; - } + return $this; + } - public function setItems(array $items){ - $this->items = array_map(array($this, 'array_trim'), $items); + public function setItems(array $items){ + $this->items = array_map(array($this, 'array_trim'), $items); - return $this; - } + return $this; + } - public function getItems(){ - if(!is_array($this->items)) - throw new \LogicException('Feed the ' . get_class($this) . ' with "setItems" method before !'); + public function getItems(){ + if(!is_array($this->items)) + throw new \LogicException('Feed the ' . get_class($this) . ' with "setItems" method before !'); - return $this->items; - } + return $this->items; + } - /** - * Define common informations can be required by formats and set default value for unknow values - * @param array $extraInfos array with know informations (there isn't merge !!!) - * @return this - */ - public function setExtraInfos(array $extraInfos = array()){ - foreach(array('name', 'uri') as $infoName){ - if( !isset($extraInfos[$infoName]) ){ - $extraInfos[$infoName] = ''; - } - } + /** + * Define common informations can be required by formats and set default value for unknow values + * @param array $extraInfos array with know informations (there isn't merge !!!) + * @return this + */ + public function setExtraInfos(array $extraInfos = array()){ + foreach(array('name', 'uri') as $infoName){ + if( !isset($extraInfos[$infoName]) ){ + $extraInfos[$infoName] = ''; + } + } - $this->extraInfos = $extraInfos; + $this->extraInfos = $extraInfos; - return $this; - } + return $this; + } - /** - * Return extra infos - * @return array See "setExtraInfos" detail method to know what extra are disponibles - */ - public function getExtraInfos(){ - if( is_null($this->extraInfos) ){ // No extra info ? - $this->setExtraInfos(); // Define with default value - } + /** + * Return extra infos + * @return array See "setExtraInfos" detail method to know what extra are disponibles + */ + public function getExtraInfos(){ + if( is_null($this->extraInfos) ){ // No extra info ? + $this->setExtraInfos(); // Define with default value + } - return $this->extraInfos; - } - - /** - * Sanitized html while leaving it functionnal. - * The aim is to keep html as-is (with clickable hyperlinks) - * while reducing annoying and potentially dangerous things. - * Yes, I know sanitizing HTML 100% is an impossible task. - * Maybe we'll switch to http://htmlpurifier.org/ - * or http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/index.php - */ - protected function sanitizeHtml($html) - { - $html = str_replace('extraInfos; + } - protected function array_trim($elements){ - foreach($elements as $key => $value){ - if(is_string($value)) - $elements[$key] = trim($value); - } - return $elements; - } + /** + * Sanitized html while leaving it functionnal. + * The aim is to keep html as-is (with clickable hyperlinks) + * while reducing annoying and potentially dangerous things. + * Yes, I know sanitizing HTML 100% is an impossible task. + * Maybe we'll switch to http://htmlpurifier.org/ + * or http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/index.php + */ + protected function sanitizeHtml($html) + { + $html = str_replace(' $value){ + if(is_string($value)) + $elements[$key] = trim($value); + } + return $elements; + } } diff --git a/lib/FormatInterface.php b/lib/FormatInterface.php index ea0cf23..2fac3fc 100644 --- a/lib/FormatInterface.php +++ b/lib/FormatInterface.php @@ -1,6 +1,6 @@ ' . PHP_EOL; - $card .= '
' . PHP_EOL; + $idArg = 'arg-' + . urlencode($bridgeName) + . '-' + . urlencode('proxyoff') + . '-' + . urlencode('_noproxy'); + + $card .= '' + . PHP_EOL; + + $card .= '
' + . PHP_EOL; } $card .= HTMLUtils::getHelperButtonsFormat($formats); @@ -59,7 +73,7 @@ CARD; $card .= HTMLUtils::getFormHeader($bridgeName); - foreach($parameter as $id=>$inputEntry) { + foreach($parameter as $id=>$inputEntry){ $additionalInfoString = ''; if(isset($inputEntry['required']) && $inputEntry['required'] === true) @@ -77,55 +91,140 @@ CARD; if(!isset($inputEntry['defaultValue'])) $inputEntry['defaultValue'] = ''; - $idArg = 'arg-' . urlencode($bridgeName) . '-' . urlencode($parameterName) . '-' . urlencode($id); - $card .= '' . PHP_EOL; + $idArg = 'arg-' + . urlencode($bridgeName) + . '-' + . urlencode($parameterName) + . '-' + . urlencode($id); - if(!isset($inputEntry['type']) || $inputEntry['type'] == 'text') { - $card .= '
' . PHP_EOL; - } else if($inputEntry['type'] == 'number') { - $card .= '
' . PHP_EOL; - } else if($inputEntry['type'] == 'list') { - $card .= '
' + . PHP_EOL; + } elseif($inputEntry['type'] == 'number'){ + $card .= '
' + . PHP_EOL; + } else if($inputEntry['type'] == 'list'){ + $card .= '
'; - } else if($inputEntry['type'] == 'checkbox') { + } elseif($inputEntry['type'] == 'checkbox'){ if($inputEntry['defaultValue'] === 'checked') - $card .= '
' . PHP_EOL; + $card .= '
' + . PHP_EOL; else - $card .= '
' . PHP_EOL; + $card .= '
' + . PHP_EOL; } } - if ($isActive){ + if($isActive){ if(defined('PROXY_URL') && PROXY_BYBRIDGE){ - $idArg = 'arg-' . urlencode($bridgeName) . '-' . urlencode('proxyoff') . '-' . urlencode('_noproxy'); - $card .= '' . PHP_EOL; - $card .= '
' . PHP_EOL; - } + $idArg = 'arg-' + . urlencode($bridgeName) + . '-' + . urlencode('proxyoff') + . '-' + . urlencode('_noproxy'); + $card .= '' + . PHP_EOL; + + $card .= '
' + . PHP_EOL; + } $card .= HTMLUtils::getHelperButtonsFormat($formats); } else { $card .= 'Inactive'; } - $card .= '' . PHP_EOL; } @@ -138,8 +237,13 @@ CARD; private static function getHelperButtonsFormat($formats){ $buttons = ''; - foreach( $formats as $name){ - $buttons .= '' . PHP_EOL; + foreach($formats as $name){ + $buttons .= '' + . PHP_EOL; } return $buttons; @@ -164,22 +268,24 @@ class HTMLSanitizer { public static $KEPT_ATTRIBUTES = ["title", "href", "src"]; public static $ONLY_TEXT = []; - public function __construct($tags_to_remove = null, $kept_attributes = null, $only_keep_text = null) { - $this->tagsToRemove = $tags_to_remove == null ? HTMLSanitizer::$DEFAULT_CLEAR_TAGS : $tags_to_remove; - $this->keptAttributes = $kept_attributes == null ? HTMLSanitizer::$KEPT_ATTRIBUTES : $kept_attributes; - $this->onlyKeepText = $only_keep_text == null ? HTMLSanitizer::$ONLY_TEXT : $only_keep_text; + public function __construct($tags_to_remove = null + , $kept_attributes = null + , $only_keep_text = null){ + $this->tagsToRemove = is_null($tags_to_remove) ? HTMLSanitizer::$DEFAULT_CLEAR_TAGS : $tags_to_remove; + $this->keptAttributes = is_null($kept_attributes) ? HTMLSanitizer::$KEPT_ATTRIBUTES : $kept_attributes; + $this->onlyKeepText = is_null($only_keep_text) ? HTMLSanitizer::$ONLY_TEXT : $only_keep_text; } - public function sanitize($textToSanitize) { + public function sanitize($textToSanitize){ $htmlContent = str_get_html($textToSanitize); - foreach($htmlContent->find('*[!b38fd2b1fe7f4747d6b1c1254ccd055e]') as $element) { - if(in_array($element->tag, $this->onlyKeepText)) { + foreach($htmlContent->find('*[!b38fd2b1fe7f4747d6b1c1254ccd055e]') as $element){ + if(in_array($element->tag, $this->onlyKeepText)){ $element->outertext = $element->plaintext; - } else if(in_array($element->tag, $this->tagsToRemove)) { + } elseif(in_array($element->tag, $this->tagsToRemove)){ $element->outertext = ''; } else { - foreach($element->getAllAttributes() as $attributeName => $attribute) { + foreach($element->getAllAttributes() as $attributeName => $attribute){ if(!in_array($attributeName, $this->keptAttributes)) $element->removeAttribute($attributeName); } @@ -189,10 +295,12 @@ class HTMLSanitizer { return $htmlContent; } - public static function defaultImageSrcTo($content, $server) { - foreach($content->find('img') as $image) { - if(strpos($image->src, "http") == NULL && strpos($image->src, "//") == NULL && strpos($image->src, "data:") == NULL) - $image->src = $server.$image->src; + public static function defaultImageSrcTo($content, $server){ + foreach($content->find('img') as $image){ + if(is_null(strpos($image->src, "http")) + && is_null(strpos($image->src, "//")) + && is_null(strpos($image->src, "data:"))) + $image->src = $server . $image->src; } return $content; } diff --git a/lib/RssBridge.php b/lib/RssBridge.php index 0728683..d7ef70f 100644 --- a/lib/RssBridge.php +++ b/lib/RssBridge.php @@ -19,28 +19,33 @@ require __DIR__ . '/HTMLUtils.php'; $vendorLibSimpleHtmlDom = __DIR__ . PATH_VENDOR . '/simplehtmldom/simple_html_dom.php'; if( !file_exists($vendorLibSimpleHtmlDom) ){ - throw new \HttpException('"PHP Simple HTML DOM Parser" library is missing. Get it from http://simplehtmldom.sourceforge.net and place the script "simple_html_dom.php" in '.substr(PATH_VENDOR,4) . '/simplehtmldom/', 500); + throw new \HttpException('"PHP Simple HTML DOM Parser" library is missing.' + . ' Get it from http://simplehtmldom.sourceforge.net and place the script' + . ' "simple_html_dom.php" in ' + . substr(PATH_VENDOR,4) + . '/simplehtmldom/' + , 500); } require_once $vendorLibSimpleHtmlDom; /* Example use - - require_once __DIR__ . '/lib/RssBridge.php'; - // Data retrieval - Bridge::setDir(__DIR__ . '/bridges/'); - $bridge = Bridge::create('GoogleSearch'); - $bridge->collectData($_REQUEST); + require_once __DIR__ . '/lib/RssBridge.php'; - // Data transformation - Format::setDir(__DIR__ . '/formats/'); - $format = Format::create('Atom'); - $format - ->setItems($bridge->getItems()) - ->setExtraInfos(array( - 'name' => $bridge->getName(), - 'uri' => $bridge->getURI(), - )) - ->display(); + // Data retrieval + Bridge::setDir(__DIR__ . '/bridges/'); + $bridge = Bridge::create('GoogleSearch'); + $bridge->collectData($_REQUEST); + + // Data transformation + Format::setDir(__DIR__ . '/formats/'); + $format = Format::create('Atom'); + $format + ->setItems($bridge->getItems()) + ->setExtraInfos(array( + 'name' => $bridge->getName(), + 'uri' => $bridge->getURI(), + )) + ->display(); */