diff options
Diffstat (limited to 'app/classes')
-rw-r--r-- | app/classes/Cache.php | 254 | ||||
-rw-r--r-- | app/classes/Opml.php | 70 | ||||
-rw-r--r-- | app/classes/OpmlManager.php | 50 | ||||
-rw-r--r-- | app/classes/Planet.php | 67 |
4 files changed, 410 insertions, 31 deletions
diff --git a/app/classes/Cache.php b/app/classes/Cache.php new file mode 100644 index 0000000..b73182e --- /dev/null +++ b/app/classes/Cache.php @@ -0,0 +1,254 @@ +<?php +/** +* This library is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this software; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* © Copyright 2005 Richard Heyes +*/ + +/** +* Caching Libraries for PHP5 +* +* Handles data and output caching. Defaults to /dev/shm +* (shared memory). All methods are static. +* +* Eg: (output caching) +* +* if (!OutputCache::Start('group', 'unique id', 600)) { +* +* // ... Output +* +* OutputCache::End(); +* } +* +* Eg: (data caching) +* +* if (!$data = DataCache::Get('group', 'unique id')) { +* +* $data = time(); +* +* DataCache::Put('group', 'unique id', 10, $data); +* } +* +* echo $data; +*/ + class Cache + { + /** + * Whether caching is enabled + * @var bool + */ + public static $enabled = true; + + /** + * Place to store the cache files + * @var string + */ + protected static $store = '/dev/shm/'; + + /** + * Prefix to use on cache files + * @var string + */ + protected static $prefix = 'cache_'; + + /** + * Stores data + * + * @param string $group Group to store data under + * @param string $id Unique ID of this data + * @param int $ttl How long to cache for (in seconds) + */ + protected static function write($group, $id, $ttl, $data) + { + $filename = self::getFilename($group, $id); + + if (self::$enabled && $fp = fopen($filename, 'xb')) { + + if (flock($fp, LOCK_EX)) { + fwrite($fp, $data); + } + fclose($fp); + + // Set filemtime + touch($filename, time() + $ttl); + } + } + + /** + * Reads data + * + * @param string $group Group to store data under + * @param string $id Unique ID of this data + */ + protected static function read($group, $id) + { + $filename = self::getFilename($group, $id); + + return file_get_contents($filename); + } + + /** + * Determines if an entry is cached + * + * @param string $group Group to store data under + * @param string $id Unique ID of this data + */ + protected static function isCached($group, $id) + { + $filename = self::getFilename($group, $id); + + if (self::$enabled && file_exists($filename) && filemtime($filename) > time()) { + return true; + } + + @unlink($filename); + + return false; + } + + /** + * Builds a filename/path from group, id and + * store. + * + * @param string $group Group to store data under + * @param string $id Unique ID of this data + */ + protected static function getFilename($group, $id) + { + $id = md5($id); + + return self::$store . self::$prefix . "{$group}_{$id}"; + } + + /** + * Sets the filename prefix to use + * + * @param string $prefix Filename Prefix to use + */ + public static function setPrefix($prefix) + { + self::$prefix = $prefix; + } + + /** + * Sets the store for cache files. Defaults to + * /dev/shm. Must have trailing slash. + * + * @param string $store The dir to store the cache data in + */ + public static function setStore($store) + { + self::$store = $store; + } + } + + /** + * Output Cache extension of base caching class + */ + class OutputCache extends Cache + { + /** + * Group of currently being recorded data + * @var string + */ + private static $group; + + /** + * ID of currently being recorded data + * @var string + */ + private static $id; + + /** + * Ttl of currently being recorded data + * @var int + */ + private static $ttl; + + /** + * Starts caching off. Returns true if cached, and dumps + * the output. False if not cached and start output buffering. + * + * @param string $group Group to store data under + * @param string $id Unique ID of this data + * @param int $ttl How long to cache for (in seconds) + * @return bool True if cached, false if not + */ + public static function Start($group, $id, $ttl) + { + if (self::isCached($group, $id)) { + echo self::read($group, $id); + return true; + + } else { + + ob_start(); + + self::$group = $group; + self::$id = $id; + self::$ttl = $ttl; + + return false; + } + } + + /** + * Ends caching. Writes data to disk. + */ + public static function End() + { + $data = ob_get_contents(); + ob_end_flush(); + + self::write(self::$group, self::$id, self::$ttl, $data); + } + } + + /** + * Data cache extension of base caching class + */ + class DataCache extends Cache + { + + /** + * Retrieves data from the cache + * + * @param string $group Group this data belongs to + * @param string $id Unique ID of the data + * @return mixed Either the resulting data, or null + */ + public static function Get($group, $id) + { + if (self::isCached($group, $id)) { + return unserialize(self::read($group, $id)); + } + + return null; + } + + /** + * Stores data in the cache + * + * @param string $group Group this data belongs to + * @param string $id Unique ID of the data + * @param int $ttl How long to cache for (in seconds) + * @param mixed $data The data to store + */ + public static function Put($group, $id, $ttl, $data) + { + self::write($group, $id, $ttl, serialize($data)); + } + } +?>
\ No newline at end of file diff --git a/app/classes/Opml.php b/app/classes/Opml.php index e69de29..ae9e8b1 100644 --- a/app/classes/Opml.php +++ b/app/classes/Opml.php @@ -0,0 +1,70 @@ +<?php + +class Opml +{ + var $_xml = null; + var $_currentTag = ''; + + var $title = ''; + var $entries = array(); + var $map = + array( + 'URL' => 'website', + 'HTMLURL' => 'website', + 'TEXT' => 'name', + 'TITLE' => 'name', + 'XMLURL' => 'feed', + 'DESCRIPTION' => 'description', + 'ISDOWN' => 'isDown' + ); + + + function parse($data) + { + $this->_xml = xml_parser_create('UTF-8'); + //xml_parser_set_option($this->_xml, XML_OPTION_CASE_FOLDING, false); + //xml_parser_set_option($this->_xml, XML_OPTION_SKIP_WHITE, true); + xml_set_object($this->_xml, $this); + xml_set_element_handler($this->_xml,'_openTag','_closeTag'); + xml_set_character_data_handler ($this->_xml, '_cData'); + + xml_parse($this->_xml,$data); + xml_parser_free($this->_xml); + return $this->entries; + } + + + function _openTag($p,$tag,$attrs) + { + $this->_currentTag = $tag; + + if ($tag == 'OUTLINE') + { + $i = count($this->entries); + foreach (array_keys($this->map) as $key) + { + if (isset($attrs[$key])) { + $this->entries[$i][$this->map[$key]] = $attrs[$key]; + } + } + } + } + + function _closeTag($p, $tag){ + $this->_currentTag = ''; + } + + function _cData($p, $cdata){ + if ($this->_currentTag == 'TITLE'){ + $this->title = $cdata; + } + } + + function getTitle(){ + return $this->title; + } + + function getPeople(){ + return $this->entries; + } +}
\ No newline at end of file diff --git a/app/classes/OpmlManager.php b/app/classes/OpmlManager.php new file mode 100644 index 0000000..02491a2 --- /dev/null +++ b/app/classes/OpmlManager.php @@ -0,0 +1,50 @@ +<?php + + +class OpmlManager +{ + public static function load($file) + { + if (!file_exists($file)) { + throw new Exception('OPML file not found!'); + } + + $opml = new opml(); + + //Remove BOM if needed + $BOM = '/^/'; + $fileContent = file_get_contents($file); + $fileContent = preg_replace($BOM, '', $fileContent, 1); + + //Parse + $opml->parse($fileContent); + + return $opml; + } + + /** + * @param Opml $opml + * @param string $file + */ + public static function save($opml, $file){ + $out = '<?xml version="1.0"?>'."\n"; + $out.= '<opml version="1.1">'."\n"; + $out.= '<head>'."\n"; + $out.= '<title>'.htmlspecialchars($opml->getTitle()).'</title>'."\n"; + $out.= '<dateCreated>'.date('c').'</dateCreated>'."\n"; + $out.= '<dateModified>'.date('c').'</dateModified>'."\n"; + $out.= '</head>'."\n"; + $out.= '<body>'."\n"; + foreach ($opml->entries as $person) { + $out.= '<outline text="' . htmlspecialchars($person['name'], ENT_QUOTES) . '" htmlUrl="' . htmlspecialchars($person['website'], ENT_QUOTES) . '" xmlUrl="' . htmlspecialchars($person['feed'], ENT_QUOTES) . '" isDown="' . htmlspecialchars($person['isDown'], ENT_QUOTES) . '"/>'."\n"; + } + $out.= '</body>'."\n"; + $out.= '</opml>'; + + file_put_contents($file, $out); + } + + public static function backup($file){ + copy($file, $file.'.bak'); + } +} diff --git a/app/classes/Planet.php b/app/classes/Planet.php index 39b55f6..c287843 100644 --- a/app/classes/Planet.php +++ b/app/classes/Planet.php @@ -34,23 +34,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ class Planet { + /** @var PlanetConfig */ public $config; + + /** @var PlanetItem[] */ public $items; + + /** @var PlanetFeed[] */ public $people; + + /** @var PlanetError[] */ public $errors; + /** + * Planet constructor. + * + * @param PlanetConfig $config + */ public function __construct($config=null) { + $this->config = $config === null ? new PlanetConfig() : $config; - if ($config == null) { - $this->config = new PlanetConfig(array()); - } else { - $this->config = $config; - } - - $this->items = array(); - $this->people = array(); - $this->errors = array(); + $this->items = []; + $this->people = []; + $this->errors = []; } /** @@ -111,8 +118,9 @@ class Planet } /** - * Adds a feed to the planet - * @param PlanetFeed feed + * Adds a feed to the planet. + * + * @param PlanetFeed $feed */ public function addPerson(&$feed) { @@ -120,8 +128,10 @@ class Planet } /** - * Load people from an OPML - * @return integer Number of people loaded + * Load people from an OPML. + * + * @param string $file File to load the OPML from. + * @return integer Number of people loaded. */ public function loadOpml($file) { @@ -162,17 +172,16 @@ class Planet } /** - * Download - * @var $max_load percentage of feeds to load + * Fetch feeds and see if new data is present. + * + * @param float $max_load Percentage of feeds to load */ public function download($max_load=0.1) { $max_load_feeds = ceil(count($this->people) * $max_load); - $opml = OpmlManager::load(__DIR__.'/../../custom/people.opml'); - foreach ($this->people as $feed) { + foreach ($this->people as &$feed) { //Avoid mass loading with variable cache duration - //$feed->set_cache_duration($this->config->getCacheTimeout()+rand(0,30)); $feed->set_cache_duration($this->config->getCacheTimeout()); //Load only a few feeds, force other to fetch from the cache @@ -181,6 +190,8 @@ class Planet $this->errors[] = new PlanetError(1, 'Forced from cache : '.$feed->getFeed()); } + // Bypass remote's SSL/TLS certificate if the user explicitly + // asked for it in the configuration. if ($this->config->checkcerts === false) { $feed->set_curl_options([ CURLOPT_SSL_VERIFYHOST => false, @@ -188,28 +199,22 @@ class Planet ]); } - //Load feed $feed->init(); - $isDown = ''; // http://simplepie.org/wiki/reference/simplepie/merge_items ? - //Add items to index if (($feed->data) && ($feed->get_item_quantity() > 0)){ $items = $feed->get_items(); $this->items = array_merge($this->items, $items); + $feed['isUp'] = true; } else { - $this->errors[] = new PlanetError(1, 'No items : '.$feed->getFeed()); - $isDown = '1'; - } - - //Mark if the feed is temporary unavailable - foreach ($opml->entries as $key => $entrie) { - if ($feed->getFeed() === $entrie['feed']) { - $opml->entries[$key]['isDown'] = $isDown; - } + $this->errors[] = new PlanetError(1, 'No items or down : ' . $feed->getFeed()); + $feed['isDown'] = false; } } - OpmlManager::save($opml, __DIR__.'/../../custom/people.opml'); + + // FIXME: not sure that it's $this->people? + // FIXME: make sure we made a change + OpmlManager::save($this->people, __DIR__.'/../../custom/people.opml'); } public function sort() |