Clean URL + Free.fr + Drupal 5.x : une solution

La documentation Drupal 6 n'est plus maintenue et en cours de dépublication.

Voici une solution qui peut intéresser ceux qui ont installé drupal 5.x sur free.fr mais qui sont frustrés de ne pas pouvoir activer l'option "URLs simplifiées (Clean URL)".

Le principe

On fait appel à la redirection 404 (Page non trouvée) vers un script PHP comme décrit sur d'autres billets de ce site. Ce script émule le positionnement des variables super-globales correspondant à une requête HTTP standard. Ceci suffit pour les requêtes HTTP GET.

Pour les requêtes HTTP POST, cela ne marche pas car la redirection 404 oublie les variables POSTées et ce de manière irréversible apparemment. Ici, la solution consiste à débrayer l'option "Clean URL" lors de la soumission de requêtes HTTP POST. Dans la mesure où les modules installés (standards, additionnels ou persos) utilisent tous form.inc, il suffit d'intervenir à deux endroits: theme_form() et theme_hidden().

Détails

1) .htaccess

Tout d'abord ajouter la ligne suivante à votre fichier .htaccess:

ErrorDocument 404 /mod_rewrite.php

2) mod_rewrite.php

Créer un script mod_rewrite.php à la racine de votre site à partir du modèle ci-dessous. Les lignes marquées (*) doivent être modifiées si drupal est installé ailleurs qu'à la racine:

<?php
$url
= $_SERVER['REQUEST_URI']; // On récupère l'URL demandée

if(preg_match("^(.*)$/", $url, $match)) // (*) "/^\/dir\/to\/drupal\/(.*)$/"
{
   
header("HTTP/1.1 200 OK");
   
$url = $match[1];
   
$start_query = strpos($url, '?');
    if (
$start_query !== FALSE) {
       
$path = substr($url, 0, $start_query);
       
$query = "q=" . $path . "&" . substr($url, $start_query + 1);
    }
    else {
       
$path = $url;
       
$query = "q=" . $path;
    }
   
$params = explode("&", $query);
    foreach(
$params as $p) {
       
$fields = explode("=", $p);
       
$key = $fields[0];
       
$value = $fields[1];
       
$_GET[$key] = $value;
       
$_REQUEST[$key] = $_GET[$key];
    }
   
$_SERVER["REDIRECT_STATUS"] = 200;
   
$_SERVER["REDIRECT_URL"] = $url;
   
$_SERVER["QUERY_STRING"] = $query;
   
$_SERVER["SCRIPT_NAME"] = "/index.php"; // (*) "/dir/to/drupal/index.php"
   
$_SERVER["SCRIPT_FILENAME"] = $_SERVER['DOCUMENT_ROOT'] . $_SERVER["SCRIPT_NAME"];
   
$_SERVER["PHP_SELF"] = $_SERVER["SCRIPT_NAME"];
   
// chdir("dir/to/drupal"); // (*)
   
include("index.php");
    exit();
}
/* Erreur 404: compléter par le code PHP ou HTML à utiliser pour les "vraies" pages non trouvées (autres que celles gérées par drupal)*/
...
?>

3) includes/form.inc

Modifier les fonctions theme_form() et theme_hidden() contenues dans includes/form.inc comme ci-dessous. On peut évidemment créer ou modifier les fonctions mon_thème_form() et mon_thème_hidden() dans sites/themes/mon_thème/template.php pour éviter de toucher au noyau de drupal. Cependant, puisque celui-ci est déjà largement patché pour fonctionner sur free.fr autant continuer.

<?php
// [...]

/<strong>
 *
Format a hidden form field.
 *
 * @
param $element
 
*   An associative array containing the properties of the element.
 *  
Properties usedvalue, edit
 
* @return
 *  
A themed HTML string representing the hidden form field.
 */
function
theme_hidden($element) {
 
// Patch free.fr
 
if ($element['#name'] == 'attach-url') {
     
$element['#value'] = patch_clean_url_exception($element['#value']);
  }
 
// End patch free.fr
 
return '<input type="hidden" name="'. $element['#name'] . '" id="'. $element['#id'] . '" value="'. check_plain($element['#value']) ."" " . drupal_attributes($element['#attributes']) ." />\n";
}

// [...]

/</strong>
 * Format a form.
 *
 * @param
$element
 *   An associative array containing the properties of the element.
 *   Properties used: action, method, attributes, children
 * @return
 *   A themed HTML string representing the form.
 */
function theme_form(
$element) {
  // Patch free.fr
 
$element['#action'] = patch_clean_url_exception($element['#action']);
  // End patch free.fr
  // Anonymous div to satisfy XHTML compliance.
 
$action = $element['#action'] ? 'action="' . check_url($element['#action']) . '" ' : '';
 
return '<form '. $action . ' method="'. $element['#method'] .'" '. 'id="'. $element['#id'] .'"'. drupal_attributes($element['#attributes']) .">\n<div>". $element['#children'] ."\n</div></form>\n";
}

/**
 * Patch free.fr
 *
 * permet d'utiliser la méthode POST sur les pages dont l'URL a été réécrite (option clean_url=1)
 * lorsque cette option est positionnée, les formulaires qui ont pour destination des url réécrites
 * sont traités par le script d'exception 404 mod_rewrite.php qui interdit la méthode POST. Le patch
 * consiste à forcer les formulaires utilisant POST à débrayer l'option clean_url durant la soumission
 * du formulaire.
 *
 * Deux cas se présentent:
 * - attribut action de <form> => modifié dans theme_form()
 * - champ caché contenant une URL => modifié dans theme_hidden()
 */
function patch_clean_url_exception($uri){
  global
$base_url;
 
$script = 'index.php';
 
$abs_path = $base_url . "/";
 
$base_path = base_path();
  if (
$uri && (strlen($uri) > 0)) {
     
$path = $uri;
     
// trim base if any
     
if (strcmp($abs_path, substr($path, 0, strlen($abs_path))) == 0) {
         
$path = substr($path, strlen($abs_path));
      }
      elseif (
strcmp($base_path, substr($path, 0, strlen($base_path))) == 0){
         
$path = substr($path, strlen($base_path));
      }
     
// trim script if any
     
if (strcmp($script, substr($path, 0, strlen($script))) == 0) {
         
$path = substr($path, strlen($script));
      }

      if (
substr($path, 0, 1) != '?') {
         
// option clean_url débrayée sur cette URL
         
$uri = $base_path . "?q=" . preg_replace('/\?/', '&', $path, 1);
      }
  }
  else {
     
// base url forcée car on ne sait pas de quelle page on vient
     
$uri = $base_path . "?q=" . $_GET['q'];
  }
  return
$uri;
}
?>

Configuration

Une fois ces modifications apportées, vous pouvez aller dans le menu d'administration et configurer l'option "Clean URL".

Conclusion

Ce patch implémente correctement l'option "Clean URL" pour un hébergement drupal sur free.fr, dans la mesure où on n'introduit pas de modules ou de modifications trop spécifiques.

En espérant que ça vous soit utile...

Version de Drupal : 

Commentaires

Très intéressant et cela fonctionne bien : je remarque juste que tu as une erreur de syntaxe :
Ce n'est pas : if(preg_match("^(.)$/", $url, $match))
mais bien if(preg_match("/^(.
)$/", $url, $match))

Le slash est important avant le ^.

je vous remercie pour le tuto, mais pour Drupal 6.0 la case pour activé le clean url, reste grisée, donc pour activer le clean url il faut taper manuellement ESPACE.free.fr/admin/settings/clean-urls
Merci à vous encore une fois...