Mettre en place un système de flux RSS sur votre site

Comprendre le flux RSS

RSS, parfois appelé Rich Site Summary, ou Really Simple Syndication, parfois portant d'autres appellations : qu'est-ce exactement ?

Pour faire simple, un flux RSS est un concept abstrait, qui consiste à ouvrir depuis un logiciel (comme Mozilla Firefox, par exemple) une page Web ... un peu spéciale ! Cette page est en réalité une page écrite en langage XML, et est censée présenter - du moins utilisée ainsi dans la majorité quasi absolue des sites - les dernières nouveautés.

Un flux RSS, c'est un peu comme un fil d'info en continu : chaque fois que vous ferez appel à lui, il ira puiser dans l'adresse correspondante les dernières infos pour vous les présenter. Ce que j'appelle ici "les dernières infos" est, bien entendu, tout au goût du créateur du flux.

Voici quelques exemples concrets de l'utilité d'un flux RSS :

  • Votre site présente régulièrement des mises à jour, comme par exemple des nouveaux articles
  • Votre site comporte un forum, ou un élément dynamique que les visiteurs peuvent remplir et vous souhaitez que les gens puissent, d'un coup d'oeil rapide, prendre connaissance des derniers sujets abordés
  • Vous proposez un programme (un programme informatique, un programme de cinéma ... peu importe) et vous souhaitez mettre à disposition des gens les dernières sorties...

Afin que je m'assure que nous parlions de la même chose, j'ajoute que l'intérêt d'un flux RSS, outre le fait de centraliser plusieurs informations, permet leur consultation sans être "réellement" sur le site : en effet, vous pouvez tout à fait vous créer une seule page (qui peut être le logiciel même, soit dit en passant) qui affiche le contenu d'une dizaine de flux RSS, venant chacun de différents sites ... En très peu de temps, vous avez toutes les plus récentes informations de vos dix sites sous les yeux !

Généralement, on accède à un flux RSS par son adresse du type http://www.le_site.tld/rss.xml

Bien entendu, on peut "coder" un fichier XML à la main pour diffuser son adresse, mais s'il n'est pas régulièrement mis à jour, le flux RSS perd les 3/4 de son intérêt ... C'est un problème que nous résoudrons plus loin.

Les outils pour créer un flux RSS (et le lire)

Il n'y a pas besoin d'énormément d'outils pour générer un flux RSS ... Point de vue logiciels, il faut avoir un bloc notes (Notepad++, Kate, gedit, kwrite, PSPad, ...), mais le plus important est bien sûr de savoir quelles données présenter ... ! Enfin, il faut connaître un peu la façon de présenter les données et diffuser l'adresse de son flux !

Pour lire un flux RSS, il faut un "reader", un logiciel qui va partir du fichier XML fourni par le site distant pour le présenter à l'écran. Les plus connus : Mozilla Firefox, Internet Explorer (meilleure présentation dès la version 7), google.com/reader, Netvibes ...

Enfin, je terminerai ce paragraphe pour présenter 2 manières de faire :

  • Flux RSS dans un fichier XML statique, en clair, il s'agit d'écrire (ou de générer) le flux XML, l'enregistrer dans un fichier texte d'extension .xml et donner l'adresse de ce fichier à vos contacts. Cette manière est la moins pratique, dans la mesure où elle demande, à chaque mise à jour, de recréer le fichier ;
  • Flux RSS dans un fichier dynamique, cette fois, le contenu du fichier XML est généré à la volée lorsqu'un visiteur demande l'adresse du flux RSS. Très pratique puisque pas de fichier à mettre à jour (on puise directement dans la base de données), elle consomme des requêtes SQL (cas d'une base de données SQL) en plus.

Les normes RSS : ATOM, RSS 0.91, RSS 2.0

Il existe plusieurs normes pour le RSS. Je ne les détaillerai pas toutes ici parce que toutes n'ont pas besoin de l'être. D'autre part, les formats RSS 2.0 et ATOM 1.0 sont les plus répandus, ce sont les normes actuelles et tant qu'à faire d'étudier des normes, autant prendre celles qui servent de référence à l'heure actuelle !

Qu'est-ce qu'une norme pour un flux RSS ? C'est juste une sorte de "formatage de document" (oui, on peut formater un document !), c'est à dire une manière d'agencer les éléments constitutifs qui fait que tout fichier RSS qui suit cette norme sera écrit de la même manière, seules les données qu'il présente diffèreront.

Je peux très bien créer ma propre norme, qui demande ce modèle de document par exemple :

	<titre>mettre le titre ici</titre>
	<description>La description ici</description>
	<donnee>un exemple de données</donnee>
	<donnee>un exemple de données</donnee>
	<donnee>un exemple de données</donnee>
	<donnee>un exemple de données</donnee>
	<donnee>un exemple de données</donnee>
	<donnee>un exemple de données</donnee>
	<donnee>un exemple de données</donnee>

Ainsi tous les documents qui présenteront d'abord le titre, puis une description, puis les données respecteront ma norme. Bien entendu, celle-ci est totalement fictive et ne sera lue par aucun logiciel !

Au tout départ, du temps de Netscape, le RSS a commencé en version 0.91, que l'on trouve parfois encore... Je ne souhaite pas faire dans cet article un comparatif entre les différentes versions, je tiens juste à expliciter les 2 dernières versions à l'heure actuelle :

  • RSS 2.0, l'évolution (en quelque sorte) du format 0.91 initial
  • ATOM 1.0, une spécification que nous a pondu le W3C

Je ne crois pas qu'il y ait de version plus aboutie que l'autre, ou de version plus complète que l'autre : chacune a ses avantages et inconvénients, celle du W3C prend en compte des paramètres d'accessibilité bien entendu. ATOM, bien que plus jeune que RSS 2.0, a la particularité d'être un vrai standard du Web (W3C, IETF). Les blogs utilisent massivement le format RSS 2.0, c'est pour cela que je préfère présenter les 2 formats, puisqu'il est facile, au sein d'une même page de présenter les 2 formats.

Comme pour l'HTML ou le CSS, il existe un validateur RSS : http://feedvalidator.org/ ou celui du W3C : http://validator.w3.org/feed/

Construire un flux RSS

Dans cette partie, nous passons de la théorie à la pratique. nous allons générer un script, écrit en PHP, qui va interroger une base de données MySQL. Les 2 manières présentées plus haut seront explicitées, avec, pour chacune, le format ATOM 1.0 et RSS 2.0. (en réalité, la différence RSS 2.0 et ATOM 1.0 tient dans l'agencement des données c'est pour cela que mes exemples ci-dessous proposeront les 2 versions du même fichier XML).

Le principe est assez simple, on peut le décomposer en 3 étapes :

  1. Préparation des données source : lecture de la base, ordonnancement des données à présenter
  2. Génération du contenu du flux RSS (le contenu du fichier XML proprement dit)
  3. Présentation des données au visiteur

Nous allons ainsi réaliser, scindé en plusieurs parties, un fichier nommé "flux_rss.php".

Partie 1 : Base de données MySQL

Voici la base de données, qui présente les sorties de films, que nous allons utiliser.

id    Titre            Sortie        Acteur               Genre     Synopsis
-----------------------------------------------------------------------------
1     Wasabi           2001          Jean Reno            Action    Hubert doit se rendre au Japon pour y résoudre un problème sentimental ...

2     Air Force One    1997          Harrisson Ford       Action    L'avion du président des Etats Unis est pris en otage par des terroristes ...

3     Die Hard IV      2007          Bruce Willis         Action    John Mc Clane affronte cette fois-ci une bande de génies de l'informatique ...

On pourrait ajouter plein d'autres informations, pour le moment celles-ci suffiront. J'ai mis également la date de sortie, au format année, c'est purement arbitraire, cela me permet de simplifier plus tard la mise en forme des dates.

Je vais supposer maintenant que mon flux RSS (qu'il soit RSS 2.0 ou ATOM 1.0) doive donner la liste des X derniers films (par exemple les 10 derniers) sortis. Il n'y en a que 3 dans mon exemple, mais c'est pour le principe. (10 est un choix purement arbitraire, il y a moyen de l'améliorer). On se connecte à MySQL et on crée la requête qui rapatrie les 10 derniers films :

<?php
// le fichier flux_rss.php commence ici

/* **********************************
 * PARTIE 1 : BASE MYSQL
 * **********************************
 */
	// Préparation de la connexion
	// dans cet exemple, j'utilise une vieille méthode, allez voir l'article sur MySQL qui est plus à jour
	$mysql_host = 'serveur_mysql';
	$mysql_port = 3306;
	$mysql_usr  = 'utilisateur_mysql';
	$mysql_pwd  = 'mot_de_passe_mysql';
	$mysql_db   = 'nom_de_la_base_mysql';

	// connexion MySQL
	try
	{
		$connexion = new PDO('mysql:host='.$mysql_host.';port='.$mysql_port.';dbname='.$mysql_db, $mysql_usr, $mysql_pwd,array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
		$connexion->SetAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
	}
	catch(Exception $e)
	{
		echo 'Erreur : '.$e->getMessage().'
'; echo 'N° : '.$e->getCode(); exit(); } // Préparation de la requête $req_derniersfilms = 'SELECT id, titre, sortie, acteur, genre, synopsis FROM table_films ORDER BY sortie DESC LIMIT 0,10;'; $requete_prepare_1 = $connexion->prepare($req_derniersfilms); $requete_prepare_1->execute(); // Je choisis maintenant de placer la réponse de la requête dans un tableau PHP : $array_films = array(); while($ligne = $requete_prepare_1->fetch(PDO::FETCH_ASSOC)) { $array_films[$ligne['id']]['titre'] = $ligne['titre']; $array_films[$ligne['id']]['sortie'] = $ligne['sortie']; $array_films[$ligne['id']]['acteur'] = $ligne['acteur']; $array_films[$ligne['id']]['genre'] = $ligne['genre']; $array_films[$ligne['id']]['synopsis'] = $ligne['synopsis']; } // fin de la partie 1

Maintenant, dans le tableau "$array_films", nous avons tous les films à présenter à notre ami lecteur. Il ne reste plus qu'à les écrire selon un format, soit le RSS 2.0, soit le ATOM 1.0.

Partie 2 : Formatage de document : RSS 2.0 ou ATOM 1.0 ?

Je supposerai donc ici que nous avons appelé le fichier avec un paramètre dans l'URL permettant de préciser le format : http://www.le_site.tld/flux_rss.php?feed=RSS ou bien http://www.le_site.tld/flux_rss.php?feed=ATOM

// le fichier flux_rss.php continue ici

/* **********************************
 * PARTIE 2 : FORMATAGE DU DOCUMENT
 * **********************************
 */

	// détection du type de flux demandé
	$feed = (isset($_GET['feed'])) ? strtoupper($_GET['feed']) : '';
	if (($feed != 'RSS') && ($feed != 'ATOM')) { $feed = 'RSS'; } // simple précaution ...

	// maintenant, selon le type de flux demandé, on prépare un flux de formatage différent :
	$rss = ''; // on initialise la variable


	// si le mode RSS est choisi :
	if ($feed == 'RSS')
	{
		// On écrit le prologue du flux RSS 2.0 :
		$rss .= '<?xml version="1.0" encoding="ISO-8859-15"?>'."\n";
		$rss .= '<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">'."\n";

		// le channel est l'entête du flux ... on y renseigne :
		$rss .= '	<channel>'."\n";

		// le titre du site (attention aux caractères spéciaux ...)
		$rss .= '		<title>PHP-Astux : un flux RSS pour votre site - Les 10 derniers films</title>'."\n";

		// l'URL (adresse) du site
		$rss .= '		<link>http://www.php-astux.info</link>'."\n";

		// la description du site (attention aux caractères spéciaux ...)
		$rss .= '		<description>PHP-Astux propose des articles pour création Web</description>'."\n";

		// la langue du flux
		$rss .= '		<language>fr</language>'."\n";

		// la date de publication
		$rss .= '		<pubDate>'.date('D, d M Y H:i:s O').'</pubDate>'."\n";

		// la date de construction du flux
		$rss .= '		<lastBuildDate>'.gmdate('D, d M Y H:i:s').' GMT</lastBuildDate>'."\n";

		// 2 lignes pour l'auteur du document
		$rss .= '		<managingEditor>no-reply@php-astux.info (PHP-Astux)</managingEditor>'."\n";
		$rss .= '		<webMaster>no-reply@php-astux.info (PHP-Astux)</webMaster>'."\n";
		$rss .= '		<ttl>5</ttl>'."\n";

		// cette ligne est très importante, elle DOIT être l'URL de la page du flux
		$rss .= '		<atom:link href="http://www.le_site.tld/flux_rss?feed=RSS" rel="self" type="application/rss+xml" />'."\n";

		// maintenant, il ne reste plus qu'à insérer les données !
		foreach($array_films as $film_id => $film)
		{
			// chaque film sera encadré d'un bloc item
			$rss .= '		<item>'."\n";
			// titre du film (ou du bloc d'info) : je choisis de mettre [Genre] Titre
			$rss .= '			<title>['.htmlspecialchars(html_entity_decode($film['genre'])).'] '.htmlspecialchars(html_entity_decode($film['title']), ENT_NOQUOTES).'</title>'."\n";
			// lien direct vers ce bloc
			$rss .= '			<link>http://www.le_site.tld/films.php?film='.$film_id.'</link>'."\n";
			// je choisis d'y mettre le synopsis, puis, à la fin, le nom de l'acteur principal
			$rss .= '			<description>'.htmlspecialchars($film['synopsis'], ENT_NOQUOTES).' &lt;br /&gt;Acteur principal : '.htmlspecialchars($film['acteur'], ENT_NOQUOTES).'</description>'."\n";
			// la date de sortie du film, encodée selon une RFC
			$rss .= '			<pubDate>'.date('D, d M Y H:i:s O', $film['sortie']).'</pubDate>'."\n";
			// le lien vers la fiche du film
			$rss .= '			<guid>http://www.le_site.tld/films.php?film='.$film_id.'</guid>'."\n";
			$rss .= '		</item>'."\n";
		};

		// et maintenant, on ferme le contenu du flux RSS ...
		$rss .= '	</channel>'."\n";
		$rss .= '</rss>'."\n";
	};


	// ou plutôt, si le mode ATOM est choisi :
	if ($feed == 'ATOM')
	{
		// pour le format ATOM, les commentaires sont sensiblement équivalents.
		// Seuls changent certaines balises et certains formats (de date notamment).

		// On écrit le prologue du flux ATOM 1.0 :
		$rss .= '<?xml version="1.0" encoding="ISO-8859-15"?>'."\n";
		$rss .= '<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">'."\n";

		// pas de channel en ATOM...

		// le titre du site (attention aux caractères spéciaux ...)
		$rss .= '	<title>PHP-Astux : le site de NewsletTux !</title>'."\n";
		// la description du site (attention aux caractères spéciaux ...)
		$rss .= '	<subtitle>PHP-Astux propose des articles pour création Web ainsi que NewsletTux, outil de mailing list en PHP MySQL</subtitle>'."\n";
		// cette ligne est très importante, elle DOIT être l'URL de la page du flux
		$rss .= '	<link rel="self" href="http://www.le_site.tld/flux_rss?feed=ATOM" type="application/atom+xml" />'."\n";

		// la date de publication
		$rss .= '	<updated>'.date('Y-m-d\TH:i:s\Z').'</updated>'."\n";
		// pour l'auteur du document
		$rss .= '	<author>'."\n";
		$rss .= '		<name>Matthieu</name>'."\n";
		$rss .= '		<email>no-reply@php-astux.info</email>'."\n";
		$rss .= '	</author>'."\n";
		// l'URL du site
		$rss .= '	<id>http://www.le_site.tld</id>'."\n";


		// maintenant, il ne reste plus qu'à insérer les données !
		foreach($array_films as $film_id => $film)
		{
			// chaque film sera encadré d'un bloc entry
			$rss .= '		<entry>'."\n";

			// titre du film (ou du bloc d'info) : je choisis de mettre [Genre] Titre
			$rss .= '			<title>['.htmlspecialchars(html_entity_decode($film['genre']), ENT_NOQUOTES).'] '.htmlspecialchars(html_entity_decode($film['titre']), ENT_NOQUOTES).'</title>'."\n";

			// lien direct vers ce bloc
			$rss .= '			<link href="http://www.le_site.tld/films.php?film='.$film_id.'" />'."\n";

			// ID de ce bloc : il doit être unique
			$rss .= '			<id>http://www.le_site.tld/films.php?film='.$film_id.'</id>'."\n";

			// la date de sortie du film, encodée selon une RFC
			$rss .= '			<updated>'.date('Y-m-d\TH:i:s\Z', $film['sortie']).'</updated>'."\n";

			// résumé du bloc (accessibilité ...)
			$rss .= '			<summary>'.htmlspecialchars($film['synopsis'], ENT_NOQUOTES).'</summary>'."\n";

			// ce bloc permet de mettre de la mise en forme dans le flux (XHTML Strict seulement !!!)
			$rss .= '			<content type="xhtml">'."\n";
			$rss .= '				<div xmlns="http://www.w3.org/1999/xhtml">'.$film['synopsis'].'</div>'."\n";
			$rss .= '			</content>'."\n";
			$rss .= '		</entry>'."\n";
		};
		// et maintenant, on ferme le contenu du flux RSS ...
		$rss .= '</feed>'."\n";
	};
	// fin partie 2

Voilà, nous disposons maintenant d'une variable, nommée $rss, qui contient l'intégralité du flux avec les 10 films : $rss contient un flux au format ATOM 1.0 ou RSS 2.0 selon ce que nous avons demandé. Il reste maintenant à présenter au visiteur ce flux, afin qu'il puisse le lire dans ses logiciels.

Partie 3 : présentation du flux

Nous sommes dans la page "flux_rss.php?feed=ATOM" (ou feed=RSS) qui nous permet, via l'interrogation de la base de données, de générer un flux RSS des 10 derniers films. Pour le présenter au visiteur, il y a 2 manières de faire :

  • Soit nous créons un fichier, nommé par exemple, "rss.xml", qui contiendra le contenu de $rss :
// le fichier flux_rss.php continue ici

/* **************************************
 * PARTIE 3.1 : PRESENTATION DU FLUX RSS
 * **************************************
 */

	$fp = fopen("rss.xml", 'w+');
	fputs($fp, $rss);
	fclose($fp);

	// fin partie 3.1

Ainsi nous pouvons diffuser l'URL : http://www.le_site.tld/rss.xml pour le flux RSS. Mais à chaque modification de notre base de données (nouveau film), il faut réexécuter le fichier flux_rss.php?feed=ATOM (ou feed=RSS) pour recréer le fichier visible par tout le monde, "rss.xml".

  • Soit nous choisissons de diffuser le fichier "flux_rss.php?feed=ATOM" à tout le monde, et à chaque fois qu'un visiteur fera appel à ce fichier, le contenu RSS sera créé instantanément en tirant de la base de données les dernières informations :
// le fichier flux_rss.php continue ici

/* **************************************
 * PARTIE 3.2 : PRESENTATION DU FLUX RSS
 * **************************************
 */

	// On envoie les headers XML / no cache
	header('Content-Type: text/xml');
	header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
	header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
	header('Pragma: public');

	// maintenant qu'on a indiqué au navigateur qu'on lui envoyait du XML,
	// on envoie le flux
	echo $rss;

	// fin partie 3.2

Et cette fois, c'est l'URL http://www.le_site/flux_rss?feed=ATOM qu'on diffuse à tout le monde ...

Pour lier le flux RSS à une page de site Web, il faut utiliser la syntaxe suivante, entre <head> et </head> (selon la méthode retenue, choisir l'une des 3 lignes) :

	<link rel="alternate" type="application/rss+xml" href="http://www.le_site/rss.xml" />
	<link rel="alternate" type="application/rss+xml" href="http://www.le_site/flux_rss?feed=ATOM" />
	<link rel="alternate" type="application/rss+xml" href="http://www.le_site/flux_rss?feed=RSS" />

Evolutions possibles

Il y a plusieurs évolutions possibles aux flux RSS : on peut y insérer des images (pour autant qu'elles soient en lien absolu), on peut même proposer au visiteur de choisir les X dernières nouveautés ... Par défaut nous avons mis 10, mais on pourrait imaginer que le visiteur puisse appeler l'URL http://www.le_site.tld/flux_rss.php?feed=ATOM&view=20 ...

Dans la partie 1, ma requête SQL devient donc :

	// Si on a un "view=XXX dans l'URL, on récupère le nombre, sinon on met 10 par défaut
	$view = (isset($_GET['view'])) ? abs(intval($_GET['view'])) : 10;

	// Préparation de la requête
	$req_derniersfilms = "SELECT id, titre, sortie, acteur, genre, synopsis FROM table_films ORDER BY sortie DESC LIMIT 0,".$view.";"; // parce qu'on est certain que $view soit un entier numérique