[php5/dom] classe de creation de flux rss via un fichier xml

Soyez le premier à donner votre avis sur cette source.

Vue 8 201 fois - Téléchargée 461 fois

Description

Cette classe permet de creer un flux rss (version 2.0) grace a un fichier xml. Il y a 4 methodes :
- CreateChannel() qui permet de creer un channel avec son propre id
- DeleteItem() qui permet d'effacer un channel existant
- CreateItem() qui cree un nouvel item dans un channel existant
- DeleteItem() qui permet d'effacer les items d'un channel (avec possibilite de selection de ceux conserver)

Une autre fonction est XMLReader() qui renvoi le contenu d'un fichier (peut etre utile dans certains cas).
La classe cree automatiquement le fichier si il n'existe pas.

Source / Exemple :


<?php
/*
	|----------|
	|Modele RSS|
	|----------|
	
	<?xml version="1.0" encoding="iso-8859-1"?>
	<rss version="2.0">
		<channel id="">
			<description></description>
			<title></title>
			<link></link>
			<language></language>
			<webMaster></webMaster>
			<copyright></copyright>
			<item>
				<title></title>
				<link></link>
				<pubDate></pubDate>
				<description></description>
				<author></author>
			</item>
		</channel>
	</rss>
	
	Nom du code : CRss v 1.1
	Auteur : IoNAce (allias jean84)
	Mail : ionace@c4.fr
	Type de code : Classe permettant la creation d'un fichier rss (format xml) avec mise a jour dynamique du fichier
	Version php : 5 
	Remerciements : A Malalam (admin de CS) qui m'a beaucoup aide grace a ses reponses toujours pertinentes
	
	NOTE : Toutes les fonctions ( sauf XMLReader() ) renvoient la valeur NO_ERROR en cas de succees.
	Sinon, elles renvoient une valeur du tableau $TableOfErrors.

  • /
class CRss { /********************************************************************************/ /* Permet a la classe de connaitre le nom du fichier XML sur lequel travailler */ /********************************************************************************/ private $NameOfXML; /********************************************************************/ /* Permet a la classe de n'ouvrir qu'une seul fois le document XML */ /********************************************************************/ private $Handle; /********************************************************************************************/ /* Tableau contenan toutes les erreurs poivant intervenir durant l'utilisation de la classe */ /********************************************************************************************/ private $TableOfErrors = array( 'NO_XML_FILE', // Appel du constructeur invalide : fichier XML manquant 'CANOT_OPEN_FILE', // Impossible d'ouvrir le fichier specifie 'CANOT_READ_FILE', // Impossible de lire le fcihier specifie 'CHAN_ID_ALLREADY_USED', // L'ID choisi est deja utilise par un autre canal 'NO_CHAN_FOR_THIS_ID', // Aucun canal ne correspond a cet ID 'NO_VALIDATE_RSS_DOCUMENT', // Le document ne contient aucune balise RSS (document non-valide) 'NO_ERROR' // Pas d'erreur ); /************************************************************************************/ /* Constructeur de la classe */ /* Param 1 = $FileXML */ /* [-> Nom du fichier XML a charger. Si le fichier n'existe pas, il sera cree. */ /************************************************************************************/ function __construct($FileXML='') { // Verification if ( empty($FileXML) ) ReturnLastError(0); // On desactive le rapport d'erreur error_reporting(0); // On sauvegarde le nom du fichier en cas de besoin $this->NameOfXML = $FileXML; // Creation d'un nouvel Handle $this->Handle = new DOMDocument('1.0', 'iso-8859-1'); // Si le fichier n'existe pas, on le cree if ( !file_exists($FileXML) ) $this->CreateXMLRSS(); else $this->Handle->load($FileXML); } /****************************************************************************************************************/ /* Creer un fichier RSS avec XML */ /* Aucun param. */ /* [-> Cette fonction cree une balise racine <rss version="2.0"> et sauvegarde le resultat dans un fichier */ /****************************************************************************************************************/ private function CreateXMLRSS() { $HandleXML = $this->Handle; // Creation du noeud racine <rss version="2.0"></racine> $Racine = $HandleXML->createElement('rss'); $Racine->setAttribute('version', '2.0'); $Racine = $HandleXML->appendChild($Racine); // On sauvegarde le fichier $HandleXML->save($this->NameOfXML); } /********************************/ /* Renvoi une date preformatte. */ /* Aucun argument. */ /********************************/ private function GetDateToday() { $TableJour = array('dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'); $TableMois = array('janvier', 'fevrier', 'mars', 'avril', 'mai', 'juin', 'juillet', 'aout', 'septembre', 'octobre', 'novembre', 'decembre'); return $TableJour[date('w')].' '.date('j').' '.$TableMois[date('n')-1].' - '.date('H:i'); } /************************************************/ /* Lit le fichier XML et renvoi son contenu */ /* Aucun param */ /************************************************/ public function XMLReader() { // On ouvre le fichier en lecture $File = fopen($this->NameOfXML, 'rb'); if ( $File === FALSE ) return $TableOfErrors[1]; // On obtient la taille en nombre de caracteres du fichier XML $SizeOfFile = filesize($this->NameOfXML); // Mise en memoire du contenu $Buffer = fread($File, $SizeOfFile); if ( $Buffer === FALSE ) return $TableOfErrors[2]; // On referme le fichier fclose($File); // On renvoi ce que l'on vient de lire return $Buffer; } /************************************************************************/ /* Cree un nouveau canal RSS */ /* Param 1 = $ID */ /* [-> ID propre a ce canal. Doit etre unique pour chaque canal ! */ /* Param 2 = $Description */ /* [-> String permettant de decrire le contenu du canal */ /* Param 3 = $Title */ /* [-> Titre du canal */ /* Param 4 = $Link */ /* [-> Lien vers le site publiant le fichier RSS */ /* Param 5 = $Language */ /* [-> Langue du canal */ /* Param 6 = $MailWebmaster */ /* [-> E-mail du webmaster publiant le fichier RSS */ /* Param 7 = $Copyright */ /* [-> Copyright applique au contenu du fichier RSS */ /************************************************************************/ public function CreateChannel($ID='', $Description='', $Title='', $Link='', $Language='', $MailWebmaster='', $Copyright='') { // Recupere la Handle transmis par la classe $HandleXML = $this->Handle; // Verification $XPath = new DOMXPath($HandleXML); $Value = $XPath->query('/rss[@version="2.0"]/channel[@id="'.$ID.'"]'); // Si un channel existe deja avec l'id voulue, la requete XPath renverra un domnodelist contenant des liens (item) // vers des domnodes. Si ce n'est pas le cas, c'ets quie le channel en question n'existe pas donc on eut le creer // sans probleme if ( empty($Value->item(0)->nodeValue) ) { // --> On se place sur le noeud racine <rss> $Rss = $HandleXML->getElementsByTagName('rss')->item(0); // --> On cree l'element <channel> enfant de rss $ChannelElement = $HandleXML->createElement('channel'); $ChannelElement->setAttribute('id', $ID); $ChannelElement = $Rss->appendChild($ChannelElement); // On cree toutes les balises filles de <channel>. Ici <description> $DescriptionElement = $HandleXML->createElement('description'); $DescriptionElement = $ChannelElement->appendChild($DescriptionElement); $DescriptionValue = $HandleXML->createTextNode($Description); $DescritpionValue = $DescriptionElement->appendChild($DescriptionValue); // <title> $TitleElement = $HandleXML->createElement('title'); $TitleElement = $ChannelElement->appendChild($TitleElement); $TitleValue = $HandleXML->createTextNode($Title); $TitleValue = $TitleElement->appendChild($TitleValue); // <link> $LinkElement = $HandleXML->createElement('link'); $LinkElement = $ChannelElement->appendChild($LinkElement); $LinkValue = $HandleXML->createTextNode($Link); $LinkValue = $LinkElement->appendChild($LinkValue); // <language> $LanguageElement = $HandleXML->createElement('language'); $LanguageElement = $ChannelElement->appendChild($LanguageElement); $LanguageValue = $HandleXML->createTextNode($Language); $LanguageValue = $LanguageElement->appendChild($LanguageValue); // <webMaster> $MailWebmasterElement = $HandleXML->createElement('webMaster'); $MailWebmasterElement = $ChannelElement->appendChild($MailWebmasterElement); $MailWebmasterValue = $HandleXML->createTextNode($MailWebmaster); $MailWebmasterValue = $MailWebmasterElement->appendChild($MailWebmasterValue); // <copyright> $CopyrightElement = $HandleXML->createElement('copyright'); $CopyrightElement = $ChannelElement->appendChild($CopyrightElement); $CopyrightValue = $HandleXML->createTextNode($Copyright); $CopyrightValue = $CopyrightElement->appendChild($CopyrightValue); // <-- Grace aux balises ajoutees, <channel> se ferme ici (</channel>) automatiquement // <-- Pareille pour la balise <rss> qui prend fin ici // Sauvegarde $HandleXML->save($this->NameOfXML); // Pas d'erreur return $TableOfErrors[6]; } else { return $TableOfErrors[3]; } } /****************************************/ /* Efface un canal RSS grace a son id */ /* Param 1 = $ID */ /* [-> ID du canal a effacer. */ /****************************************/ public function DeleteChannel($ID='') { // Recupere le Handle fournis par la classe $HandleXML = $this->Handle; $XPath = new DOMXPath($HandleXML); // Recupere rss $Rss = $HandleXML->getElementsByTagName('rss'); // On verifie que le noeud n'est pas vide if ( is_object($Rss->item(0)) ) { // On ne prend que le premier groupe de balise (si jamais il y a plusieurs balise rss, elles seront ignores) $Rss = $Rss->item(0); // Requete XPath pour recuperer les enfants de rss valide $Element = $XPath->query('/rss[@version="2.0"]/channel[@id="'.$ID.'"]'); // On verifie que le noeud Element n'est pas vide if ( empty($Element->item(0)->nodeValue) === false ) { // Parcours des enfants de l'element obtenu foreach ( $Element as $Index => $Value ) { // On detruit chaque enfant du noeud en cours $Rss->removeChild($Value); } // Sauvegarde du traitement (on suppose qu'il y a eu des modifications si on a atteri ici) $HandleXML->save($this->NameOfXML); // Pas d'erreur return $TableOfErrors[6]; } else { return $TableOfErrors[4]; } } else { return $TableOfErrors[5]; } } /****************************************************************/ /* Function permettant de creer un nouvel item dans un canal */ /* Param 1 = $IDSource */ /* [-> ID de l'element channel parent de l'item */ /* Param 2 = $Title */ /* [-> Titre du nouvel item */ /* Param 3 = $Link */ /* [-> Lien vers l'article correspondant a l'item */ /* Param 4 = $Description */ /* [-> Descriptif de l'item */ /* Param 5 = $MailAuthor */ /* [-> E-mail de l'autheur de l'article */ /****************************************************************/ public function CreateItem($IDChan='', $Title='', $Link='', $Description='', $MailAuthor='') { // Recupere le Handle fournis par la classe $HandleXML = $this->Handle; // Expression XPath recuperant l'id du channel concerne $XPath = new DOMXPath($HandleXML); $XQuery = '/rss[@version="2.0"]/channel[@id="'.$IDChan.'"]'; $ChannelElement = $XPath->query($XQuery)->item(0); // Verifie si $ChannelElement est un objet renvoye par DOMNodeList->item(). Sinon c'est que le chan n'existe pas if ( is_object($ChannelElement) ) { // --> Balise <item> $Item = $HandleXML->createElement('item'); $Item = $ChannelElement->appendChild($Item); // Creation de la balise <title> $TitleElement = $HandleXML->createElement('title'); $TitleElement = $Item->appendChild($TitleElement); $TitleValue = $HandleXML->createTextNode($Title); $TitleValue = $TitleElement->appendCHild($TitleValue); // Creation de la balise <link> $LinkElement = $HandleXML->createElement('link'); $LinkElement = $Item->appendChild($LinkElement); $LinkValue = $HandleXML->createTextNode($Link); $LinkValue = $LinkElement->appendChild($LinkValue); // creation de la balise <pubDate> $DateElement = $HandleXML->createELement('pubDate'); $DateElement = $Item->appendChild($DateElement); $DateValue = $HandleXML->createTextNode(ucfirst($this->GetDateToDay())); $DateValue = $DateElement->appendChild($DateValue); // Creation de la balise <description> $DescritpionElement = $HandleXML->createElement('description'); $DescriptionElement = $Item->appendChild($DescritpionElement); $DescriptionValue = $HandleXML->createTextNode($Description); $DescriptionValue = $DescriptionElement->appendChild($DescriptionValue); // Creation de la balise <author> $AuthorElement = $HandleXML->createElement('author'); $AuthorElement = $Item->appendChild($AuthorElement); $AuthorValue = $HandleXML->createTextNode($MailAuthor); $AutorValue = $AuthorElement->appendChild($AuthorValue); // <-- Fin de la balise <item> // Sauvegarde $HandleXML->save($this->NameOfXML); // Pas d'erreur return $TableOfErrors[6]; } else { return $TableOfErrors[4]; } } /********************************************************************/ /* Vide tous les items d'un channel */ /* Param 1 = $IDChannel */ /* [-> ID du canal a vider */ /* Param 2 = $TableOfExeption */ /* [-> Tableau contenant les titres des items a ne pas effacer */ /********************************************************************/ public function DeleteItem($IDChannel='', $TableOfExeption='') { // Recupere le Handle fournis par la classe $HandleXML = $this->Handle; // Indque si le $TableOfExeption est vide ou non if ( empty($TableOfExeption) ) $MakeExeption = false; else $MakeExeption = true; // Expression XPath recuperant l'id du channel concerne $XPath = new DOMXPath($HandleXML); $XQuery = '/rss[@version="2.0"]/channel[@id="'.$IDChannel.'"]'; $ChannelElement = $XPath->query($XQuery)->item(0); // Verifie si $ChannelElement est un objet renvoye par DOMNodeList->item(). // Si ce n'est pas le cas, c'est que le chan n'existe pas if ( is_object($ChannelElement) ) { // Expression recuperant toutes les balises item de la balise channel concerne $XQuery = '/rss[@version="2.0"]/channel[@id="'.$IDChannel.'"]/item'; $ItemElements = $XPath->query($XQuery); // on efface toutes les node <item> du channel foreach ( $ItemElements as $Node ) { // Permet de savoir si on doit effacer l'item ou pas $DeleteItem = true; // Si un tableau d'exeption a ete transmis, on verifie les enfants de l'item en cours pour recherchee les exeptions // Sinon, on efface directement sans chercher a comprendre :P if ( $MakeExeption ) { // Verifie que le titre de l'item en cours d'effacement n'est pas dans le tableau d'exeption. // Si c'est le cas, on ne l'efface pas $TilteElement = $Node->childNodes; // Parcours de tous les enfants foreach ( $TilteElement as $ChildNodeOfTitle ) { // Si on tombe sur la balise titre if ( $ChildNodeOfTitle->nodeName == 'title' ) { // On verifie si elle est dans le tableau d'exeption if ( in_array($ChildNodeOfTitle->nodeValue, $TableOfExeption) ) $DeleteItem = false; // On arrete la boucle car on a trouve ce que l'on cherchait break; } } } // Apres parcours des elements, si l'item a ete identife et doit etre sauvegarde, on ne fais rien. // Sinon, on supprime if ( $DeleteItem ) $ChannelElement->removeChild($Node); } // Sauvegarde $HandleXML->save($this->NameOfXML); // Pas d'erreur return $TableOfErrors[6]; } else { return $TableOfErrors[4]; } } } ?>

Conclusion :


Petite info sur la fonction DeleteItem() :
Cette fonction attend comme argument un tableau qui contient tous les titres des items a ne pas effacer. Il est possible en quelques secondes de changer le profil de recherche et de ne selectionner que les dates par exemple. J'ai choisi les titres car je n'etais pas sur de la syntaxe a utiliser pour les dates (y en a tellement de differents sur les exemples que j'ai pu voir que j'ai choisi une facon de faire arbitraire). Si vous souhaitez modifier cette syntaxe, il suffit tout simplement de modifier la fonction GetDateToday(), la classe fait appel a elle automatiquement lorsqu'elle en a besoin.

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

cs_jean84
Messages postés
450
Date d'inscription
jeudi 26 août 2004
Statut
Membre
Dernière intervention
5 mars 2009
-
Etant donne que c'est mon premier code du genre et que j'ai du apprendre sur le tas, il n'est evidement pas exclu que le code soit imparfait.
J'attend donc vos suggestions/commentaires !

Merci ;-)
malalam
Messages postés
10844
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
17 -
hello jean,

je n'ai pas eu le temps d'aller uploader ton code avant que tu ne le mettes ici, désolé, je suis un peu "sous l'eau" en ce moment.
Mais comme j'ai un petit moment ce soir, j'en profite pour mater un peu ce que tu nous as concocté :-)
Je ne vais pas pouvoir approfondir ni tester ce soir, mais ...d'emblée, ça a l'air pas mal!
Je devance une remarque que l'on te fera sûrement : quand tu utilises une fonction qui ne renvoie que true ou false, le === true est inutile. MAIS...cela ne nuit pas non plus, et peut très bien entrer dans le cadre d'une standardisation du code. Donc, pourquoi pas.
Ceci dit :
if ( empty($Element->item(0)->nodeValue) === false )
c'est carrémént perturbant, pour moi...question d'habitude, sans doute.
Un plus pour l'utilisation de XPath afin de palier à l'éventulle défaillance de DOMDocument::getElementById() sur certains systèmes...:-)
Même si xml:id est tout aussi efficace, lol.

Par contre, je ne comprends pas pourquoi dans CRss::CreateXMLRSS() tu passes par une variable temporaire pour créer l'amorce de ton fichier xml et le sauvegarder dans le fichier passé en paramètre au constructeur. Pourquoi ne pas avoir utilisé directement le flux en tant que propriété de ta classe ? De plus, pour la réation, j'aurais plutôt passé le nom du fichier dans la méthode initialisant la création. Idem pour la lecture, en fait.
Ou via un setter. (__set)
Parce que là, tu te trimbales plein de $handleXML qui sont inutiles, à mon avis. Et cela permettrait d'utiliser une seule instance pour traiter plusieurx flux. Là, il faut instancier un nouvel objet à chaque fois qu'on veut changer de flux.
au lieu de tes echo, il eu mieux valu une gestion des erreurs laissant l'opportunité à un intégrateur de créer son interface récupérant les erreurs/alertes générées par ta classe, et affichant ce qu'il veut. En l'état, c'est inutilisable dans le cadre d'une intégration. Et chiant à modifier :-) Tu devrais centraliser ça, par exemple dans un tableau de messages, avec des codes de message. Modifiables.
Tien, je me rends compte que tu initialise une propriété non présente dans les déclaration des propriétés de ta classe, dans le constructeur :
$this->HandleXML = new DOMDocument('1.0', 'iso-8859-1');
Et je ne vois pas où tu l'utilises ensuite, en plus ?

Sinon, c'est pas mal! Y a du boulot, et des possibilités. Une utilisation de DOM qui reste simple et efficace :-)
cs_jean84
Messages postés
450
Date d'inscription
jeudi 26 août 2004
Statut
Membre
Dernière intervention
5 mars 2009
-
Merci beaucoup Malalam de tes conseils !

Pour repondre a ta (tes) question(s) :
- j'avais bel et bien au debut utilise, lors de l'appel au constructeur, un seul HandleXML pour toute la classe. Malheureusement, etant encore novice dans la gestion des nodes, je me suis retrouve avec des erreurs partout car j'utilisais a chaque fois le pointeur de l'element DOMDocument dans mes fonctions ce qui faisait "perdre" son statut (je crois qu'il se transformer en DOMElement ou quelque chose dans le meme ton). Pour prevenir tout bug pendant la conception, j'ai pris l'initiative d'ouvrir un nouvel Handle a chaque fonction pour eviter ce genre de probleme (je sai spas si j'ai ete clair). C'ets vrai que maintenant que j'ai mieux compris le DOM (enfin ! ^^), je vais m'attacher a corriger sa (c'est un peu comme si j'avais compile en debug plutot qu'en release en fait ^^)

- pour le ===, grand moment de solitude. Vu qu'on en avait parler sur ce topic => http://www.phpcs.com/codes/LECTURE-TOUS-SOUS-DOSSIERS-FICHIERS-REPERTOIRE_39422.aspx, je pensais avoir compris qu'il fallait en mettre partout .... apparement pas ^^ Si tu pouvais m'expliquer STP !! Parce que moi ecrire if ( $Var === true ) sa me choque grave a chaque fois que je code sa (je viens du C++ alors forcement)

- je suis ravi que tu ai vus ma petite modif en XPath ;-) C'est vrai que je m'en suis fait une motagne alors que finallement, avec un peu de rigueur c'est relativement digeste. Bon par contre c'est evident que je dois utiliser 10% des capacites de ce language mais bon, faut bien commence quelque part !

- if ( empty($Element->item(0)->nodeValue) false ) a part le false qui doit etre choquant, le reste ne vas pas bien ? parce que certaine classe renvoi un DOMNodeList vide en guise de reponse (super ...) donc c'est le seul moyen de tester si un noeud est vide ou pas. J'ai bô essayer la propriete leght, rien y fait cela me renvoi toujours 0 (en fait rien donc je suppose que c'est 0)

En tout cas merci de ton commentaire, c'est tres encourageant ! Je vais faire en sorte de mettre a jour la classe rapidement pour etre au top (cette classe va servir pour un site avec lequel je travaille et qui va bientot passer en V3)

@++
xque19
Messages postés
47
Date d'inscription
dimanche 20 février 2005
Statut
Membre
Dernière intervention
19 novembre 2006
1 -
Salut!

Un petit récapitulatifs des différents opérateurs de PHP. :)

Exemple Nom Résultat
$a == $b Egal TRUE si $a est égal à $b .
$a === $b Identique TRUE si $a est égal à $b et qu'ils sont de même type (introduit en PHP 4).
$a != $b Différent TRUE si $a est différent de $b .
$a <> $b Différent TRUE si $a est différent de $b .
$a !== $b Différent TRUE si $a est différent de $b ou bien
qu'ils ne sont pas du même type. (introduit en PHP 4)
$a < $b Plus petit que TRUE si $a est strictement plus petit que $b .
$a > $b Plus grand TRUE si $a est strictement plus grand que $b .
$a <= $b Inférieur ou égal TRUE si $a est plus petit ou égal à $b .
$a >= $b Supérieur ou égal TRUE si $a est plus grand ou égal à $b .

++
cs_jean84
Messages postés
450
Date d'inscription
jeudi 26 août 2004
Statut
Membre
Dernière intervention
5 mars 2009
-
Salut !

Merci pour ton commentaire xque19 mais je ne suis quand meme pas a ce point ! La ou j'ai fait une erreur, c'est dans l'utilisation des === qui compare 2 types de donnees identiques. Ce n'etait meme pas une erreur mais c'en fait un defaut d'optimisation ^^, a ne pas confondre ;-)

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.