Créer un flux ATOM en PHP structure encodage et format des dates
Pour coder un flux RSS ou un flux ATOM sur un site, il faut d'abord savoir comment l'organiser. Ne nous prenons pas la tête dans les normes et standards, spécifications RFC... Dotclear l'a fait. Sous forme d'un fichier de template, c'est plus facile à appréhender. Dans un premier temps j'utilise ces derniers, en ajoutant mes commentaires pour faire ce mémo. Plus loin, j'ai noté la façon de générer les dates au bon format et d'encoder le contenu des éléments du flux.
Structure
l’entête
<?xml version="1.0" encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xml:lang="fr"> <title type="html">__LE TITRE DU FLUX ENCODÉ POUR L'XML__</title> <subtitle type="html">__LA DESCRIPTION DU SITE ENCODÉ XML__</subtitle> <link href="__LA PROPRE ADRESSE DE CE FLUX__" rel="self" type="application/atom+xml"/> <link href="__L'URL DU SITE__" rel="alternate" type="text/html"> title="__LE TITRE DU SITE__"/> <updated>__LA TOUTE DERNIERE DATE DE MODIFICATION__</updated> <author> <name>__L'AUTEUR__</name> </author> <id>L URL DU SITE</id> <generator uri="__BAH HEU L'ADRESSE DE VOTRE SITE__">__SELFMADE__</generator>
Chaque élément du flux:
chaque élément du flux commence par <entry> et est cloturé par </entry>
<entry> <title>LE TITRE DE LELEMENT</title> <link href="SON URL" rel="alternate" type="text/html" title="SON TITRE" /> <id>SON URL</id> <published>DATE DE PUBLICATION</published> <updated>LA DERNIERE DATE DE MODIFICATION</updated> <author><name>NOM DE L'AUTEUR</name></author> <dc:subject>SUJET, LA CHEZ DOTCLEAR ILS METTENT LA CATEGORIE</dc:subject> <dc:subject>SUJET IDEM, UN TAG PAR EXEMPLE</dc:subject> <content type="html">LE CONTENU</content> <link rel="enclosure" href="URL DE L'EVENTUELLE PIECE JOINTE" length="SA TAILLE" type="SON TYPE" /> <wfw:comment>L'URL DES EVENTUELS COMMENTAIRES</wfw:comment> <wfw:commentRss>LE FLUX DES COMMENTAIRES</wfw:commentRss> </entry>
Et on termine notre fichier par:
</feed>
Headers HTML
Le fichier Php, apache va l'envoyer avec comme mime type "text/html", il suffit de préciser dès le début du script php:
header('Content-type: application/atom+xml');
Le format des dates.
C'est le format ATOM, et je n'ai pas trouvé comment faire en sorte que MySQL le fournisse de la bonne manière directement. Pour récupérer le timestamp UNIX (format différent du timestamp MySQL), on fait la requête de cette manière:
SELECT UNIX_TIMESTAMP(createdtime) .....
createdtime est le nom de la colonne.
En en PHP pour obtenir la date au format ATOM à partir du timestamp unix, c'est simplement comme ça:
$DateAtom=date(DATE_ATOM, $VariableTimestampUnix);
L'encodage de l'HTML
Bah oui, on fournit des éléments au format html qui est un langage balisé tout comme le XML (l'ATOM est du XML),Pour qu'il n'y ait pas de confusion, il faut modifier ça.
Tout ce qui se trouve dans des balises indiquant type="html" ou type="text/html" doit etre traité préalablement. La function htmlentities de PHP doit être utilisée, avec l'option ENT_QUOTES. de cette manière:
htmlentities($string,ENT_QUOTES);
Quelques liens:
- Le service de validation des flux du w3c
- Un tuto sympa et complet, Comment créer un flux Atom en PHP, et pour quelles raisons. juste dommage que l'auteur l'ait alourdi avec des explications de ce qu'est une base de donnée, et du fonctionnement du serveur LAMP. (j'ai tendance à avoir ce défaut aussi dans la rédaction de billets, vouloir tout expliquer, puis finalement à la relecture, je supprime la moitié du contenu, car en soit... public averti only).
- Le standard atom rfc 4287
Conclusion
Si j'ai écrit ce billet c'est parce que j'ai mis un flux ATOM sur un site abandonné (edit de ce post en 2017)
Bon la structure de la base de données n'est pas un secret., voici en exemple le script PHP qui génère le flux ATOM de l'image board. Si ça peut aider de l'avoir sous les yeux.
<?php // by Gnieark 01/2011 http://blog-du-grouik.tinad.fr header('Content-type: application/atom+xml'); echo '<?xml version="1.0" encoding="utf-8"?>'; ?> <feed xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xml:lang="fr"> <title type="html">Image Board Tinad</title> <subtitle type="html">Board tinad est un image board, un site de partage de medias, francophone, sans inscription, anonyme</subtitle> <link href="http://board.tinad.fr/atom.php" rel="self" type="application/atom+xml"/> <link href="http://board.tinad.fr" rel="alternate" type="text/html" title="Image Board Tinad"/> <?php function username($string) { if ($string == ''){ return 'Anonyme'; }else{ return ($string); } } function contenu($id,$img,$comment) { //je fais le choix de mettre les commentaires dans le cotenu de l'élément sur ce site $html="<p><a href="http://board.tinad.fr/images/".$img.""><img src="http://board.tinad.fr/images/thumb-".$img."" alt="image"/></a><br />".$comment."</p>"; $rscomment=mysql_query("SELECT createdtime, media_filename, media_fileext,media_hasthumb,titre,commentaire,user_pseudo,id FROM reponses WHERE parent='".$id."' ORDER BY createdtime DESC"); while ($rcomment=mysql_fetch_row($rscomment)) { $html.="<p><b>Réponse de ".username($rcomment[6])." ".$rcomment[0]."</b></p><p>"; if ($rcomment[1]!= "") { $html.="<a href="http://board.tinad.fr/images/".$rcomment[1].".".$rcomment[2].""> <img src="http://board.tinad.fr/images/thumb-".$rcomment[1].".".$rcomment[2]."" alt="img" /></a><br />"; } $html.=$rcomment[5]."</p>"; } return $html; } include ("config.php"); if (!mysql_connect($config['mysql_host'], $config['mysql_user'], $config['mysql_password'])) { echo 'Impossible de se connecter à MySQL'; exit; } mysql_query("USE ".$config['mysql_database']); //Pour récupérer la date de modification la plus récente: $rupdtedtime=mysql_query("SELECT UNIX_TIMESTAMP(updatetime) FROM posts ORDER BY updatetime LIMIT 0,1"); $rsupdtedtime=mysql_fetch_row($rupdtedtime); $updtedtime=$rsupdtedtime[0]; //Requete pour trouver les 20 derniers éléments $sql="SELECT UNIX_TIMESTAMP(createdtime), media_filename, media_fileext, titre, commentaire, id,user_pseudo, nbe_reponses, UNIX_TIMESTAMP(updatetime) FROM posts ORDER BY createdtime DESC LIMIT 0,20"; $rs=mysql_query($sql); ?> <updated><?php echo date(DATE_ATOM, $updtedtime);?></updated> <author> <name>Gnieark</name> </author> <id>http://board.tinad.fr/</id> <generator uri="http://board.tinad.fr/">SELFMADE</generator> <?php while ($r=mysql_fetch_row($rs)) { //Là commence l'affichage des elements: ?> <entry> <title>Post <?php echo $r[5]." Par ".htmlentities(username($r[6])." - ".$r[3],ENT_QUOTES); ?></title> <link href="http://board.tinad.fr/index.php?post=<?php echo $r[5]; ?>" rel="alternate" type="text/html" title="<?php echo htmlentities($r[3]." Par ".username($r[6]),ENT_QUOTES); ?>" /> <id>http://board.tinad.fr/index.php?post=<?php echo $r[5]; ?></id> <published><?php echo date(DATE_ATOM, $r[0]);?></published> <updated><?php echo date(DATE_ATOM, $r[8]);?></updated> <author><name><?php echo username($r[6]); ?></name></author> <content type="html"><?php echo htmlentities(contenu($r[5],$r[1].".".$r[2],$r[7]),ENT_QUOTES); ?></content> </entry> <?php } ?> </feed>
Commentaires
Pour la date au format Atom, il suffit d'enregistrer avec date("c") dans un champ de la BDD
oui, à condition d'enregistrer la date dans un champs text ou varchar Intéressant, pour se simplifier les conversions.
La limite, c'est que tu ne pourras plus faire de ORDER BY tadate, car ton champs texte il va le classer par ordre alphabétique. mais en effet si ton appli n'en a pas besoin, faut pas se géner.
Bonsoir,
merci pour ce tutorial bien sympa et très complet ! J'ai justement à cette occasion suivi ce tuto pour créer le flux RSS du site de mon école. Tout marche à peu près mais j'ai l'impression que le flux ne marche pas très bien suivant les applications. Par exemple, le marque page dynamique de Firefox ne m'affiche aucun article, pareil quand j'essaye d'importer le flux dans un groupe LinkedIn...
Pourriez-vous m'expliquer d'où cela peut venir ?
Voici l'adresse du flux : http://imac.alwaysdata.net/rss.php .
Merci par avance
Bonjour,
Tous les éléments de votre flux ont le même id
http://imac.alwaysdata.net/index.ph...
Vu la façon dont est fait votre site, c'est pas évident car chaque actualité n'a pas une URL propre. Peut être qu'en modifiant un peu la structure du site et en ajoutant des ancres aux titres des actualités, puis dans le flux atom fournir dans l'id l'URL avec le lien vers l'ancre genre http://imac.alwaysdata.net/index.ph...
ça passera mieux au niveau des agrégateurs
Bonjour,
merci de votre réponse rapide, j'ai donc modifié en conséquence la structure de ma page d'actualité, elle peut maintenant prendre un id en paramètre pour afficher la news correspondante. Je génère donc maintenant dans mon flux des id propres à chaque article mais mon problème reste entier : curieusement le marque page dynamique firefox ne m'affiche tjs pas d'articles :(.
De chez moi ça marche:
Et ça passe sans erreur au w3c validate:
http://validator.w3.org/feed/check....
Et j'ai testé sous google reader, c'est OK aussi.
Je rajouterai juste un petit détail, pour chaque entry de préciser le link alternate:
par exemple:
<link href="http://board.tinad.fr/index.php?pos..." rel="alternate" type="text/html" title="poney Par Anonyme" />
ça permet d'avor un lien vers la page originale depuis le flux
Bonsoir,
les marques pages dynamiques marchent maintenant que j'ai ajouté le lien. Par contre, l'importation de ce flux reste tjs un problème dans des applications comme facebook ou linkedin mais, je m'en passerai : ce n'est pas grave.
Merci en tout cas pour votre aide.
Bonsoir, de rien au contraire, ça me fait plaisir d'avoir des retours, Ellny et toi se sont appuyés sur ce billet, c'est plutot cool.
Pour facebook, J'ai fait divers essais, à la moindre erreur html dans les contenus des billets, au moindre caractere qu'il n'aime pas, ou si certaines balises ont un style qui est indiqué dans la balise et pas dans le CSS, il rejete tout le flux.
Il y a peu de flux qui passent par facebook, et je me demande si ce n'est pas une stratégie de leur part... autant avant ils étaient dans un objectif d'attirer les gens vers facebook (donc s'ouvraient aux flux), à présent ils sont dans l'idée de les maintenir captif. donc éviter qu'ils rédigent ailleurs et inciter à la création d'applications facebook dont ils ont le contrôle.
Une solution alternative pour publier automatiquement sur facebook, c'est d'utiliser ping fm (il a des défauts) ou de coller le lien à la main à chaque nouvel article.