402 lines
16 KiB
PHP
Executable File
402 lines
16 KiB
PHP
Executable File
<?php
|
||
/**
|
||
* classe permettant de gérer des flux de syndication
|
||
* on ne traite pas ici le stockage des données, le cache, etc.
|
||
* pour la lecture des flux, inspiré des scripts trouvés sur :
|
||
* http://www.scriptol.fr/rss/lecteur-commun.php (Licence Mozilla 1.1.)
|
||
*
|
||
* @author Fabrice PENHOËT
|
||
**/
|
||
require_once("lien.php");
|
||
class Flux extends Lien
|
||
{
|
||
protected $source_url; // url de la page HTML déclarée en entête du flux
|
||
protected $type; // flux RSS ou Atom ?
|
||
protected $date_maj_flux; // date de dernière mise à jour du flux telle que déclarée en entête
|
||
/**
|
||
* Méthode testant la validité du type fournit pour le flux
|
||
*
|
||
* @return booléen suivant succès
|
||
* @author Fabrice PENHOËT
|
||
**/
|
||
public function set_type($type)
|
||
{
|
||
$type_ok=array("RSS","Atom");
|
||
if (!in_array($type,$type_ok))
|
||
{
|
||
$ajout_journal=new journal_erreurs(array(__FILE__,__LINE__,ERREUR_PARAM_AUTORISES." >> $type"));
|
||
return false;
|
||
}
|
||
$this->type=$type;
|
||
return true;
|
||
}
|
||
/**
|
||
* Méthode retournant les flux de syndication déclarés en entête d'une page html
|
||
*
|
||
* @param objet de type Lien dont l'url doit être connue
|
||
* @return tableau listant les flux si trouvés, false sinon
|
||
* @author Fabrice PENHOËT
|
||
**/
|
||
static function detecte_flux_entete($lien)
|
||
{
|
||
if(!isset($lien->url))
|
||
{
|
||
$ajout_journal=new journal_erreurs(array(__FILE__,__LINE__,ERREUR_PARAM_MANQUANT));
|
||
return false;
|
||
}
|
||
$entetes=$lien->get_entete_html();
|
||
if(empty($entetes))
|
||
return false;
|
||
$flux=array();
|
||
$i=0;
|
||
while(isset($entetes["link$i"]))
|
||
{
|
||
if(isset($entetes["link$i"]["type"]))
|
||
{
|
||
if(($entetes["link$i"]["type"]=="application/rss+xml")||($entetes["link$i"]["type"]=="application/atom+xml"))
|
||
$flux[$i]=$entetes["link$i"];
|
||
}
|
||
$i++;
|
||
}
|
||
if(count($flux)==0)
|
||
return false;
|
||
else
|
||
return $flux;
|
||
}
|
||
/**
|
||
* Recherche les infos d'un flux en se basant sur ses "tags"
|
||
* Attribue les valeurs trouvées
|
||
*
|
||
* @return booléen suivant succès
|
||
* @author Fabrice PENHOËT + scriptol.fr
|
||
**/
|
||
public function get_infos_entete()
|
||
{
|
||
if(!isset($this->url))
|
||
{
|
||
$ajout_journal=new journal_erreurs(array(__FILE__,__LINE__,ERREUR_PARAM_MANQUANT));
|
||
return false;
|
||
}
|
||
$xml=$this->get_contenu(10.0);
|
||
if(empty($xml))
|
||
{
|
||
$ajout_journal=new journal_erreurs(array(__FILE__,__LINE__,ERREUR_FLUX_INFOS));
|
||
return false;
|
||
}
|
||
$doc=new DOMDocument();
|
||
$doc->loadXML($xml);
|
||
$channels=$doc->getElementsByTagName("channel");
|
||
if($channels->length!=0)
|
||
$this->set_type("RSS");
|
||
else
|
||
{
|
||
$entries=$doc->getElementsByTagName("entry");
|
||
if($entries->length!=0)
|
||
$this->set_type("Atom");
|
||
}
|
||
if(empty($this->type))
|
||
{
|
||
$ajout_journal=new journal_erreurs(array(__FILE__,__LINE__,ERREUR_FLUX_INFOS));
|
||
return false;
|
||
}
|
||
if($this->type=="RSS")
|
||
{
|
||
if(!empty($doc->getElementsByTagName("title")->item(0)->firstChild->textContent))
|
||
$this->designation=affiche_utf8(strip_tags($doc->getElementsByTagName("title")->item(0)->firstChild->textContent),UTF8_OK);
|
||
if(!empty($doc->getElementsByTagName("description")->item(0)->firstChild->textContent))
|
||
$this->description=html_entity_decode(str_replace("","'",trim(strip_tags($doc->getElementsByTagName("description")->item(0)->firstChild->textContent))));//!! attention si pas de description pour le flux, récupère la première description d'un item
|
||
if(!empty($doc->getElementsByTagName("link")->item(0)->firstChild->textContent))
|
||
$this->source_url=$doc->getElementsByTagName("link")->item(0)->firstChild->textContent;
|
||
$tnl=$doc->getElementsByTagName("pubDate");
|
||
if($tnl->length==0)
|
||
$tnl=$doc->getElementsByTagName("lastBuildDate");
|
||
if($tnl->length!=0)
|
||
$this->date_maj_flux=$tnl->item(0)->firstChild->textContent;
|
||
}
|
||
else
|
||
{
|
||
if(!empty($doc->getElementsByTagName("title")->item(0)->firstChild->textContent))
|
||
$this->designation=affiche_utf8(strip_tags($doc->getElementsByTagName("title")->item(0)->firstChild->textContent),UTF8_OK);
|
||
if(!empty($doc->getElementsByTagName("summary")->item(0)->firstChild->textContent))
|
||
$this->description=affiche_utf8(strip_tags($doc->getElementsByTagName("summary")->item(0)->firstChild->textContent),UTF8_OK);
|
||
$links=$doc->getElementsByTagName("link");
|
||
if ($links->length!=0)
|
||
{
|
||
foreach($links as $link)
|
||
{
|
||
if(($link->getAttribute("rel")=="alternate")&&($link->getAttribute("type")=="text/html")&&(!empty($link->getAttribute("href"))))
|
||
{
|
||
$this->source_url=$link->getAttribute("href");
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if(!empty($doc->getElementsByTagName("updated")->item(0)->firstChild->textContent))
|
||
$this->date_maj_flux=$doc->getElementsByTagName("updated")->item(0)->firstChild->textContent;
|
||
}
|
||
return true;
|
||
}
|
||
/**
|
||
* Lit les items d'un flux RSS ou Atom
|
||
*
|
||
* @param $nb_max nombre maximum d'items que l'on souhaite récupérer, $log_erreur pour savoir si on enregistre les erreurs de lecture dans le journal
|
||
* @return tableau listant les infos du flux, false si erreur
|
||
* @author Fabrice PENHOËT
|
||
**/
|
||
public function lecture($nb_max=1000,$log_erreur=true)
|
||
{
|
||
if(!isset($this->url))
|
||
{
|
||
$ajout_journal=new journal_erreurs(array(__FILE__,__LINE__,ERREUR_PARAM_MANQUANT));
|
||
return false;
|
||
}
|
||
if(!is_int($nb_max))
|
||
{
|
||
$ajout_journal=new journal_erreurs(array(__FILE__,__LINE__,ERREUR_PARAM_FORMAT));
|
||
return false;
|
||
}
|
||
$xml=$this->get_contenu(5.0);
|
||
if(empty($xml))
|
||
{
|
||
if($log_erreur)
|
||
$ajout_journal=new journal_erreurs(array(__FILE__,__LINE__,ERREUR_FLUX_INFOS." >> ".htmlentities($this->url,ENT_QUOTES)));
|
||
return false;
|
||
}
|
||
$carabug=array("","","&","&");
|
||
$cara_remplace=array("","","&","&");
|
||
$xml=str_replace($carabug,$cara_remplace,$xml);
|
||
$doc=new DOMDocument();
|
||
$setXML=@$doc->loadXML($xml);
|
||
if($setXML===false)
|
||
return $this->lecture_reg($nb_max,$xml,$log_erreur);//fichier XML mal formé...
|
||
// quel format ?
|
||
$rss_ok=$doc->getElementsByTagName("channel");
|
||
$atom_ok=$doc->getElementsByTagName("feed");
|
||
if($rss_ok->length!=0)
|
||
$this->set_type("RSS");
|
||
elseif($atom_ok->length!=0)
|
||
$this->set_type("Atom");
|
||
else
|
||
{
|
||
if($log_erreur)
|
||
$ajout_journal=new journal_erreurs(array(__FILE__,__LINE__,ERREUR_FLUX_INFOS." >> ".htmlentities($this->url,ENT_QUOTES)));
|
||
return false;
|
||
}
|
||
if(empty($this->type))
|
||
{
|
||
if($log_erreur)
|
||
$ajout_journal=new journal_erreurs(array(__FILE__,__LINE__,ERREUR_FLUX_INFOS." >> ".htmlentities($this->url,ENT_QUOTES)));
|
||
return false;
|
||
}
|
||
$maj=array();
|
||
$i=0;
|
||
if($this->type=="RSS")
|
||
{
|
||
$items=$doc->getElementsByTagName("item");
|
||
if($items->length!=0)
|
||
{
|
||
foreach($items as $item)
|
||
{
|
||
if($i<$nb_max)
|
||
{
|
||
if(!empty($item->getElementsByTagName("title")->item(0)->firstChild->textContent))
|
||
$maj[$i]["designation"]=html_entity_decode(str_replace("","'",trim(strip_tags($item->getElementsByTagName("title")->item(0)->firstChild->textContent))));
|
||
if(!empty($item->getElementsByTagName("description")->item(0)->firstChild->textContent))
|
||
$maj[$i]["description"]=html_entity_decode(str_replace("","'",trim(strip_tags($item->getElementsByTagName("description")->item(0)->firstChild->textContent))));
|
||
if(!empty($item->getElementsByTagName("link")->item(0)->firstChild->textContent))
|
||
$maj[$i]["url"]=str_replace("&","&",trim(strip_tags($item->getElementsByTagName("link")->item(0)->firstChild->textContent)));
|
||
$tnl=$item->getElementsByTagName("pubDate");
|
||
if($tnl->length==0)
|
||
$tnl=$item->getElementsByTagName("lastBuildDate");
|
||
if(($tnl->length!=0)&&(!empty($tnl->item(0)->firstChild->textContent)))
|
||
{
|
||
$maj[$i]["date_article"]=trim($tnl->item(0)->firstChild->textContent);
|
||
$date_maj=date_create($maj[$i]["date_article"]);
|
||
if(!empty($date_maj))
|
||
$maj[$i]["timeS"]=$date_maj->getTimestamp();
|
||
$date_maj=null;
|
||
}
|
||
}
|
||
// besoin au minimum d'un titre et d'une url
|
||
if((!empty($maj[$i]["designation"]))&&(!empty($maj[$i]["url"])))
|
||
$i++;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
$entries=$doc->getElementsByTagName("entry");
|
||
if($entries->length!=0)
|
||
{
|
||
foreach($entries as $item)
|
||
{
|
||
if($i<$nb_max)
|
||
{
|
||
if(!empty($item->getElementsByTagName("title")->item(0)->firstChild->textContent))
|
||
$maj[$i]["designation"]=html_entity_decode(str_replace("","'",trim(strip_tags($item->getElementsByTagName("title")->item(0)->firstChild->textContent))));
|
||
if(!empty($item->getElementsByTagName("summary")->item(0)->firstChild->textContent))
|
||
$maj[$i]["description"]=html_entity_decode(str_replace("","'",trim(strip_tags($item->getElementsByTagName("summary")->item(0)->firstChild->textContent))));
|
||
else if(!empty($item->getElementsByTagName("content")->item(0)->firstChild->textContent))
|
||
$maj[$i]["description"]=html_entity_decode(trim($item->getElementsByTagName("content")->item(0)->firstChild->textContent));
|
||
|
||
if(!empty($item->getElementsByTagName("link")->item(0)->getAttribute("href")))
|
||
$maj[$i]["url"]=str_replace("&","&",trim(strip_tags($item->getElementsByTagName("link")->item(0)->getAttribute("href"))));
|
||
// attention, il peut y avoir +sieurs balises link
|
||
$j=0;
|
||
while(null!=$item->getElementsByTagName("link")->item($j))
|
||
{
|
||
if((!empty($item->getElementsByTagName("link")->item($j)->getAttribute("href")))&&($item->getElementsByTagName("link")->item($j)->getAttribute("rel")=="alternate")&&($item->getElementsByTagName("link")->item($j)->getAttribute("type")=="text/html"))
|
||
{
|
||
$maj[$i]["url"]=str_replace("&","&",trim(strip_tags($item->getElementsByTagName("link")->item($j)->getAttribute("href"))));
|
||
break(1);
|
||
}
|
||
$j++;
|
||
}
|
||
if((empty($maj[$i]["url"]))&&($j==1)&&(!empty($item->getElementsByTagName("link")->item(0)->getAttribute("href"))))// les propriétés du lien n'ont pas toutes été fournies.
|
||
$maj[$i]["url"]=str_replace("&","&",trim(strip_tags($item->getElementsByTagName("link")->item(0)->getAttribute("href"))));
|
||
if(!empty($item->getElementsByTagName("updated")->item(0)->firstChild->textContent))
|
||
{
|
||
$maj[$i]["date_article"]=trim($item->getElementsByTagName("updated")->item(0)->firstChild->textContent);
|
||
$date_maj=date_create($maj[$i]["date_article"]);
|
||
if(!empty($date_maj))
|
||
$maj[$i]["timeS"]=$date_maj->getTimestamp();
|
||
$date_maj=null;
|
||
}
|
||
}
|
||
// besoin au minimum d'un titre et d'une url
|
||
if((!empty($maj[$i]["designation"]))&&(!empty($maj[$i]["url"])))
|
||
$i++;
|
||
}
|
||
}
|
||
}
|
||
if(count($maj)!=0)
|
||
return $maj;
|
||
else
|
||
return null;
|
||
}
|
||
/**
|
||
* Lit les items d'un flux RSS ou Atom non conforme et ne pouvant donc être chargé avec DOMDocument.
|
||
* //à revoir, bug encodage (?) avec des <20> qui apparaissent après les Reg
|
||
*
|
||
* @param $nb_max nombre maximum d'items que l'on souhaite récupérer, $xml le contenu du fichier à traiter, $log_erreur pour savoir si on enregistre les erreurs de lecture dans le journal
|
||
* @return tableau listant les infos du flux, false si erreur
|
||
* @author Fabrice PENHOËT
|
||
**/
|
||
public function lecture_reg($nb_max=1000,$xml,$log_erreur)
|
||
{
|
||
if(!is_int($nb_max))
|
||
{
|
||
$ajout_journal=new journal_erreurs(array(__FILE__,__LINE__,ERREUR_PARAM_FORMAT));
|
||
return false;
|
||
}
|
||
if(empty($xml))
|
||
{
|
||
$ajout_journal=new journal_erreurs(array(__FILE__,__LINE__,ERREUR_PARAM_MANQUANT));
|
||
return false;
|
||
}
|
||
else
|
||
$xml=str_replace("&","&",$xml);//plus de bug ici
|
||
//est-ce que ça ressemble à un flux ?
|
||
if(strpos($xml,"</channel>")!==false)
|
||
$this->set_type("RSS");
|
||
elseif(strpos($xml,"</feed>")!==false)
|
||
$this->set_type("Atom");
|
||
else
|
||
{
|
||
if($log_erreur)
|
||
$ajout_journal=new journal_erreurs(array(__FILE__,__LINE__,ERREUR_FLUX_INFOS." >> ".htmlentities($this->url,ENT_QUOTES)));
|
||
return false;
|
||
}
|
||
$maj=array();
|
||
$i=0;
|
||
if($this->type=="RSS")
|
||
{
|
||
// liste des items trouvés dans le flux
|
||
$items=preg_split("#<\/?item>#i",$xml);
|
||
// date du flux utile si pas de date spécifiée pour chaque article.
|
||
$get_date_flux=preg_split("#<\/?lastBuildDate>#i",$xml);
|
||
if(!empty($get_date_flux[1]))
|
||
$date_flux=$get_date_flux[1];
|
||
for($j=1;$j<sizeof($items)-1;$j+=2)
|
||
{
|
||
// il peut y avoir +sieurs balises <title> et le type="html" n'est pas toujours déclaré... Je considère ici que le premier trouvé est le bon.
|
||
preg_match("#<title(?: (?:\w+)=\"(?:\w+)\")*>(.*)</title>?#i",$items[$j],$item_title);
|
||
if(!empty($item_title[1]))
|
||
$maj[$i]["designation"]=html_entity_decode(str_replace("","'",trim(strip_tags(str_replace("]]>","",str_replace("<![CDATA[","",$item_title[1]))))));
|
||
preg_match("#<description(?: (?:\w+)=\"(?:\w+)\")*>(.*)</description>?#i",$items[$j],$item_description);
|
||
if(!empty($item_description[1]))
|
||
$maj[$i]["description"]=html_entity_decode(str_replace("","'",trim(strip_tags(str_replace("]]>","",str_replace("<![CDATA[","",$item_description[1]))))));
|
||
preg_match("#<link(?: (?:\w+)=\"(?:\w+)\")*>(.*)</link>?#i",$items[$j],$item_link);
|
||
if((!empty($item_link[1]))&&(filter_var($item_link[1],FILTER_VALIDATE_URL)))
|
||
$maj[$i]["url"]=trim(strip_tags($item_link[1]));
|
||
$item_date=preg_split("#<\/?pubDate>#i",$items[$j]);
|
||
if(!empty($item_date[1]))
|
||
$maj[$i]["date_article"]=$item_date[1];
|
||
elseif(!empty($date_flux))
|
||
$maj[$i]["date_article"]=$date_flux;
|
||
if(!empty($maj[$i]["date_article"]))
|
||
{
|
||
$date_maj=date_create($maj[$i]["date_article"]);
|
||
if(!empty($date_maj))
|
||
$maj[$i]["timeS"]=$date_maj->getTimestamp();
|
||
$date_maj=null;
|
||
}
|
||
//au moins un titre et une url
|
||
if((!empty($maj[$i]["designation"]))&&(!empty($maj[$i]["url"])))
|
||
$i++;
|
||
else
|
||
$maj[$i]=null;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// liste des items trouvés dans le flux
|
||
$items=preg_split("#<\/?entry>#i",$xml);
|
||
// date du flux utile si pas de date spécifiée pour chaque article.
|
||
$get_date_flux=preg_split("#<\/?updated>#i",$xml);
|
||
if(!empty($get_date_flux[1]))
|
||
$date_flux=$get_date_flux[1];
|
||
for($j=1;$j<sizeof($items)-1;$j+=2)
|
||
{
|
||
// il peut y avoir +sieurs balises <title> et le type="html" n'est pas toujours déclaré... Je considère ici que le premier trouvé est le bon.
|
||
preg_match("#<title(?: (?:\w+)=\"(?:\w+)\")*>(.*)</title>?#i",$items[$j],$item_title);
|
||
if(!empty($item_title[1]))
|
||
$maj[$i]["designation"]=html_entity_decode(str_replace("","'",trim(strip_tags(str_replace("]]>","",str_replace("<![CDATA[","",$item_title[1]))))));
|
||
preg_match("#<summary(?: (?:\w+)=\"(?:\w+)\")*>(.*)</summary>?#i",$items[$j],$item_description);
|
||
if(!empty($item_description[1]))
|
||
$maj[$i]["description"]=html_entity_decode(str_replace("","'",trim(strip_tags(str_replace("]]>","",str_replace("<![CDATA[","",$item_description[1]))))));
|
||
else
|
||
{
|
||
preg_match("#<content(?: (?:\w+)=\"(?:\w+)\")*>(.*)</content>?#i",$items[$j],$item_description);
|
||
if(!empty($item_description[1]))
|
||
$maj[$i]["description"]=html_entity_decode(str_replace("","'",trim(strip_tags(str_replace("]]>","",str_replace("<![CDATA[","",$item_description[1]))))));
|
||
}
|
||
//attention + sieurs href dans certains flux mais le 1er doit être le bon... -> pas certain ! à revoir !
|
||
preg_match("#href=\"(.+?)\"#",$items[$j],$item_link);
|
||
if((!empty($item_link[1]))&&(filter_var($item_link[1],FILTER_VALIDATE_URL)))
|
||
$maj[$i]["url"]=str_replace("&","&",trim(strip_tags($item_link[1])));
|
||
$item_date=preg_split("#<\/?updated>#i",$items[$j]);
|
||
if(!empty($item_date[1]))
|
||
$maj[$i]["date_article"]=$item_date[1];
|
||
elseif(!empty($date_flux))
|
||
$maj[$i]["date_article"]=$date_flux;
|
||
if(!empty($maj[$i]["date_article"]))
|
||
{
|
||
$date_maj=date_create($maj[$i]["date_article"]);
|
||
if(!empty($date_maj))
|
||
$maj[$i]["timeS"]=$date_maj->getTimestamp();
|
||
$date_maj=null;
|
||
}
|
||
//au moins un titre et une url
|
||
if((!empty($maj[$i]["designation"]))&&(!empty($maj[$i]["url"])))
|
||
$i++;
|
||
else
|
||
$maj[$i]=null;
|
||
}
|
||
}
|
||
if(count($maj)!=0)
|
||
return $maj;
|
||
else
|
||
return null;
|
||
}
|
||
} |