Routez vos visiteurs !

Voici un petit bout de code permettant de résoudre un phénomène dû à l’utilisation des routes avec CakePHP. Lors d’une question récemment posée sur IRC, un membre a soulevé une remarque intéressante vis-à-vis du système de routage de Cake : lorsqu’une route existe pour une page, rien n’empêche l’utilisateur d’accéder à la page en utilisant l’url d’origine « /controller/action/param1/param2« .

Ci-après une illustration du problème avec le contrôleur « Pages » livré avec CakePHP, ainsi qu’une proposition de code pour rediriger correctement les utilisateurs. C’est l’occasion idéale pour découvrir quelques méthodes proposées par le Router de CakePHP.

Le problème

Prenons l’exemple du contrôleur « Pages » qui est livré avec CakePHP. Dans une nouvelle installation, la page d’accueil de l’application est la Page « home » correspondant à l’action « display » du contrôleur Pages. Ainsi, lorsque l’on accède à l’url http://monsite.com/ nous voyons en fait la page http://monsite.com/pages/display/home … ceci est dû à la route suivante, déclarée dans « /config/routes.php » :

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));

Mais rien n’empêche un utilisateur d’accéder à cette même page directement depuis l’url http://monsite.com/pages/display/home. Dans la plupart des cas, c’est assez peu important mais vous pouriez vouloir éviter ceci pour des raisons de référencement (duplicate content, changements d’url) ou autre.

Une solution

La solution suivante consiste à analyser l’url actuelle pour déterminer quelle action est appelée, puis de vérifier si l’url correspond aux routes déclarées. Si l’url ne correspond pas il suffit simplement de faire une redirection 301 vers l’url correcte.

Dans la méthode beforeFilter de votre AppController, ajoutez l’instruction suivante :

/**
 * Before filter callback
 *
 * @return void
 * @access public
 */
 public function beforeFilter() {
    $this->_checkRoute();
 }

Et créez la méthode « _checkRoute » dans votre AppController, avec l’implémentation suivante :

/**
 * Check that the current page has been accessed through the correct url.
 * When current url does not match the correct route, user is redirected to the correct location
 *
 * @return void
 * @access protected
 */
 protected function _checkRoute() {
    $urlParts = Router::parse($this->here);
    $url = array_merge($urlParts, $urlParts['pass'], $urlParts['named']);
    unset($url['pass'], $url['named']);
    if ($this->here != Router::url($url)) {
       $this->redirect($url, 301);
    }
 }

… et le tour est joué !

Petite analyse

La première ligne décode l’url actuelle ($this->here) pour récupérer chaque partie dans un tableau. Ensuite, les paramètres nommés et non-nommés sont ajoutés au tableau de base décrivant l’url afin que celui-ci puisse être utilisé pour générer l’url correcte de la page.

Si l’url générée est différente de l’url actuelle l’utilisateur est redirigé au bon endroit.

Pour information, je n’ai jamais utilisé ce code dans une application mais n’ai fait que quelques tests basiques pour vérifier son bon fonctionnement. Si vous l’utilisez et trouvez des problèmes, n’hésitez pas à me les parvenir dans les commentaires ;)

Partagez avec vos amis !
  • del.icio.us
  • Twitter
  • Tumblr
  • Facebook
  • Digg
  • LinkedIn
  • Google Bookmarks
  • email
  • Technorati
  • Wikio FR
  • Netvibes
  • RSS
If you enjoyed this post, make sure you subscribe to my RSS feed!

Tags : CakePHP, routes
blog comments powered by Disqus