Version en ligne

Tutoriel : Du rewriting réalisé avec du PHP

Table des matières

Du rewriting réalisé avec du PHP
Utilisation pour une news
Améliorations et astuces

Du rewriting réalisé avec du PHP

Utilisation pour une news

L'URL Rewriting est souvent nécessaire pour les sites de grande envergure, tout simplement pour masquer le nom des paramètres envoyés dans les URL, pour rendre les adresses plus séduisantes, mais aussi pour accroître le référencement (mais pas dans tous les cas). Vous aurez sans doute remarqué que les hébergeurs ne proposent pas tous l'URL Rewriting, c'est le cas de Free. Les choses sont révolues maintenant, nous pouvons aussi, à présent, créer de l'URL Rewriting avec un peu de tricherie, mais intelligemment.

Vous avez toujours rêvé d'avoir de beaux liens comme celui-ci : http://monsite.fr/page-1.html, ou encore http://monsite.fr/forum-1-maphraseavec-des-tirets.html ?
Vous en avez marre d'avoir ce type de lien : http://monsite.fr/page.php?id=1 ?
Ou encore ceci : http://monsite.fr/?/page-1.html ?

Alors suivez le guide !

Liens utiles :

Utilisation pour une news

Améliorations et astuces

Pour comprendre son utilisation, rien de mieux que de l'expliquer en donnant un exemple concret. Pour cela, nous allons nous intéresser au système de news. J'ai choisi cet exemple, tout simplement parce que je suis sûr que vous aurez déjà vu comment cela fonctionne, si vous avez lu le tutoriel de M@teo21.

Code pour la news

CREATE TABLE IF NOT EXISTS `news` (
  `id` mediumint(9) NOT NULL auto_increment,
  `auteur` varchar(50) NOT NULL,
  `titre` varchar(200) NOT NULL,
  `message` text NOT NULL,
  `temps` datetime NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

INSERT INTO `news` (`id`, `auteur`, `titre`, `message`, `temps`) VALUES
(1, 'Jérémy_B', 'L''URL rewriting', 'C''était pas si dur que ça !', '2008-12-31 01:36:14'),
(2, 'Jean', 'Re !', 'C''est vrai que c''est tout simple.', '2009-01-10 12:46:24'),
(3, 'Paul', 'Re re !', 'Merci Jérémy_B. :)', '2009-01-10 13:39:13');
<?php

	mysql_connect('localhost', 'root', '');
	mysql_select_db('urlrewriting'); // Mettez ici le nom de votre base de données.

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" >
	<head>
		<title>Page de news avec URL Rewriting !</title>
		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
	</head>
	<body>

<?php

$requete = "SELECT id, auteur, titre, message, DATE_FORMAT(temps, '%d/%m/%Y') AS temps_formate FROM news";

if (!empty($match)) {
	$requete .= " WHERE id = ".$match[1];
}

$resultat = mysql_query($requete);

while ($donnees = mysql_fetch_assoc($resultat)) {
	echo "Id : ".$donnees['id']."<br />";
	echo "Auteur : ".stripslashes($donnees['auteur'])."<br />";
	echo "Titre : ".stripslashes($donnees['titre'])."<br />";
	echo "Message : ".stripslashes($donnees['message'])."<br />";
	echo "Temps : ".$donnees['temps_formate']."<br />";
}

?>

	</body>
</html>

Voilà, jusque-là, rien de compliqué. Si vous avez été attentifs, vous aurez vu une petite condition vérifiant si la variable $match existe, et si elle n'est pas nulle. Elle nous sera utile lorsqu'on aura mis en place les codes pour l'URL Rewriting. D'ailleurs, il est temps de passer aux pages qui nous intéressent le plus.

Code pour l'URL Rewriting

php 1
ErrorDocument 404 /rewriting.php

Explication

<?php

if (preg_match('#news-([0-9-]+)\.html#isU', $_SERVER['REDIRECT_URL'], $match)) {
	// Modification du code retour, pour que les moteurs de recherche indexent nos pages !
	header("Status: 200 OK", false, 200);

	require 'news.php';
}
else {
	require 'erreur404.php';
}

Explication

Déroulement des évènements

On va donc faire appel à la page de news, pour afficher la toute première actualité. Ainsi, rentrons dans la barre d'adresse de notre navigateur, l'adresse suivante : http://monsite.fr/news-1.html.

Mais cette page n'existe pas sur notre FTP... ça va me retourner une erreur, non ?

Exact, et pas n'importe quelle erreur, la 404. C'est là que notre tricherie va opérer ! Je vous ai dit qu'avec le fichier .htaccess, on allait rediriger l'erreur sur la page rewriting.php. Avec notre page de code, on fait une condition sur l'URL qu'on nous a envoyée, on récupère le chiffre 1, nous permettant, en réalité, de prendre l'id de la news, on renvoie un header pour dire que ce n'était pas une erreur, puis on inclut la page news.php, qui elle, existe réellement.

Je vous rappelle qu'on a récupéré l'id dans la variable $match[1]. Je vous rappelle aussi qu'une variable peut être transmise dans une autre page qu'on inclut juste après sa déclaration, à condition que dans la deuxième page, la variable ait le même nom.

Pour en revenir au déroulement des opérations, on vient donc d'inclure la page news.php. Sur cette page, notre requête peut avoir deux cas de figure :

Et voilà, miracle, ça marche ! Qu'on appelle notre page avec l'adresse http://monsite.fr/news-1.html ou avec http://monsite.fr/news.html, on visualise bien notre news.


Améliorations et astuces

Améliorations et astuces

Utilisation pour une news

Pour que notre script soit le plus intéressant possible, il faudrait qu'on puisse avoir plusieurs possibilités dans nos URL. Mais notre script a ses limites, on ne peut pas tout faire. Nous devrons donc mettre en place une cohérence dans nos liens, sinon, on ne s'en sortira jamais. Ainsi, dans les paramètres de l'URL, nous mettrons, dans un premier temps, les chiffres (id de la news, du membre, du commentaire, du topic, etc.), puis, dans un second temps, les chaînes de caractères. Nous pourrons donc arriver à ce type de lien :

<?php

$page_du_site = array("/news"); // Super important les / devant le nom du fichier !
$url_sans_parametre = str_replace('.html', '', $_SERVER['REDIRECT_URL']);
$url_avec_parametre = substr($_SERVER['REDIRECT_URL'], 0, strpos($_SERVER['REDIRECT_URL'], "-"));

if (in_array($url_sans_parametre, $page_du_site)) {
	$url = dirname(__FILE__).$url_sans_parametre;
}
elseif (in_array($url_avec_parametre, $page_du_site)) {
	$url = dirname(__FILE__).$url_avec_parametre;
}
else {
	$url = 'erreur404';
}

$page = basename($url_avec_parametre);

if (preg_match('#'.$page.'-([0-9-]+)-([^0-9](?:.+))\.html#isU', $_SERVER['REDIRECT_URL'], $match)) {
	header("Status: 200 OK", false, 200);
}
elseif (preg_match('#'.$page.'-([0-9-]+)\.html#isU', $_SERVER['REDIRECT_URL'], $match)) {
	header("Status: 200 OK", false, 200);
}
else {
	header("Status: 200 OK", false, 200);
}

require $url.'.php';

Explication

Maintenant que nous avons mis le code en place, créez la page page.php, permettant de bien comprendre ce que fait notre script du dessus. Voici le code :

<?php

$taille = count($match);

for ($i=0; $i<$taille; $i++) {
	echo 'match['.$i.'] vaut : '.$match[$i].'<br />';
}

Il ne vous reste plus qu'à tester les différentes URL possibles, et vous comprendrez bien mieux ce qu'on a voulu faire. Pour que tout le monde ait le même résultat, testez les URL que je vous ai données au début de ce sous-chapitre. Par exemple, pour http://monsite.fr/page-1-le-super-titre.html, on obtient ceci :

match[0] vaut : page-1-2-le-super-titre.html <--> correspond aussi à $_SERVER['REDIRECT_URL']
match[1] vaut : 1-2
match[2] vaut : le-super-titre

Mais... match[1] vaut 1-2 ! C'est nul ton truc ! Comment on fait si je ne voulais que le 1 ou le 2 ?

Pas de panique, on y va tranquillement pour bien comprendre. Pour séparer une chaîne en tableau avec PHP, il faut utiliser la fonction explode. Nous allons donc passer $match[1] dans explode, et nous pourrons ainsi récupérer nos paramètres 1 et 2.

<?php

$parametre = explode('-', $match[1]);
print_r($parametre); // Array ( [0] => 1 [1] => 2 )

Et voilà, nous pouvons maintenant avoir nos beaux paramètres dans des variables : $parametre[0] = 1 et $parametre[1] = 2. Le code ci-dessus (sans le print_r()), est à placer, bien évidemment, dans le fichier rewriting.php, au niveau des deux conditions utilisant preg_match(). Il ne nous reste plus qu'à faire la même chose pour $match[2], qui contient, cette fois-ci, une chaîne. Sauf que là, on veut juste remplacer les tirets (-) par des espaces et, pourquoi pas, mettre une lettre majuscule pour la première lettre !

<?php

$titre = ucfirst(str_replace('-', ' ', $match[2]));
echo $titre; // Le super titre

Nous avons vu comment avoir les bons paramètres dans plusieurs variables pour nous faciliter la tâche, mais nous n'avons pas vu comment créer ces liens ! Eh oui, car bon, pour les chiffres, il n'y a pas trop de problèmes, mais pour les chaînes de caractères... c'est une tout autre paire de manches. On a, facilement, la possibilité de faire des URL invalides... et ce n'est pas notre but. Bref, voyons comment régler ce problème.

Tout d'abord, reprenons l'exemple de notre news. On va, cette fois-ci, sélectionner une news avec tous ses champs, et ainsi, on pourra, avec son id et son titre, créer un lien pour notre belle URL :

<?php

	mysql_connect('localhost', 'root', '');
	mysql_select_db('urlrewriting'); // Mettez ici le nom de votre base de données

	function caractereValideUrl($string) {
		$string= strtr($string,
			"ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÇçÌÍÎÏìíîïÙÚÛÜùúûüÿÑñ",
			"aaaaaaaaaaaaooooooooooooeeeeeeeecciiiiiiiiuuuuuuuuynn");

		// Mettez ici les caractères spéciaux qui seraient susceptibles d'apparaître dans les titres. La liste ci-dessous est indicative.
		$speciaux = array("?","!","@","#","%","&amp;","*","(",")","[","]","=","+"," ",";",":","'",".","_");
		$string = str_replace($speciaux, "-", $string); // Les caractères spéciaux dont les espaces, sont remplacés par un tiret.
		$string = strtolower(strip_tags($string));

		return $string;
	}

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" >
	<head>
		<title>Les news !</title>
		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
	</head>
	<body>

<?php

$requete = "SELECT id, auteur, titre, message, DATE_FORMAT(temps, '%d/%m/%Y') AS temps_formate FROM news";

if (!empty($match)) {
	$requete .= " WHERE id = ".$match[1];
}

$resultat = mysql_query($requete);

while ($donnees = mysql_fetch_assoc($resultat)) {
	// Tout ce qu'on souhaite afficher pour la news, comme au tout début...
	echo '<a href="http://monsite.fr/news-'.$donnees['id'].'-
	'.caractereValideUrl('Jérémy B')))).'.html">Un superbe lien !</a>';
	// http://monsite.fr/news-1-jeremy-b.html
}

?>

	</body>
</html>

Explication

Et une dernière amélioration pour la route : tout ceci se passe à la racine du FTP, mais qu'en est-il pour les autres fichiers qui se trouvent dans des dossiers ? Comme à notre habitude, on va devoir modifier la page qui nous intéresse : rewriting.php. La solution est toute simple, il suffit de mettre le nom du dossier avec la page dans le tableau $page_du_site.

<?php

$page_du_site = array("/test/page", "/news");

Bon, je crois qu'on a fait le tour des améliorations possibles. Comme quoi, avec notre script, nous avions au départ un code tout simple, nous l'avons complexifié, en rajoutant diverses améliorations, et nous avons fait en sorte d'avoir pensé à toutes les éventualités.

Voilà, le tutoriel touche à sa fin. Vous savez maintenant qu'on peut faire du Rewriting, sans pour autant avoir le moteur adéquat dans Apache (désactivé par Free, par exemple). Ne me dites pas, par contre, que ça ne marche pas ou autre, car j'ai bien tout testé avant d'avoir écrit ce tutoriel.

Le tutoriel n'est sûrement pas parfait, il doit bien y avoir quelques erreurs, mais il n'est cependant pas figé. Venez donc m'en faire part pour que je puisse l'améliorer !

La seule chose qui me manque comme information, ce serait de savoir si cette méthode est plus lente que celle du véritable moteur. Je n'ai, hélas, pas les connaissances suffisantes, mais bon, vu que notre système et celui du moteur utilisent tous les deux les REGEX, il ne doit pas y avoir d'énorme différence (de temps, bien sûr).

Merci, en tout cas, d'avoir lu jusqu'au bout, et j'espère en avoir aidé plus d'un !

Je remercie aussi au passage ptipilou pour sa Zcorrection.


Utilisation pour une news