hellofacteurV1/modele/flux.php

402 lines
16 KiB
PHP
Raw Permalink Normal View History

2021-11-02 11:23:49 +01:00
<?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(" ","","&#38;","&");
$cara_remplace=array("","","&amp;","&amp;");
$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("&amp;","&",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("&amp;","&",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("&amp;","&",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("&amp;","&",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("&amp;","&",$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("&amp;","&",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;
}
}