'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(); } /** * 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); } }