mirror of
https://github.com/Chouchen/ShikiryuRSS.git
synced 2024-10-31 14:38:51 +01:00
Adding class
This commit is contained in:
parent
f82362e399
commit
ec49c5c400
735
srss.php
Normal file
735
srss.php
Normal file
@ -0,0 +1,735 @@
|
||||
<?php
|
||||
/**
|
||||
TODO textinput a 4 sous enfant
|
||||
TODO language
|
||||
TODO CDATA ?
|
||||
*/
|
||||
class SRSS extends DomDocument implements Iterator
|
||||
{
|
||||
protected $xpath; // xpath engine
|
||||
protected $items; // array of SRSSItems
|
||||
protected $attr; // array of RSS attributes
|
||||
private $position; // Iterator position
|
||||
|
||||
// lists of possible attributes for RSS
|
||||
protected $possibleAttr = array(
|
||||
'title' => '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 : <strong>Message : ' . $this->getMessage() . '</strong> à 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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user