MODx - Du Rewriting sans Apache mod_rewrite avec MultiviewRewriting

Dans ce post je vais présenter:

Nous étudierons ensuite deux (1 et 2) anciennes solutions exitantes (pas obligatoirement très propre) permettant d'émuler l'url rewriting chez free, tout en les appliquants au monde MODx via des exemples.

Enfin, nous aborderons le concept du Multiview, et nous l'utiliserons sous MODx afin d'émuler proprement du rewriting. Cette mise en place est facilité par le plugin MultiviewRewriting. Son fonctionnement est présenté en fin de post. Il est téléchargeable en fin de post, son source est également directement disponible.

URL rewriting ?

L'URL rewritting est une technique permettant d'améliorer le référencement (la visibilitédu site via un site de recherche comme google) des sites dynamiques.
Les sites dynamiques sont souvent accéder via des url complexes comportant une liste de paramétres commençant par un ? et délimités par des &.
Par exemple: article.php?id=51&page=2&rubrique=5 est une adresse complexe. Un autre exemple parlant: www.fabienletort.com/index.php?q=4. Ce lien n'est rien d'autres que le lien vers cet article.... pas très sexy !
L'URL rewritting est donc une technique permettant de rendre ce genre de lien beaucoup plus lisible  aussi bien par l'internaute que par les moteurs de recherches... On ne s'apperçoit plus que la page est une page dynamique, on pourrait même croire à une page statique, en présentant un lien beaucoup plus lisible. Ainsi l'url de notre page actuelle devient: www.fabienletort.com/blog/2008/modx-plugin-multiviewrewriting.html. La régle de convertion est définie par le webmaster du site. L'ancienne adresse est bien entendue toujours valide, il faut juste vieiller à ne jamais l'utiliser dans son site afin de ne pas la communiquer...

Sous MODx tout ceçi est géré très facilement via  l'interface d'administration, comme l'indique ce guide. Il est donc possible d'activer cette option, de définir un préfixe et suffixe fixe pour toutes les pages (le suffixe étant généralement .html, faisant croire à une réelle page) et un alias est défini pour chaque page.

Mais tout ceçi s'appuie sur une condition ! Votre hébergeur doit supporter l'extension mod_rewrite d'Apache. Et bien sûr, en France, on a un hébergeur gratuit qui connait un grand succés (www.free.fr) et qui ne supporte pas cette option.

Nous allons d'abord voir ici différentes technique plus ou moins sexy qui ont déjà était plus ou moins abordés sur le web pour contourner ce problème. Nous allons juste les adopter à l'architecture de MODx. Enfin nous finirons par la plus sexy, s'inspirant de différentes solutions,et intégrable facilement sous MODX à l'aide d'un plugin !

1ère Méthode, l'Erreur 404

Cette méthode, assez vieille (des posts de 2004 en parlent), utilisée par certains sur les hébergements free, permet de contourner le problème d'une manière qu'on pourrait qualifier d'assez "bourrine". Elle n'est certes pas très sexy, mais cela marche, et ce de manière très simple.

Le principe de base est de rediriger toutes ces urls virtuelles vers un script php qui effectuera la réécriture de l'url. Si on tape, sans aucune astuce, ce genre d'url, on va arriver sur une page d'Erreur 404. L'astuce se trouve içi. Chez free, il est posssible de spécifier sa page d'erreur 404 perso. Cette page sera donc simplement notre script de réécriture !

Ajout de la régle dans le fichier .htaccess spécifiant notre page d'erreur :

ErrorDocument 404 /rewrite.php

Source du script de réécriture,rewrite.php

 
<?php
header("HTTP/1.0 200 OK");
$url = str_replace("modx/", "modx/index.php?q=", $_SERVER['REQUEST_URI']);
header('Location: '.$url);
?>
 
Dans cet example, modx est installé dans le sous-répertoire modx. La première ligne permet de changer le header HTML. En effet, sans cette ligne, celui-ci serait envoyé avec une erreur au navigateur. Il ne faut pas oublier qu'on se trouve ici dans un cas d'erreur. C'est le côté pas très sexy. Les deux autres lignes permettent d'appeller modx avec la bonne requête.

Cela fonctionne, par contre, l'adresse est changée dans la barre des taches du navigateur. Cette ancienne méthode permettaient surtout une visibilité sur une adresse non dynamique pour les navigateur de recherche. L'utilisateur, lui, au final, voyait quand même l'adresse dynamique.

Source de cette solution:

  • Lionel : http://lionel.suz.free.fr/index.php?id=about&sub=blog&entry=1076844339
  • Le post de ce forum: http://www.webrankinfo.com/forums/viewtopic_12843.htm

2ème Méthode, l'Erreur 404 plus sexy

On va encore utilisée la méthode de redirection sur Erreur 404, mais cette fois-ci on va éviter la redirection envoyée au navigateur: on va directement appeler le script avec les bons paramétres. Içi, je me suis inspiré de la solution de pablo expliquée sur ce post.

On garde donc la régle du fichier .htaccess afin de garder l'appel à notre script. Le script va par contre être légèrement modifié :

 
<?php
header("HTTP/1.0 200 OK");
$url = str_replace("modx/", "", $_SERVER['REQUEST_URI']);
// modx seems to use _REQUEST, see getDocumentMethod in document.parser.class.inc.php
$_REQUEST["q"] = $url;
require_once("index.php");
?>
 

Encore une fois, cet example nécessite que modx soit installé dans le sous-répertoire modx. Içi on remplace la redirection par un appel directe au script principal de modx. On passe alors le paramétre récupéré dans l'url dans la variable global $_REQUEST. Cela permet donc d'accéder au script dynamique avec l'url "non-réecrite" comme avec le vrai url rewritting livré dans le .htaccess par défault avec MODx. En clair, avec cet example un appel à www.site-web.com/modx/la-vie-des-mouches-en-antarctique appel en fait l'url dynamique www.site-web.com/modx/index.php?q=la-vie-des-mouches-en-antarctique. Cette fois-ci, l'utilisateur ne voit rien... Il pourra bookmarquer la belle url.

3ème Méthode, le Multiview

Cette méthode se base encore sur un post de pablo. Elle permet déjà de ne pas utliser la bidouille de redirection sur Erreur 404. Cela n'est pas très propre et j'ai déjà lu des discutions parlant d'éventuels problèmes de référencement sur ce genre de bidouille. Nous alons donc utiliser içi l'option Multiview offerte par apache. Celle ci est disponible chez free et de plus activée par défault. Dans la suite de cette article l'option ajoutée dans le .htaccess peut donc être supprimée.

Multiview ? 

Le Multiview permet d'accéder à un fichier sans spécifier son extension. La page test.php peut donc être accéder en tapant seulement test. De plus, il est possible d'ajouter, un slash suivi de n'importe quoi après ce nom de fichier (avec ou sans extension): on arrivera toujours sur la même page. Ainsi toutes les adresses suivantes pointent sur test.php :

  • test
  • test/
  • test/categorie/
  • test/categorie/article.truc
  • test/cat/page.html

Pour vérification (cela fait toujours du bien), créez un simple fichier test.php et tapez les différentes urls ci-dessus. Votre fichier test.php peut comporter un simple echo comme ci-dessous:

 
<?php echo("Test URL Rewritting"); ?>
 

Appliquons le à MODx

Nous allons donc appliquer cette méthode à MODx.
Dans notre cas, c'est un peu plus compliqué. En effet, dans son post pablo met en place une redirection en se basant sur le fait que tous ces documents se trouvent dans le sous répertoire virtuel blog/. blog.php est donc son script de redirection. Nous, nous somme suceptible d'avoir n répertoire parent virtuel dans notre site : ce sont tous les documents root de notre site MODx. Ainsi au même niveau que l'index.php de MODx, il va falloir créer autant de document.php qu'on a de document de 1er niveau dans la hiérachie modx. Par exemple si blog est l'alias d'un document root, le fichier blog.php doit contenir le script de redirection.

Cette méthode plus propre, ajoute donc aussi quelque contraintes dans la configuration des URLs simples sous MODx :

  • L'option Chemin d'accès pour les alias simples doit être activée. En effet, comme on se base sur les documents roots pour la redirection, ceux-ci doivent toujours être présent dans les urls utilisées.
  • L'option Suffixe des URLs simples ne doit pas contenir une extension de fichier du genre ".html". (sauf .php qui serait envisageable). En effet, pour des documents fils, il n'y aurait pas de problème : modx/blog/article.html appelera le script modx/blog.php. Par contre, les liens générés par modx vers les documents root seront aussi de cette forme: modx/blog.html. Dans ce cas le Multiview ne fonctionne pas... on a une erreur 404 ! Le plus simple pour le moment est donc de laisser cette option vide.

Pour faire simple nous allons garder un seul script de redirection, rewrite.php. La nouvelle version est la suivante (modx est toujours installé dans le répertoire /modx) :

 
<?php
$url = str_replace("modx/", "", $_SERVER['REQUEST_URI']);
// modx seems to use _REQUEST, see getDocumentMethod in document.parser.class.inc.php
$_REQUEST["q"] = $url
require_once("index.php");
?>
 

Elle ressemble beaucoup à notre 2ème solution. On a enlevé le forçage du header html à OK qui n'est plus utile.

Pour chaque document root, on aure donc besoin d'un fichier php incluant ce script générique. Par exemple, si blog est l'alias d'un document root, on aura un fichier blog.php au même niveau que l'index.php de modx, contenant :

 
<?php require_once("rewrite.php"); ?>
 

La solution: du multiview automatisé - plugin MultiviewRewriting

Nous sommes des fainéants, nous allons donc automatiser la 3ème solution à l'aide d'un plugin.

Par rapport à nos examples précédants, il a deux choses à améliorer:

  • le rewrite.php ne doit plus contenir le répertoire d'installation de MODx
  • un fichier php doit être crée pour chaque document root présent dans votre site MODx.

Le script rewrite.php est donc réécrit afin de le rendre universel.

 
<?php
// Get script_name
$sapi= 'undefined';
if (!strstr($_SERVER['PHP_SELF'], $_SERVER['SCRIPT_NAME']) && ($sapi= @ php_sapi_name()) == 'cgi') 
{
  $script_name= $_SERVER['PHP_SELF'];
} 
else 
{
  $script_name= $_SERVER['SCRIPT_NAME'];
}
 
// Get Modx Base Url Installation
$base_url = str_replace("\\", "/", dirname($script_name));
 
// remove the Base Url from Actual Request Url to get Modx Request url
if ($base_url != '/')
{
  $url = str_replace($base_url, "", $_SERVER['REQUEST_URI']);
}
else
{
  $url = $_SERVER['REQUEST_URI'];
}
 
 
// modx seems to use _REQUEST, see getDocument Method in document.parser.class.inc.php
$_REQUEST["q"] = $url; 
require_once("index.php");
?>
 

Enfin un plugin est crée, "MultiviewRewriting" afin d'automatiser la création des fichiers php incluant le script rewrite.php.

Présentation, Fonctionnement du Plugin MultiviewRewriting

Ce plug-in permet de prendre en compte les différentes façon d'accéder à un document (par alias ou id). Par exemple, considérons le document ayant comme alias blog, et comme id 2. On peut donc y accéder de cette manière: www.fabienletort.com/blog ou www.fabienletort.com/2. Bien sûr, si MODx est bien paramétré, seul le lien le plus parlant www.fabienletort.com/blog sera communiqué dans les liens internes au site. Mais l'autre existe et fonctionne. Içi, sur www.fabienletort.com, on utilise le mod url_rewriting d'apache et l'url par id fonctionne donc toujours. Avec notre MultiviewRewriting, on peut choisir via un paramétre la possiblitée d'utliser la méthode par id ou non. En effet, pour activer la redirection par alias le fichier blog.php doit être crée. Pour la méthode par id, c'est le fichier 2.php qui doit être crée.

Par défault, le plugin ne génére du rewriting que pour l'alias du document. Si celui-ci n'est pas présent, alors le rewriting sera activé pour l'id. Une option de configuration (paramIdRedirection) permet cependant d'activer toujours le rewriting sur id même si un alias existe.
Le (grand) schéma ci-dessous permet d'expliquer plus simplement son fonctionnement.

Flowchart of MultiviewRewriting MODx Plugin

Source du plugin

 
/*
 * @Title:   MultiviewRewriting
 * 
 * @Brief:   Simulate URL Rewriting by Multiview 
 *           (Very usefful on webhosting like free.fr (and similar one))
 * 
 * @Author:  Fabien Letort (www.fabienletort.com)
 * 
 * @Version: 0.1
 *
 * @license: GNU General Public License 2.0
 *
 * @see:
 *     - On author French Blog:
 *       http://www.fabienletort.com/blog/2008/modx-plugin-multiviewrewriting 
 *     - On Modx Repository:
 *       http://modxcms.com/MultiviewRewriting-0.1-2044.html 
 * 
 *  - Plugin Configuration Needed:
 *     &paramIdRedirection=Id Redirection Always Activated;list;true,false;false
 *  - Events that must be selected in the System Events tab.
 *     OnBeforeDocFormSave, OnDocFormDelete
 *
 * This plugin simulates URL Rewriting on webhosting that does not support this
 * feature.
 * 
 * @warning:
 *   - The wehosting must support Mutiview feature and this option must be
 *     activated.
 *   - MODx must be configurated with :
 *        - Alias paht for fiendly url activated
 *        - empty suffix & prefix for friendly url
*/
 
$debug = FALSE;
 
$e = &$modx->Event;
$isIdRuleRequested = ($paramIdRedirection  == 'true') ? TRUE : FALSE;
 
switch($e->name) {
  case 'OnBeforeDocFormSave':
    /* The OnBeforeDocFormSave is send by manager\processors\save_content.processor.php
     * See case new and case edit of this file to find global and params definition */
    global $alias;    // The Current Document Alias
    global $parent;   // The Document Id of the parent Doc 
    $parentId = $parent;  // The Document Id of the parent Doc.
    $docAlias = $alias;   // The Current Document Alias
    $docId = $modx->event->params["id"];  // The Current Document Id
    $mode = $modx->event->params["mode"]; // The Save Mode: 'new' our 'upd'
 
    if ($debug)
    {
        echo("Debug<br/>");
        echo('ParentId: '.$parentId.'</br>');
        echo('CurrentDocId: '.$docId.'</br>');
        echo('CurrentDocAlias: '.$docAlias.'</br>');
        echo('Mode: '.$mode.'</br>');
    }
 
    // If it is a root document 
    if ($parentId == 0)
    {
       // UPDATE CASE
       if ($mode == 'upd')
       {
           // Get Old Alias
           $pageInfo = $modx->getPageInfo($docId, 0, 'alias');
           $docPrevAlias = $pageInfo['alias'];
           if ($debug)
           {
              echo 'Update<br/>';
              echo('NewDocAlias: '.$docAlias.'</br>');
              echo('PreviousDocAlias: '.$docPrevAlias.'</br>');
           }
 
           if ($docAlias != $docPrevAlias)
           {
               // Alias is modified
 
               if ( ($docPrevAlias != '') &&
                    file_exists($modx->config['base_path'].$docPrevAlias.'.php') )
               {
                   // Remove Previous Alias Rewritting Rule
                   unlink($modx->config['base_path'].$docPrevAlias.'.php');
               }
 
               if ($docAlias != '')
               {
                   //Generate alias rewritting Rule
                   copy($modx->config['base_path'].'/assets/plugins/multiviewRewriting/rootTemplate.php',
                        $modx->config['base_path'].$docAlias.'.php');
               }
           }
 
           if ( ($isIdRuleRequested || $docAlias=='') && !file_exists($modx->config['base_path'].$docId.'.php') )
           {
               // id rewritting rule is requested (or alias null) and id rule does not exist
               // (the parameter $paramIdRedirection has just been modified or alias becomes null)
 
               // Add Id Rewritting Rule
               copy($modx->config['base_path'].'/assets/plugins/multiviewRewriting/rootTemplate.php',
                    $modx->config['base_path'].$docId.'.php');
           }
           else if( ($docAlias != '') && !$isIdRuleRequested && file_exists($modx->config['base_path'].$docId.'.php') )
           {
               // if an alias rule exist, if the id rule exist but this one
               // is not requested => delete it
               unlink($modx->config['base_path'].$docId.'.php');
           }
 
       }
 
       // NEW DOCUMENT CASE
       if ($mode == 'new')
       {
           if ( ($docAlias == '') || !isset($docAlias) )
           {
               // No Alias defined => Only generate Id Rewritting Rule
               $filenames[] = $docId.'.php';
           }
           else
           {
               // Alias defined => Generate alias rewritting Rule
               $filenames[] = $docAlias.'.php';
 
               // generete also Id Rewritting Rule if it is requested
               if ($isIdRuleRequested)
               {
                   $filenames[] = $docId.'.php';
               }
           }
 
           // generate all requested URL Rewritting Rule
           foreach( $filenames as $file )
           {
               copy($modx->config['base_path'].'/assets/plugins/multiviewRewriting/rootTemplate.php',
                    $modx->config['base_path'].$file);
           }
       }
    }
    break;
 
  case 'OnDocFormDelete':
    /* The OnDocFormDelete is send by manager\processors\delete_content.processor.php
     * See this file to find param definition */
    $docId = $modx->event->params["id"];  // The Current Document Id
    if ($debug)
    {
        echo("Debug<br/>");
        echo('CurrentDocId: '.$docId.'</br>');
    }
 
    // Get Old Alias
    $pageInfo = $modx->getPageInfo($docId, 0, 'alias');
    $docPrevAlias = $pageInfo['alias'];
 
    // Alias exists
    if ( ($docPrevAlias != '') &&
          file_exists($modx->config['base_path'].$docPrevAlias.'.php') )
    {
        unlink($modx->config['base_path'].$docPrevAlias.'.php');
    }
 
    // delete also $docId.'.php' if exists
    if (file_exists($modx->config['base_path'].$docId.'.php'))
    {
        unlink($modx->config['base_path'].$docId.'.php');
    }               
    break;
 
 
  default:
    return;
    break;
}
 

Télécharger depuis le repository MODx

top