III. Implémentation▲
Je vous propose de voir l'implémentation en deux étapes : une première approche nous permettra de voir comment fonctionne chaque mécanisme puis nous aborderons l'approche complète.
La raison de cette séparation est que nous avons le contrôle sur les liens figurant à l'intérieur de notre propre site, ce qui signifie que nous pouvons les modifier sans que l'utilisateur final en ait connaissance. Cela nous permet d'éliminer peu à peu les liens périmés.
En revanche, les liens situés à l'extérieur de notre site sont hors de notre portée. Il nous faut donc indiquer aux visiteurs qui utilisent ce type de lien qu'il est recommandé de mettre leurs favoris à jour.
III-A. Liens externes▲
Cela se fait au moyen d'un code HTTP/1.1 : lorsqu'un visiteur utilise une adresse que nous savons mauvaise, il nous faut employer le code 301 (« déplacé de manière permanente »). Nous indiquons ensuite au visiteur l'emplacement de l'adresse correcte.
<?php
header('HTTP/1.1 301 Moved Permanently'
);
header('Location: nouvelle-adresse.ext'
);
exit;
// Il ne faut rien envoyer d'autre
?>
Dans la pratique, il nous faut d'abord retrouver (restaurer) l'adresse d'origine puis utiliser notre réécriture de liens afin de rediriger vers la bonne adresse.
La première phase (la restauration) est effectuée au moyen du fichier .htaccess : nous substituons la mauvaise adresse par un script de redirection auquel nous indiquons l'adresse standard (nom physique du script + paramètres). De cette manière, il suffit au script de redirection de réécrire cette adresse selon les règles de réécriture que nous avons définies dans le tutoriel précédent.
DirectoryIndex index.php
Options +FollowSymlinks
RewriteEngine on
#Restauration des URL de base
RewriteRule ^ftopic([0-9]+).* /phpbb-test/redirect.php?url=viewtopic.php?t=$1 [L]
RewriteRule ^forum([0-9]+).* /phpbb-test/redirect.php?url=viewforum.php?f=$1 [L]
#Réécriture normale
RewriteRule ^sujet-([0-9]+).* /phpbb-test/viewtopic.php?t=$1 [L]
RewriteRule ^forum-([0-9]+).* /phpbb-test/viewforum.php?f=$1 [L]
Nous retrouvons dans ce fichier .htaccess les trois types d'URL que nous avons vus tout à l'heure dans la Problématique : les URL de base (viewtopic.php?t=$1), intermédiaires (ftopic[0-9]+.*) et finales (sujet-[0-9]+.*).
<?php
define('IN_PHPBB'
,
true
);
$phpbb_root_path
=
'./'
;
include($phpbb_root_path
.
'extension.inc'
);
include($phpbb_root_path
.
'common.'
.
$phpEx
);
if
(!
empty($userdata
[
'user_lang'
]
)){
$current_language
=
$userdata
[
'user_lang'
];
}
else
{
$current_language
=
$board_config
[
'default_lang'
];
}
include($phpbb_root_path
.
'/language/lang_'
.
$current_language
.
'/lang_urlrewrite.'
.
$phpEx
);
if
(is_array($lang
[
'urlrewrite'
]
)){
require_once($phpbb_root_path
.
'includes/functions_urlrewrite.'
.
$phpEx
);
$new_url
=
rewrite_url(urldecode($_GET
[
'url'
]
),
$lang
[
'urlrewrite'
]
);
header('HTTP/1.1 301 Moved Permanently'
);
header('Location: '
.
$new_url
[
'url'
]
);
exit;
}
?>
L'appel à urldecode() est rendu nécessaire par les scripts utilisant plusieurs paramètres (ils sont légion) et d'une contrainte imposée par notre .htaccess, dans lequel nous avons simulé un appel à urlencode().
Pourquoi urldecode() est nécessaire :
- /phpbb-test/redirection.php?url=viewtopic.php?t=1&start=25 ==> il y a confusion pour le paramètre « start » qui peut ici être envoyé au script « redirection.php » (ce n'est pas ce que nous voulons) ;
- /phpbb-test/redirection.php?url=viewtopic.php?t=1&start=25 ==> « start » n'est pas encore compris comme un paramètre, mais comme faisant partie intégrante du paramètre « url » (c'est ce que nous voulons).
Si notre site a subi plusieurs réécritures successives de ses liens, il suffit de compléter la partie « Restauration des URL de base » de notre fichier .htaccess !
DirectoryIndex index.php
Options +FollowSymlinks
RewriteEngine on
#Restauration des URL de base
RewriteRule ^ftopic([0-9]+).* /phpbb-test/redirect.php?url=viewtopic.php?t=$1 [L]
RewriteRule ^forum([0-9]+).* /phpbb-test/redirect.php?url=viewforum.php?f=$1 [L]
RewriteRule ^viewtopic.php?t=([0-9]+) /phpbb-test/redirect.php?url=viewtopic.php?t=$1 [L]
RewriteRule ^viewforum.php?f=([0-9]+) /phpbb-test/redirect.php?url=viewforum.php?f=$1 [L]
#Réécriture normale
RewriteRule ^sujet-([0-9]+).* /phpbb-test/viewtopic.php?t=$1 [L]
RewriteRule ^forum-([0-9]+).* /phpbb-test/viewforum.php?f=$1 [L]
III-B. Liens internes▲
Si nous observons l'un des fichiers de langue de l'autre tutoriel, nous pouvons remarquer la présence de clefs pour le tableau $lang['urlrewrite']['regexes']. Nous allons utiliser les mêmes clefs dans notre tableau actuel afin de pouvoir faire correspondre les URL sans problème.
Pour restaurer les URL, il nous faut mettre les adresses « brutes » dans un tableau à part que nous appellerons $raw_URL. Nous utiliserons un autre tableau, $rewritten_URL, pour contenir les différentes versions de chaque adresse réécrite : l'index « old » sert aux adresses construites par d'anciennes versions de la réécriture de liens de notre site. Chacun des autres index correspond à une langue installée dans notre forum phpBB : les utilisateurs ont pu poster des adresses dans toutes ces différentes langues, il faut donc uniformiser la présentation.
Dans tous ces tableaux, nous utiliserons les clefs que nous avons remarquées ci-dessus.
<?php
$raw_URL
=
array
(
'viewtopic_topicid_title'
=>
'viewtopic.php?t=$1'
,
'viewforum_id_title'
=>
'viewforum.php?f=$1'
,
// ...
);
$rewritten_URL
[
'old'
]
=
array
(
'viewtopic_topicid_title'
=>
array
('ftopic([0-9]+)'
),
'viewforum_id_name'
=>
array
('forum([0-9]+)'
),
// ...
);
// ...
if
($directory
=
dir($phpbb_root_path
.
'language'
)){
while
($entry
=
$directory
->
read()){
if
(is_file($phpbb_root_path
.
'language/'
.
$entry
.
'/lang_urlrewrite.'
.
$phpEx
)){
include($phpbb_root_path
.
'language/'
.
$entry
.
'/lang_urlrewrite.'
.
$phpEx
);
$rewritten_URL
[
basename($entry
)]
=
$lang
[
'urlrewrite'
][
'regexes'
];
}
}
}
?>
Il nous reste maintenant à restaurer les URL par défaut de phpBB.
J'ai choisi de commencer par restaurer les URL par défaut pour ensuite laisser le soin à notre méthode de réécriture de se charger du reste des opérations de la même manière qu'elle en a l'habitude.
Un point de sémantique : dans ce cas précis, « restaurer » signifie retrouver une URL par défaut de phpBB à partir d'une URL réécrite, tandis que « réécrire » signifie modifier l'URL par défaut en une URL réécrite. Les deux termes peuvent être utilisés dans les deux situations, c'est pourquoi je préfère être clair.
Afin de récupérer les URL de la page, j'ai modifié le code utilisé dans includes/page_tail.php :
require_once('
functions_urlrewrite.
'
.
$phpEx
);
//
// Find all the links in the page
// There are 4 parenthesized parts in these regular expressions:
// #1: there might be an option like class="..."
// #2: full path to the target Web page
// #3: #1 bis
// #4: text of the link (optional)
//
$regexes
=
array(
'
a
'
=>
'
#<a(.+)href="([^"]+)"([^>]*)>(.*)</a>#Usi
'
,
'
form
'
=>
'
#<form(.+)action="([^"]+)"([^>]*)>#Usi
'
,
'
link rel
'
=>
'
#<link rel(.+)href="([^"]+)"([^>]*)>#Usi
'
);
foreach($regexes
as $link_type
=>
$pattern
){
$matches
=
array();
if($link_type
==
'
a
'
){
// Restore only anchor-type links
if(preg_match_all($pattern
,
$contents
,
$matches
,
PREG_SET_ORDER)){
$contents
=
restore_URL($contents
,
$matches
);
}
}
$matches
=
array();
if(preg_match_all($pattern
,
$contents
,
$matches
,
PREG_SET_ORDER)){
$contents
=
rewrite_URL($contents
,
$matches
,
$link_type
);
}
}
Étudions maintenant la fonction restore_URL().
Le principe est similaire à celui de la fonction rewrite_URL() : commencer par répertorier toutes les URL à réécrire, puis tout traiter d'un coup à l'aide de la fonction str_replace().
/*
* Restore URL to their original (not rewrited) state
* it builds a string suitable for URL
* @param string $string The string to rewrite
* @global array $lang The language variables
* @return string The rewritten string
*/
function restore_URL($contents
,
$matches
){
global $raw_URL
,
$rewritten_URL
;
$patterns
=
array();
// The link patterns will be added to this array
$replacements
=
array();
// The link replacements will be added to this array
foreach($matches
as $match
){
$current_url
=
trim($match
[
2
]
);
if(in_array($current_url
,
$patterns
)){
continue;
// Skip this match
}
foreach($rewritten_URL
as $pool
){
//
// Old and new rewriting (handled as a pool of URL)
//
foreach($pool
as $key
=>
$regexes
){
//
// Each rewrited URL in this URL pool (usually: one)
// These URL should be available in a generic form
// using a regular expression syntax (without delimiters)
//
foreach($regexes
as $key
=>
$regex
){
$regex
=
'
/
'
.
$regex
.
'
/
'
;
if(preg_match($regex
,
$current_url
)){
$changed_url
=
preg_replace($regex
,
$raw_URL
[
$key
],
$current_url
);
$patterns
[]
=
'
href="
'
.
$current_url
.
'
"
'
;
$replacements
[]
=
'
href="
'
.
$changed_url
.
'
"
'
;
break 2
;
}
}
}
}
}
return str_replace($patterns
,
$replacements
,
$contents
);
}