Tutoriel d'URL Rewriting (réécriture de liens)
Exemple avec phpBB 2
Date de publication : 7 mai 2006 , Date de mise à jour : 5 juillet 2006
III. Exemples avec Apache & PHP
III-1. Première partie : traduire les requêtes du client
Traduire une URL fictive en une URL réelle
Traduire une URL fictive en une URL réelle en simulant une arborescence
III-2. Seconde partie : modifier les pages envoyées au client
Utiliser le tampon pour modifier tous les liens plus facilement
Utiliser une base de données pour généraliser le script
Utiliser un fichier de langue pour traduire les URLs du site
III. Exemples avec Apache & PHP
Ce code est minimaliste. Je n'ai mis aucune mesure de sécurité afin de ne pas nous détourner du sujet. De même, je n'ai prêté aucune attention aux tables créées dans la base de donnée : ce n'est pas l'objet de ce tutoriel. Pour un cas réel, il conviendrait d'appliquer votre stratégie de sécurité habituelle et de structurer correctement les données.
Dans tous les exemples, le fichier .htaccess redirige vers un répertoire que j'ai nommé "urlr" et que j'ai placé à la racine de mon serveur Web : à vous de modifier cette valeur pour qu'elle corresponde à votre configuration.
Ces exemples ont été testés avec succès sur ma machine de développement : j'utilise EasyPHP 1.8, c'est-à-dire Apache 1.3.33 avec PHP 4.3.10 et MySQL 4.1.9. Cela fonctionne malgré ces versions préhistoriques et je pense que c'est une bonne indication de la portabilité de l'URL Rewriting.
III-1. Première partie : traduire les requêtes du client
Nos URLs peuvent être réécrites principalement de deux manières : au moyen de noms de fichiers fictifs ou bien en simulant une arborescence.
Traduire une URL fictive en une URL réelle
Fichier : index.php | < a href = " tous - les - articles . html " > Tous les articles< / a > < br / >
< a href = " article - 1 - sur - les - vaches . html " > Les vaches< / a > < br / >
< a href = " article - 2 - sur - le - php . html " > Le PHP< / a > < br / >
< a href = " article - 3 - sur - le - papier - recycle . html " > Le papier recyclé< / a > < br / > < br / >
<?php
if (! empty($ _GET [ ' a ' ] )){
switch ($ _GET [ ' a ' ] ){
case 1 :
echo ' <u>Article "Les vaches"</u> :<br />Meuh ' ;
break ;
case 2 :
echo ' <u>Article "Le PHP"</u> :<br />echo "Hello World!"; ' ;
break ;
default :
echo ' <u>Article "Le papier recyclé"</u> :<br />Pensons-y ' ;
break ;
}
}
?>
|
Fichier : .htaccess | DirectoryIndex index.php
RewriteEngine on
RewriteRule article-([0-9]+).* /urlr/index.php?a=$1 [L]
RewriteRule tous-les-articles.* /urlr/index.php [L]
|
Des deux grandes solutions qui s'offrent à nous pour réécrire les liens d'une page Web, celle-ci est ma préférée.
Traduire une URL fictive en une URL réelle en simulant une arborescence
Fichier : index.php | < a href = " http : / / localhost / urlr / tous - les - articles . html " > Tous les articles< / a > < br / >
< a href = " http : / / localhost / urlr / articles / 1 - sur - les - vaches . html " > Les vaches< / a > < br / >
< a href = " http : / / localhost / urlr / articles / 2 - sur - le - php . html " > Le PHP< / a > < br / >
< a href = " http : / / localhost / urlr / articles / 3 - sur - le - papier - recycle . html " > Le papier recyclé< / a > < br / > < br / >
<?php
if (! empty($ _GET [ ' a ' ] )){
switch ($ _GET [ ' a ' ] ){
case 1 :
echo ' <u>Article "Les vaches"</u> :<br />Meuh ' ;
break ;
case 2 :
echo ' <u>Article "Le PHP"</u> :<br />echo "Hello World!"; ' ;
break ;
default :
echo ' <u>Article "Le papier recyclé"</u> :<br />Pensons-y ' ;
break ;
}
}
?>
|
Fichier : .htaccess | DirectoryIndex index.php
RewriteEngine on
RewriteRule articles/([0-9]+).* /urlr/index.php?a=$1 [L]
RewriteRule tous-les-articles.* /urlr/index.php [L]
|
Cette solution me plaît moins que la précédente mais, puisqu'elle est tellement fréquente, j'ai décidé de la traiter ici. À vous de choisir celle que vous préférez de celle-ci ou de la précédente. Pour ma part, je poursuivrai ma présentation d'exemples avec la solution sans arborescence.
Je dois avouer que c'est ma grande fainéantise qui oriente mon choix... J'imagine que simuler une arborescence a tout un tas d'intérêts d'optimisation ! Si vous en avez le temps, je vous recommande de vous pencher sérieusement sur la question.
III-2. Seconde partie : modifier les pages envoyées au client
Utiliser le tampon pour modifier tous les liens plus facilement
Squelette du script :
- Initialiser la mise en tampon de la sortie standard
- Afficher les liens à réécrire
- Afficher le contenu en fonction du paramètre appelé (facultatif)
- Récupérer le tampon et arrêter la mise en cache
- Réécrire les liens
- Afficher la page
Fichier : index.php | <?php
ob_start();
?>
< a href = " index . php " > Tous les articles< / a > < br / >
< a href = " index . php ? a = 1 " > Les vaches< / a > < br / >
< a href = " index . php ? a = 2 " > Le PHP< / a > < br / >
< a href = " index . php ? a = 3 " > Le papier recyclé< / a > < br / >
<?php
if (! empty($ _GET [ ' a ' ] )){
switch ($ _GET [ ' a ' ] ){
case 1 :
echo ' <u>Article "Les vaches"</u> :<br />Meuh ' ;
break ;
case 2 :
echo ' <u>Article "Le PHP"</u> :<br />echo "Hello World!"; ' ;
break ;
default :
echo ' <u>Article "Le papier recyclé"</u> :<br />Pensons-y ' ;
break ;
}
}
$ contents = ob_get_contents();
ob_end_clean();
$ patterns [ ] = ' <a href="index.php?a=1">Les vaches</a> ' ;
$ patterns [ ] = ' <a href="index.php?a=2">Le PHP</a> ' ;
$ patterns [ ] = ' <a href="index.php?a=3">Le papier recyclé</a> ' ;
$ new_urls [ ] = ' <a href="article-1-les-vaches.html">Les vaches</a> ' ;
$ new_urls [ ] = ' <a href="article-2-le-php.html">Le PHP</a> ' ;
$ new_urls [ ] = ' <a href="article-3-le-papier-recycle">Le papier recyclé</a> ' ;
$ contents = str_replace($ patterns , $ new_urls , $ contents );
echo $ contents ;
?>
|
Fichier : .htaccess | DirectoryIndex index.php
RewriteEngine on
RewriteRule article-([0-9]+).* /urlr/index.php?a=$1 [L]
RewriteRule tous-les-articles.* /urlr/index.php [L]
|
Observez ce qui a changé.
Non seulement les liens pointent vers des fichiers inexistants, mais nous avons également ajouté la propriété title à chacun d'eux. Notez également comme il est possible de mettre n'importe quoi à la suite du numéro d'article.
Et pourtant, cela fonctionne.
Il me paraît limpide que cet exemple peut être amélioré, au vu de la quantité d'information que nous dupliquons...
Étant donné que notre site piochera toutes ses données dans une base de données, autant s'y faire tout de suite !
Utiliser une base de données pour généraliser le script
Voici un exemple concret (indépendant de phpBB) utilisant le tampon et une base de données :
Squelette du script :
- Initialiser la mise en tampon de la sortie standard
- Se connecter à la base de données
- Afficher les liens à réécrire
- Afficher le contenu en fonction du paramètre appelé (facultatif)
- Récupérer le tampon et arrêter la mise en cache
- Récupérer les liens à l'aide d'une expression régulière
- Parcourir les liens et les réécrire à l'aide de la base de données
- Afficher la page
Code SQL pour créer la base de données | CREATE TABLE `article` (
`id` INT (11 ) NOT NULL AUTO_INCREMENT,
`author` VARCHAR (255 ) NOT NULL ,
`title` VARCHAR (255 ) NOT NULL ,
`text ` TEXT NOT NULL ,
PRIMARY KEY (`id`)
);
INSERT INTO `article` (`author`, `title`, `text `)
VALUES
(' Yogui ' , ' Les vaches ' , ' Meuh ' ),
(' Yogui ' , ' Le PHP ' , ' echo "Hello world!"; ' ),
(' Yogui ' , ' Le papier recyclé ' , ' Pensons-y ' )
;
|
Fichier : index.php | <?php
function clean($ string ){
return urlencode($ string );
}
ob_start();
mysql_connect(' localhost ' , ' root ' , ' ' )
or die(__LINE__ . ' : ' . mysql_error());
mysql_select_db(' developpez ' )
or die(__LINE__ . ' : ' . mysql_error());
$ sql = ' SELECT `id`, `title`
FROM `article` ' ;
$ result = mysql_query($ sql )
or die(__LINE__ . ' : ' . mysql_error());
?>
< a href = " index . php " > Tous les articles< / a > < br / >
<?php
while ($ article = mysql_fetch_assoc($ result )){
?>
< a href = " index . php ? a = <?php echo $ article [ ' id ' ] ; ?> " > <?php echo $ article [ ' title ' ] ; ?> < / a >
< br / >
<?php
}
if (! empty($ _GET [ ' a ' ] )){
$ sql = ' SELECT `title`, `text`
FROM `article`
WHERE `id` = ' . $ _GET [ ' a ' ] ;
$ result = mysql_query($ sql )
or die(__LINE__ . ' : ' . mysql_error());
if ($ article = mysql_fetch_assoc($ result )){
?>
< br / > < br / >
< u > Article "<?php echo $ article [ ' title ' ] ; ?> "< / u > :
< br / > <?php echo $ article [ ' text ' ] ; ?>
<?php
}
}
$ contents = ob_get_contents();
ob_end_clean();
if (preg_match_all(
' #<a href="index.php\?a=([0-9]+)">(.+)</a>#Usi ' ,
$ contents ,
$ matches ,
PREG_SET_ORDER))
{
foreach ($ matches as $ match ){
$ pattern = $ match [ 0 ] ;
$ article_id = $ match [ 1 ] ;
$ anchor = $ match [ 2 ] ;
$ sql = ' SELECT `title`, `text`
FROM `article`
WHERE `id` = ' . $ article_id ;
$ result = mysql_query($ sql )
or die(__LINE__ . ' : ' . mysql_error());
if ($ article = mysql_fetch_assoc($ result )){
$ new_url =
' <a href="article- ' . $ article_id . ' -sur- ' . clean($ article [ ' title ' ] ). ' .html" '
. ' title=" ' . $ article [ ' title ' ] . ' "> '
. $ article [ ' title ' ]
. ' </a> ' ;
$ contents = str_replace($ pattern , $ new_url , $ contents );
}
}
}
echo $ contents ;
?>
|
Fichier : .htaccess | DirectoryIndex index.php
RewriteEngine on
RewriteRule article-([0-9]+).* /urlr/index.php?a=$1 [L]
RewriteRule tous-les-articles.* /urlr/index.php [L]
|
Utiliser un fichier de langue pour traduire les URLs du site
Voici un exemple concret (indépendant de phpBB) utilisant le tampon, une base de données (multilingue) et un fichier de langue :
Squelette du script :
- Initialiser la mise en tampon de la sortie standard
- Déterminer dans quelle langue les URLs seront traduites
- Se connecter à la base de données
- Afficher les langues disponibles
- Afficher les liens à réécrire
- Afficher le contenu en fonction du paramètre appelé (facultatif)
- Récupérer le tampon et arrêter la mise en cache
- Récupérer les liens à l'aide d'une expression régulière
- Parcourir les liens et les réécrire à l'aide de la base de données et du fichier de langue
- Afficher la page
Code SQL pour créer la base de données | CREATE TABLE `language` (
`id` INT NOT NULL AUTO_INCREMENT,
`name ` VARCHAR (255 ) NOT NULL ,
PRIMARY KEY (`id`)
);
INSERT INTO `language` (`name `)
VALUES
(' fr ' ),
(' en ' ),
(' es ' )
;
CREATE TABLE `article` (
`id` int (11 ) NOT NULL auto_increment,
`author` VARCHAR (255 ) NOT NULL ,
PRIMARY KEY (id)
);
INSERT INTO `article` (`author`)
VALUES
(' Yogui ' ),
(' Yogui ' ),
(' Yogui ' )
;
CREATE TABLE `article_lang` (
`article_id` int (11 ) NOT NULL default ' 0 ' ,
`lang_id` int (11 ) NOT NULL default ' 0 ' ,
`title` varchar (255 ) NOT NULL default ' ' ,
`text ` text NOT NULL ,
PRIMARY KEY (`article_id`, `lang_id`)
);
INSERT INTO `article_lang` (`article_id`, `lang_id`, `title`, `text `)
VALUES
(1 , 1 , ' Les vaches ' , ' Meuuh ' ),
(1 , 2 , ' Cows ' , ' Muuh ' ),
(1 , 3 , ' Las vacas ' , ' Muu ' ),
(2 , 1 , ' Le PHP ' , ' echo "Bonjour le monde !"; ' ),
(2 , 2 , ' PHP ' , ' echo "Hello world!"; ' ),
(2 , 3 , ' El PHP ' , ' echo "¡Hola mundo!"; ' ),
(3 , 1 , ' Le papier recyclé ' , ' Pensons-y ' ),
(3 , 2 , ' Recycled paper ' , ' Think about it ' ),
(3 , 3 , ' Papel reciclado ' , ' Piensa en ello ' )
;
|
Fichier : index.php | <?php
function clean($ string ){
return urlencode($ string );
}
ob_start();
if (! empty($ _GET [ ' lang ' ] ) and is_file(' lang_ ' . $ _GET [ ' lang ' ] . ' .php ' )){
define(' LANG_ID ' , $ _GET [ ' lang ' ] );
}
else {
define(' LANG_ID ' , ' fr ' );
}
require(' lang_ ' . LANG_ID. ' .php ' );
mysql_connect(' localhost ' , ' root ' , ' ' )
or die(__LINE__ . ' : ' . mysql_error());
mysql_select_db(' developpez ' )
or die(__LINE__ . ' : ' . mysql_error());
$ sql = ' SELECT `name`
FROM `language` ' ;
$ result = mysql_query($ sql )
or die(__LINE__ . ' : ' . mysql_error());
while ($ language = mysql_fetch_assoc($ result )){
?>
[ < a href = " index . php ? lang = <?php echo $ language [ ' name ' ] ; ?> " >
<?php echo $ language [ ' name ' ] ; ?>
< / a > ]
<?php
}
echo ' <br /><br /> ' ;
$ sql = ' SELECT a.`id`, a.`author`, al.`title`, al.`text`
FROM `article_lang` AS al
INNER JOIN `article` AS a ON al.`article_id` = a.`id`
INNER JOIN `language` AS l ON al.`lang_id` = l.`id`
WHERE l.`name` = " ' . LANG_ID. ' " ' ;
$ result = mysql_query($ sql )
or die(__LINE__ . ' : ' . mysql_error());
while ($ article = mysql_fetch_assoc($ result )){
?>
< a href = " index . php ? a = <?php echo $ article [ ' id ' ] ; ?> " > <?php echo $ article [ ' title ' ] ; ?> < / a >
< br / >
<?php
}
if (! empty($ _GET [ ' a ' ] )){
$ sql = ' SELECT a.`id`, a.`author`, al.`title`, al.`text`
FROM `article_lang` AS al
INNER JOIN `article` AS a ON al.`article_id` = a.`id`
INNER JOIN `language` AS l ON al.`lang_id` = l.`id`
WHERE a.`id` = ' . $ _GET [ ' a ' ] . '
AND l.`name` = " ' . LANG_ID. ' " ' ;
$ result = mysql_query($ sql )
or die(__LINE__ . ' : ' . mysql_error());
if ($ article = mysql_fetch_assoc($ result )){
?>
< br / > < br / >
< u > Article "<?php echo $ article [ ' title ' ] ; ?> "< / u > :
< br / > <?php echo $ article [ ' text ' ] ; ?>
<?php
}
}
$ contents = ob_get_contents();
ob_end_clean();
if (preg_match_all(
' #<a href="index.php\?a=([0-9]+)">(.+)</a>#Usi ' ,
$ contents ,
$ matches ,
PREG_SET_ORDER))
{
foreach ($ matches as $ match ){
$ pattern = $ match [ 0 ] ;
$ article_id = $ match [ 1 ] ;
$ anchor = $ match [ 2 ] ;
$ sql = ' SELECT a.`id`, a.`author`, al.`title`, al.`text`
FROM `article_lang` AS al
INNER JOIN `article` AS a ON al.`article_id` = a.`id`
INNER JOIN `language` AS l ON al.`lang_id` = l.`id`
WHERE a.`id` = ' . $ article_id . '
AND l.`name` = " ' . LANG_ID. ' " ' ;
$ result = mysql_query($ sql )
or die(__LINE__ . ' : ' . mysql_error());
if ($ article = mysql_fetch_assoc($ result )){
$ new_url = sprintf($ lang [ ' url ' ] , $ article_id , clean($ article [ ' title ' ] )). ' .html ' ;
$ new_title = sprintf($ lang [ ' title ' ] , $ article [ ' title ' ] );
}
else {
$ new_url = $ lang [ ' index ' ] . ' .html ' ;
$ new_title = ' ' ;
}
$ new_link = ' <a href=" ' . $ new_url . ' " title=" ' . $ new_title . ' "> ' . $ article [ ' title ' ] . ' </a> ' ;
$ contents = str_replace($ pattern ,
$ new_link ,
$ contents );
}
}
echo $ contents ;
?>
|
Fichier : lang_fr.php | <?php
$ lang = array ();
$ lang [ ' index ' ] = ' tous-les-articles ' ;
$ lang [ ' url ' ] = ' article-%d-sur-%s ' ;
$ lang [ ' title ' ] = ' Article : %s ' ;
?>
|
Fichier : lang_en.php | <?php
$ lang = array ();
$ lang [ ' index ' ] = ' all-the-articles ' ;
$ lang [ ' url ' ] = ' article-%d-about-%s ' ;
$ lang [ ' title ' ] = ' Article: %s ' ;
?>
|
Fichier : lang_es.php | <?php
$ lang = array ();
$ lang [ ' index ' ] = ' todos-los-articulos ' ;
$ lang [ ' url ' ] = ' articulo-%d-sobre-%s ' ;
$ lang [ ' title ' ] = ' Artículo: %s ' ;
?>
|
Fichier : .htaccess | DirectoryIndex index.php
RewriteEngine on
RewriteRule article-([0-9]+)-sur.* /urlr/index.php?a=$1 [L]
RewriteRule tous-les-articles.* /urlr/index.php [L]
RewriteRule article-([0-9]+)-about.* /urlr/index.php?a=$1&lang=en [L]
RewriteRule all-the-articles.* /urlr/index.php&lang=en [L]
RewriteRule articulo-([0-9]+)-sobre.* /urlr/index.php?a=$1&lang=es [L]
RewriteRule todos-los-articulos.* /urlr/index.php&lang=es [L]
|
Les sources présentés sur cette page sont libres de droits,
et vous pouvez les utiliser à votre convenance. Par contre cette page de présentation de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright ©2006 Guillaume Rossolini.
Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu :
textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts.
Cette page est déposée à la SACD.
|