123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- <?php
- /*
- @nom: Feed
- @auteur: Idleman (idleman@idleman.fr)
- @description: Classe de gestion des flux RSS/ATOM
- */
- class Feed extends MysqlEntity{
- protected $id,$name,$url,$events=array(),$description,$website,$folder,$lastupdate,$isverbose,$lastSyncInError;
- protected $TABLE_NAME = 'feed';
- protected $CLASS_NAME = 'Feed';
- protected $object_fields =
- array(
- 'id'=>'key',
- 'name'=>'string',
- 'description'=>'longstring',
- 'website'=>'longstring',
- 'url'=>'longstring',
- 'lastupdate'=>'string',
- 'folder'=>'integer',
- 'isverbose'=>'boolean',
- 'lastSyncInError'=>'boolean',
- );
- protected $object_fields_index =
- array(
- 'folder'=>'index'
- );
- protected $error = '';
- function __construct($name=null,$url=null){
- $this->name = $name;
- $this->url = $url;
- parent::__construct();
- }
- /** @TODO: ne faire qu'un seul chargement avec SimplePie et récupérer les
- même informations. Mettre le chargement en cache au moins d'une méthode
- loadLeed() qui ne chargera qu'une seule fois. Voire même en déclenchement
- retardé, au dernier moment. */
- function getInfos(){
- $xml = @simplexml_load_file($this->url);
- if($xml!=false){
- $this->name = $xml->xpath('channel/title')[0];
- $this->description = $xml->xpath('channel/description')[0];
- $this->website = $xml->xpath('channel/link')[0];
- }
- }
- function getError() { return $this->error; }
- function getLastSyncInError() { return $this->lastSyncInError; }
- /*@TODO: fournir un extrait quand il 'y a pas de description. De même pour les médias.
- @TODO: SimplePie remplace "é" par "é", il ne devrait pas le faire.
- J'ai testé set_stupidly_fast(true) sans succès.
- Il encadre les descriptions avec <div>, absents dans le source du flux.
- @TODO: la vérification de doublon est sous la responsabilité de l'appelant.
- Il serait peut-être utile de faire une méthode add() qui vérifie, plante si
- nécessaire, et appelle parse(). Impossible de vérifier dans parse() même
- car elle est appelée aussi pour autre chose que l'ajout.
- */
- function parse($syncId,&$nbEvents =0, $enableCache=true, $forceFeed=false){
- $nbEvents = 0;
- assert('is_int($syncId) && $syncId>0');
- if (empty($this->id) || 0 == $this->id) {
- /* Le flux ne dispose pas pas d'id !. Ça arrive si on appelle
- parse() sans avoir appelé save() pour un nouveau flux.
- @TODO: un create() pour un nouveau flux ? */
- $msg = 'Empty or null id for a feed! '
- .'See '.__FILE__.' on line '.__LINE__;
- error_log($msg, E_USER_ERROR);
- die($msg); // Arrêt, sinon création événements sans flux associé.
- }
- $feed = new SimplePie();
- $feed->enable_cache($enableCache);
- $feed->force_feed($forceFeed);
- $feed->set_feed_url($this->url);
- $feed->set_useragent('Mozilla/4.0 Leed (LightFeed Agrgegator) '.VERSION_NAME.' by idleman http://projet.idleman.fr/leed');
- $this->lastSyncInError = 0;
- if (!$feed->init()) {
- $this->error = $feed->error;
- $this->lastSyncInError = 1;
- $this->lastupdate = $_SERVER['REQUEST_TIME'];
- $this->save();
- return false;
- }
- $feed->handle_content_type(); // UTF-8 par défaut pour SimplePie
- if($this->name=='') $this->name = $feed->get_title();
- if($this->name=='') $this->name = $this->url;
- $this->website = $feed->get_link();
- $this->description = $feed->get_description();
- $items = $feed->get_items();
- $eventManager = new Event();
- $events = array();
- $iEvents = 0;
- foreach($items as $item){
- // Ne retient que les 100 premiers éléments de flux.
- if ($iEvents++>=100) break;
- // Si le guid existe déjà, on évite de le reparcourir.
- $alreadyParsed = $eventManager->load(array('guid'=>$item->get_id(), 'feed'=>$this->id));
- if (isset($alreadyParsed)&&($alreadyParsed!=false)) {
- $events[]=$alreadyParsed->getId();
- continue;
- }
- // Initialisation des informations de l'événement (élt. de flux)
- $event = new Event();
- $event->setSyncId($syncId);
- $event->setGuid($item->get_id());
- $event->setTitle($item->get_title());
- $event->setPubdate($item->get_date());
- $event->setCreator(
- ''==$item->get_author()
- ? ''
- : $item->get_author()->name
- );
- $event->setLink($item->get_permalink());
- $event->setFeed($this->id);
- $event->setUnread(1); // inexistant, donc non-lu
- //Gestion de la balise enclosure pour les podcasts et autre cochonneries :)
- $enclosure = $item->get_enclosure();
- if($enclosure!=null && $enclosure->link!=''){
- $enclosureName = substr(
- $enclosure->link,
- strrpos($enclosure->link, '/')+1,
- strlen($enclosure->link)
- );
- $enclosureArgs = strpos($enclosureName, '?');
- if($enclosureArgs!==false)
- $enclosureName = substr($enclosureName,0,$enclosureArgs);
- $enclosureFormat = isset($enclosure->handler)
- ? $enclosure->handler
- : substr($enclosureName, strrpos($enclosureName,'.')+1);
- $enclosure ='<div class="enclosure"><h1>Fichier média :</h1><a href="'.$enclosure->link.'"> '.$enclosureName.'</a> <span>(Format '.strtoupper($enclosureFormat).', '.Functions::convertFileSize($enclosure->length).')</span></div>';
- }else{
- $enclosure = '';
- }
- $event->setContent($item->get_content().$enclosure);
- $event->setDescription($item->get_description().$enclosure);
- if(trim($event->getDescription())=='')
- $event->setDescription(
- substr($event->getContent(),0,300)
- .'…<br><a href="'.$event->getLink()
- .'">Lire la suite de l\'article</a>'
- );
- if(trim($event->getContent())=='')
- $event->setContent($event->getDescription());
- $event->setCategory($item->get_category());
- $event->save();
- $nbEvents++;
- }
- $listid = "";
- foreach($events as $item){
- $listid.=','.$item;
- }
- $query='UPDATE `'.MYSQL_PREFIX.'event` SET syncId='.$syncId.' WHERE id in (0'.$listid.');';
- $myQuery = $this->customQuery($query);
- $this->lastupdate = $_SERVER['REQUEST_TIME'];
- $this->save();
- return true;
- }
- function removeOldEvents($maxEvent, $currentSyncId){
- if ($maxEvent<=0) return;
- $eventManager = new Event();
- $nbLines = $eventManager->rowCount(array(
- 'feed'=>$this->id,
- 'unread'=>0,
- 'favorite'=>0,
- ));
- $limit = $nbLines - $maxEvent;
- if ($limit<=0) return;
- $tableEvent = '`'.MYSQL_PREFIX."event`";
- $query = "
- DELETE FROM {$tableEvent} WHERE feed={$this->id} AND favorite!=1 AND unread!=1 AND syncId!={$currentSyncId} ORDER BY pubdate ASC LIMIT {$limit}
- ";
- ///@TODO: escape the variables inside mysql
- $this->customExecute($query);
- }
- function setId($id){
- $this->id = $id;
- }
- function getDescription(){
- return $this->description;
- }
- function setDescription($description){
- $this->description = $description;
- }
- function getWebSite(){
- return $this->website;
- }
- function setWebSite($website){
- $this->website = $website;
- }
- function getId(){
- return $this->id;
- }
- function getUrl(){
- return $this->url;
- }
- function setUrl($url){
- $this->url = $url;
- }
- function getName(){
- return (trim($this->name)!='' ? $this->name:$this->url);
- }
- function setName($name){
- $this->name = $name;
- }
- function getEvents($start=0,$limit=10000,$order,$columns='*'){
- $eventManager = new Event();
- $events = $eventManager->loadAllOnlyColumn($columns,array('feed'=>$this->getId()),$order,$start.','.$limit);
- return $events;
- }
- function countUnreadEvents(){
- $unreads = array();
- $results = Feed::customQuery("SELECT COUNT(".MYSQL_PREFIX."event.id), ".MYSQL_PREFIX."event.feed FROM ".MYSQL_PREFIX."event WHERE ".MYSQL_PREFIX."event.unread = 1 GROUP BY ".MYSQL_PREFIX."event.feed") ;
- if($results!=false){
- while($item = mysql_fetch_array($results)){
- $unreads[$item[1]] = $item[0];
- }
- }
- return $unreads;
- }
- function getFeedsPerFolder(){
- $feedsFolderMap = array();
- $feedsIdMap = array();
- $results = Feed::customQuery("SELECT ".MYSQL_PREFIX."feed.name AS name, ".MYSQL_PREFIX."feed.id AS id, ".MYSQL_PREFIX."feed.url AS url, ".MYSQL_PREFIX."folder.id AS folder FROM ".MYSQL_PREFIX."feed INNER JOIN ".MYSQL_PREFIX."folder ON ( ".MYSQL_PREFIX."feed.folder = ".MYSQL_PREFIX."folder.id ) ORDER BY ".MYSQL_PREFIX."feed.name ;");
- if($results!=false){
- while($item = mysql_fetch_array($results)){
- $name = $item['name'];
- $feedsIdMap[$item['id']]['name'] = $name;
- $feedsFolderMap[$item['folder']][$item['id']]['id'] = $item['id'];
- $feedsFolderMap[$item['folder']][$item['id']]['name'] = $name;
- $feedsFolderMap[$item['folder']][$item['id']]['url'] = $item['url'];
- }
- }
- $feeds['folderMap'] = $feedsFolderMap;
- $feeds['idMap'] = $feedsIdMap;
- return $feeds;
- }
- function getFolder(){
- return $this->folder;
- }
- function setFolder($folder){
- $this->folder = $folder;
- }
- function getLastupdate(){
- return $this->lastUpdate;
- }
- function setLastupdate($lastupdate){
- $this->lastupdate = $lastupdate;
- }
- function getIsverbose(){
- return $this->isverbose;
- }
- function setIsverbose($isverbose){
- $this->isverbose = $isverbose;
- }
- /** @returns vrai si l'url n'est pas déjà connue .*/
- function notRegistered() {
- return $this->rowCount(array('url' => $this->url)) == 0;
- }
- }
- ?>
|