From ec49c5c400bd451daff724ad1ba6f4a76cde7bbe Mon Sep 17 00:00:00 2001 From: Chouchen Date: Tue, 31 May 2011 11:03:32 +0200 Subject: [PATCH] Adding class --- srss.php | 735 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 735 insertions(+) create mode 100644 srss.php diff --git a/srss.php b/srss.php new file mode 100644 index 0000000..225c0ab --- /dev/null +++ b/srss.php @@ -0,0 +1,735 @@ + 'nohtml', + 'link' => 'link', + 'description' => 'html', + 'language' => '', + //'language' => 'lang', + 'copyright' => 'nohtml', + 'pubDate' => 'date', + 'lastBuildDate' => 'date', + 'category' => 'nohtml', + 'docs' => 'link', + 'cloud' => '', + 'generator' => 'nohtml', + 'managingEditor' => 'email', + 'webMaster' => 'email', + 'ttl' => 'int', + 'image' => '', + 'rating' => 'nohtml', + //'textInput' => '', + 'skipHours' => 'hour', + 'skipDays' => 'day', + ); + + /** + * Constructor + */ + public function __construct() + { + libxml_use_internal_errors(true); + parent::__construct(); + $this->xpath = new DOMXpath($this); + $this->attr = array(); + $this->items = array(); + $this->position = 0; + $this->formatOutput = true; + } + + /** + * Destructor + * manage of libxml errors + */ + public function __destruct() + { + foreach (libxml_get_errors() as $error) { + error_log($error->message, 3, 'error.log'); + } + libxml_clear_errors(); + } + + /** + * @param $link url of the rss + * @return SRSS + */ + public static function read($link) + { + $doc = new SRSS; + if(@$doc->load($link)) // We don't want the warning in case of bad XML. Let's manage it. + { + $channel = $doc->getElementsByTagName('channel'); + if($channel->length == 1){ // Good URL and good RSS + $doc->_loadAttributes(); // loading channel properties + $doc->getItems(); // loading all items + return $doc; + } + else + { + throw new SRSSException('invalid file '.$link); + } + } + else + { + throw new SRSSException('Can not open file '.$link); + } + } + + /** + * @return SRSS + */ + public static function create() + { + $doc = new SRSS; + $root = $doc->createElement('rss'); + $root->setAttribute('version', '2.0'); + $channel = $doc->createElement('channel'); + $root->appendChild($channel); + $doc->appendChild($root); + $doc->encoding = "UTF-8"; + $doc->generator = 'Shikiryu RSS'; + $docs = 'http://www.scriptol.fr/rss/RSS-2.0.html'; + return $doc; + } + + /** + * setter of "image"'s channel attributes + * @param $url picture's url + * @param $title picture's title + * @param $link link on the picture + * @param $width width + * @param $height height + * @param $description description + */ + public function setImage($url, $title, $link, $width = 0, $height = 0, $description = '') + { + $channel = $this->_getChannel(); + $array = array(); + $url = SRSSTools::checkLink($url); + $array['url'] = $url; + $title = SRSSTools::noHTML($title); + $array['title'] = $title; + $link = SRSSTools::checkLink($link); + $array['link'] = $link; + if($width != 0) + { + $width = SRSSTools::checkInt($width); + $array['width'] = $width; + } + if($height != 0) + { + $height = SRSSTools::checkInt($height); + $array['height'] = $height; + } + if($description != 0) + { + $description = SRSSTools::noHTML($description); + $array['description'] = $description; + } + if($this->image == null) + { + $node = $this->createElement('image'); + $urlNode = $this->createElement('url', $url); + $titleNode = $this->createElement('title', $title); + $linkNode = $this->createElement('link', $link); + $node->appendChild($urlNode); + $node->appendChild($titleNode); + $node->appendChild($linkNode); + if($width != 0) + { + $widthNode = $this->createElement('width', $width); + $node->appendChild($widthNode); + } + if($height != 0) + { + $heightNode = $this->createElement('height', $height); + $node->appendChild($heightNode); + } + if($description != '') + { + $descNode = $this->createElement('description', $description); + $node->appendChild($descNode); + } + $channel->appendChild($node); + } + $this->attr['image'] = $array; + } + + /** + * setter of "cloud"'s channel attributes + * @param $domain domain + * @param $port port + * @param $path path + * @param $registerProcedure register procedure + * @param $protocol protocol + */ + public function setCloud($domain, $port, $path, $registerProcedure, $protocol) + { + $channel = $this->_getChannel(); + $array = array(); + $domain = SRSSTools::noHTML($domain); + $array['domain'] = $domain; + $port = SRSSTools::checkInt($port); + $array['port'] = $port; + $path = SRSSTools::noHTML($path); + $array['path'] = $path; + $registerProcedure = SRSSTools::noHTML($registerProcedure); + $array['registerProcedure'] = $registerProcedure; + $protocol = SRSSTools::noHTML($protocol); + $array['protocol'] = $protocol; + if($this->cloud == null) + { + $node = $this->createElement('cloud'); + $node->setAttribute('domain', $domain); + $node->setAttribute('port', $port); + $node->setAttribute('path', $path); + $node->setAttribute('registerProcedure', $registerProcedure); + $node->setAttribute('protocol', $protocol); + $channel->appendChild($node); + } + $this->attr['cloud'] = $array; + } + + /** + * check if current RSS is a valid one (based on specifications) + * @return bool + */ + public function isValid() + { + $valid = true; + $items = $this->getItems(); + $invalidItems = array(); + $i = 1; + foreach($items as $item){ + if($item->isValid() === false){ + $invalidItems[] = $i; + $valid = false; + } + $i++; + } + return ($valid && $this->title != null && $this->link != null && $this->description != null); + } + + /** + * getter of current RSS channel + */ + private function _getChannel() + { + $channel = $this->getElementsByTagName('channel'); + if($channel->length != 1) throw new SRSSException('channel node not created, or too many channel nodes'); + return $channel->item(0); + } + + /** + * setter of others attributes + */ + public function __set($name, $val) + { + $channel = $this->_getChannel(); + if(array_key_exists($name, $this->possibleAttr)){ + $flag = $this->possibleAttr[$name]; + $val = SRSSTools::check($val, $flag); + if(!empty($val)){ + if($this->$name == null){ + $node = $this->createElement($name, $val); + $channel->appendChild($node); + } + $this->attr[$name] = $val; + } + }else{ + throw new SRSSException($name.' is not a possible item'); + } + } + + /** + * getter of others attributes + */ + public function __get($name) + { + if(isset($this->attr[$name])) + return $this->attr[$name]; + $channel = $this->_getChannel(); + if(array_key_exists($name, $this->possibleAttr)){ + $tmp = $this->xpath->query('//channel/'.$name); + if($tmp->length != 1) return; + return $tmp->item(0)->nodeValue; + }else{ + throw new SRSSException($name.' is not a possible value.'); + } + } + + /** + * add a SRSS Item as an item into current RSS + * @param SRSSItem $item + */ + public function addItem(SRSSItem $item) + { + $node = $this->importNode($item->getItem(), true); + $channel = $this->_getChannel(); + $channel->appendChild($node); + } + + /** + * rewind from Iterator + */ + public function rewind() { + $this->position = 0; + } + + /** + * current from Iterator + */ + public function current() { + return $this->items[$this->position]; + } + + /** + * key from Iterator + */ + public function key() { + return $this->position; + } + + /** + * next from Iterator + */ + public function next() { + ++$this->position; + } + + /** + * valid from Iterator + */ + public function valid() { + return isset($this->items[$this->position]); + } + + /** + * getter of 1st item + * @return SRSSItem + */ + public function getFirst() + { + return $this->getItem(1); + } + + /** + * getter of last item + * @return SRSSItem + */ + public function getLast() + { + $items = $this->getItems(); + return $items[count($items)-1]; + } + + /** + * getter of an item + * @param $i int + * @return SRSSItem + */ + public function getItem($i) + { + $i--; + return isset($this->items[$i]) ? $this->items[$i] : null; + } + + /** + * getter of all items + * @return array of SRSSItem + */ + public function getItems() + { + $channel = $this->_getChannel(); + $item = $channel->getElementsByTagName('item'); + $length = $item->length; + $items = array(); + if($length > 0){ + for($i = 0; $i < $length; $i++) + { + $this->items[$i] = new SRSSItem($item->item($i)); + } + } + return $this->items; + } + + /** + * display XML + * see DomDocument's docs + */ + public function show() + { + return $this->saveXml(); + } + + /** + * save XML on server + * @param + * see DomDocument's docs + */ + public function save($path) + { + return $this->saveXml($path); + } + + /** + * putting all RSS attributes into the object + */ + private function _loadAttributes() + { + $channel = $this->_getChannel(); + foreach($channel->childNodes as $child) + { + if($child->nodeType == XML_ELEMENT_NODE && $child->nodeName != 'item') + { + $this->{$child->nodeName} = $child->nodeValue; + } + } + } + + /** + * transform current object into an array + * @return array + */ + public function toArray() + { + $doc = array(); + foreach($this->attr as $attrName => $attrVal) + { + $doc[$attrName] = $attrVal; + } + foreach($this->getItems() as $item) + { + $doc['items'][] = $item->toArray(); + } + return $doc; + } +} + +class SRSSItem extends DomDocument +{ + + protected $node; // item node + protected $attr; // item's properties + + // possible properties' names + protected $possibilities = array( + 'title' => 'nohtml', + 'link' => 'link', + 'description' => 'html', + 'author' => 'email', + 'category' => 'nohtml', + 'comments' => 'link', + 'enclosure' => '', + 'guid' => 'nohtml', + 'pubDate' => 'date', + 'source' => 'link', + ); + + /** + * Constructor + * @param DomElement $node + */ + public function __construct($node = null) + { + parent::__construct(); + if($node instanceof DOMElement) $this->node = $this->importNode($node, true); + else $this->node = $this->importNode(new DomElement('item')); + $this->_loadAttributes(); + } + + /** + * putting all item attributes into the object + */ + private function _loadAttributes() + { + foreach($this->node->childNodes as $child) + { + if($child->nodeType == XML_ELEMENT_NODE && $child->nodeName != 'item') + { + $this->{$child->nodeName} = $child->nodeValue; + } + } + } + + /** + * getter of item DomElement + */ + public function getItem() + { + $this->appendChild($this->node); + return $this->getElementsByTagName('item')->item(0); + } + + /** + * setter for enclosure's properties + * @param $url string url + * @param $length int length + * @param $type string type + */ + public function setEnclosure($url, $length, $type) + { + $array = array(); + $url = SRSSTools::checkLink($url); + $array['url'] = $url; + $length = SRSSTools::checkInt($length); + $array['length'] = $length; + $type = SRSSTools::noHTML($type); + $array['type'] = $type; + if($this->enclosure == null) + { + $node = $this->createElement('enclosure'); + $node->setAttribute('url', $url); + $node->setAttribute('length', $length); + $node->setAttribute('type', $type); + $this->node->appendChild($node); + } + $this->attr['enclosure'] = $array; + } + + /** + * check if current item is valid (following specifications) + * @return bool + */ + public function isValid() + { + return $this->description != null ? true : false; + } + + /** + * main setter for properties + */ + public function __set($name, $val) + { + if(array_key_exists($name, $this->possibilities)) + { + $flag = $this->possibilities[$name]; + if($flag != '') + $val = SRSSTools::check($val, $flag); + if(!empty($val)){ + if($this->$name == null){ + $this->node->appendChild(new DomElement($name, $val)); + } + $this->attr[$name] = $val; + } + } + else + { + throw New SRSSException($name.' is not a possible item : '.print_r($this->possibilities)); + } + } + + /** + * main getter for properties + */ + public function __get($name) + { + if(isset($this->attr[$name])) + return $this->attr[$name]; + if(array_key_exists($name, $this->possibilities)) + { + $tmp = $this->node->getElementsByTagName($name); + if($tmp->length != 1) return; + return $tmp->item(0)->nodeValue; + } + else + { + throw New SRSSException($name.' is not a possible item : '.print_r($this->possibilities)); + } + } + + /** + * display item's XML + * see DomDocument's docs + */ + public function show() + { + return $this->saveXml(); + } + + /** + * transform current item's object into an array + * @return array + */ + public function toArray() + { + $infos = array(); + foreach($this->attr as $attrName => $attrVal) + { + $infos[$attrName] = $attrVal; + } + return $infos; + } +} + +class SRSSException extends Exception +{ + public function __construct($msg) + { + parent :: __construct($msg); + } + + public function getError() + { + $return = 'Une exception a été générée : Message : ' . $this->getMessage() . ' à la ligne : ' . $this->getLine(); + return $return; + } +} + +class SRSSTools +{ + public static function check($check, $flag) + { + switch($flag){ + case 'nohtml': + return self::noHTML($check); + break; + case 'link': + return self::checkLink($check); + break; + case 'html': + return self::HTML4XML($check); + break; + /*case 'lang': + return self::noHTML($check); + break;*/ + case 'date': + return self::getRSSDate($check); + break; + case 'email': + return self::checkEmail($check); + break; + case 'int': + return self::checkInt($check); + break; + case 'hour': + return self::checkHour($check); + break; + case 'day': + return self::checkDay($check); + break; + case '': + return $check; + break; + default: + throw new SRSSEXception('flag '.$flag.' does not exist.'); + } + } + + /** + * format the RSS to the wanted format + * @param $format string wanted format + * @param $date string RSS date + * @return date + */ + public static function formatDate($format, $date) + { + return date($format, strtotime($date)); + } + + /** + * format a date for RSS format + * @param $date string date to format + */ + public static function getRSSDate($date) + { + if(strtotime($date) !==false) + return date("D, d M Y H:i:s T", strtotime($date)); + else + { + list($j, $m, $a) = explode('/', $date); + return date("D, d M Y H:i:s T", strtotime($a.'-'.$m.'-'.$j)); + } + } + + /** + * check if it's an url + * @param $check string to check + * @return the filtered data, or FALSE if the filter fails. + */ + public static function checkLink($check) + { + return filter_var($check, FILTER_VALIDATE_URL); + } + + /** + * make a string XML-compatible + * @param $check string to format + * @return formated string + * TODO CDATA ? + */ + public static function HTML4XML($check) + { + return htmlspecialchars($check); + } + + /** + * delete html tags + * @param $check string to format + * @return formated string + */ + public static function noHTML($check) + { + return strip_tags($check); + } + + /** + * check if it's a day (in RSS terms) + * @param $check string to check + * @return theday, or empty string + */ + public static function checkDay($check) + { + $possibleDay = array('monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'); + return in_array(strtolower($check), $possibleDay) ? $check : ''; + } + + /** + * check if it's an email + * @param $check string to check + * @return the filtered data, or FALSE if the filter fails. + */ + public static function checkEmail($check) + { + return filter_var($check, FILTER_VALIDATE_EMAIL); + } + + /** + * check if it's an hour (in RSS terms) + * @param $check string to check + * @return the filtered data, or FALSE if the filter fails. + */ + public static function checkHour($check) + { + $options = array( + 'options' => array( + 'default' => 0, + 'min_range' => 0, + 'max_range' => 23 + ) + ); + return filter_var($check, FILTER_VALIDATE_INT, $options); + } + + /** + * check if it's an int + * @param $check int to check + * @return the filtered data, or FALSE if the filter fails. + */ + public static function checkInt($check) + { + return filter_var($check, FILTER_VALIDATE_INT); + } +} \ No newline at end of file