Reescribir direcciones con mod_rewrite

Muchas veces, cuando estamos haciendo páginas web, nos interesa tener URI lo más limpias que sea posible; no ya porque te indexen mejor los buscadores o porque queden más bonitas, sino porque un usuario normal, por lo general, va a recordar más fácilmente una dirección de este tipo, con lo que le será más fácil volver a nuestra página.

Para esta tarea se suelen usar archivos .htaccess del servidor HTTP Apache junto con el módulo de reescritura del mismo (el mod_rewrite). El mod_rewrite es una pequeña extensión de Apache que nos permite que, al visitar una dirección de una página, realmente se está llamando a otra diferente.

Funcionamiento

Apache usa archivos con el nombre de .htaccess (que no es que tengas que poner nombre.htaccess, sino simplemente eso, .htaccess) para que el administrador de las páginas web (que no del servidor) pueda definir una serie de parámetros de configuración para su espacio. Deben estar ubicados en el directorio sobre el que quieras aplicar esa configuración.

Crear archivos de este tipo en plataformas Microsoft Windows puede ser un problema, ya que el famoso "sistema operativo" no te deja poner archivos sin nombre (solo tiene extensión), pero ello no significa que no se pueda hacer.

El archivo se puede crear de varias maneras, yo recomiendo PHP, ya que es muy fácil de hacer. Simplemente con poner algo como lo siguiente nos deberí­a crear el archivo:

<?php
touch('.htaccess');
?>

Antes de seguir adelante debemos comprobar que podemos usar los archivos .htaccess y que tenemos el mod_rewrite activado.

Comprobar que podemos usar .htaccess es igualmente sencillo: basta con crear un archivo con ese nombre y poner en él una cadena aleatoria como, por ejemplo, "asdasd123"- y guardarlo en el directorio sobre el que queremos aplicar la reescritura; si el servidor nos devuelve un Internal Server Error es que todo ha ido bien, ya que querrá decir que el servidor procesa esos archivos.

Para comprobar que el servidor tiene el mod_rewrite activado podemos hacer un phpinfo() (si disponemos de PHP en el servidor). Si Apache está como módulo de PHP, podremos comprobar los módulos que tiene cargados; muy posiblemente el mod_rewrite esté entre ellos.

Para empezar deberemos poner al principio del documento (el .htaccess) la cadena RewriteEngine On, que se encarga de activar el módulo de reescritura. Tras poner esto ya debemos poder empezar a escribir nuestras reglas para formatear las direcciones como nos plazca. A veces puede ser necesario poner un Options FollowSymLinks antes para que funcione, de modo que quedarí­a así­:

Options FollowSymLinks
RewriteEngine On

Si te ha fallado alguno de los pasos o no estás seguro de si tienes activado el mod_rewrite, siempre puedes consultarle al administrador de tu sistema.

Funciones o comandos del mod_rewrite

Hay varias funciones (o comandos) que usaremos a menudo y debemos conocer para escribirlos sin tener que recurrir al manual cada vez. La sintaxis de los comandos del mod_rewrite es bastante sencilla y rápida de entender. Los comandos empiezan con Rewrite, siguiendo normalmente el patrón siguiente:

Comando Parámetro1 Parámetro2

Aunque en algunos casos varí­a ligeramente, como se verá a continuación:

RewriteEngine

Solo acepta dos valores para su único parámetro: On y Off. Le dice a Apache una vez puesto en el .htaccess si debe o no iniciar el motor de reescritura el cual se encuentra desactivado por defecto.

# Para activar la reescritura
RewriteEngine On
RewriteBase

Nos permite ajustar una "base" para las rutas que escribamos a partir del momento en el que se usa. Lo que hace es añadir a las rutas siguientes el prefijo que indiquemos, lo que puede ahorrar mucho espacio y es necesario muchas veces al no encontrarse el archivo .htaccess en el mismo directorio sobre el que se quiere aplicar (por eso es recomendable ponerlo en el .htaccess).

RewriteRule ^/pagina/index.xml$ /pagina/xml.php?generar=xml
#Con RewriteBase nos podemos ahorrar el /pagina/ de la siguiente forma:
RewriteBase /pagina/
RewriteRule ^index.xml$ xml.php?generar=xml
RewriteCond

Con esto se pueden definir sentencias condicionales. La sintaxis es muy simple y fácil de entender. Se pueden unir varias condiciones con el modificador OR.

A continuación de este comando se debe poner o bien otro RewriteCond (usando el modificador para unirlos), o bien un RewriteRule, que es el que se debe ejecutar en última instancia en caso de cumplirse la(s) condicion(es). En caso de no cumplirse la condición, el RewriteRule serí­a ignorado.

#RewriteCond Cadena Patrón
#Si la dirección contiene "pepe" se ejecuta el RewriteRule que habrí­a debajo
RewriteCond %{REQUEST_URI} pepe
RewriteRule

Posiblemente este sea el comando que más usaremos. Es el comando básico para lo que queremos hacer, ya que de él depende que se lleve a cabo la reescritura.

Lo que hace es simple: le das un patrón y una URI de destino; si el patrón coincide, se llama a la URI especificada con los parámetros que hayas indicado, etcétera. Las referencias hacia los valores agrupados con paréntesis en las expresiones regulares del patrón pueden hacerse con $1, $2… hasta $9.

Aquí­ es donde las expresiones regulares juegan un papel importante, ya que con ellas se formarán lospatrones de comparación. Es importante conocer su sintaxis básica y poder manejarlas con soltura para crear reglas efectivas.

Modificadores de RewriteRule

Esto son las "flags" de las que se habla en el manual oficial. Los modificadores sirven para añadir funciones adicionales a ciertos comandos del mod_rewrite, como RewriteRule o RewriteCond.

Cada comando tiene sus propios modificadores. Se ponen entre corchetes, tras un espacio al final del comando y se separan (en caso de especificar más de uno) con comas y sin espacios.

Hay varios y no los explicaré todos, ya que para eso está el manual oficial; solo expondré los pertenecientes a RewriteRule, que me parecen más útiles para el objetivo de este escrito.

A grandes rasgos, los modificadores que más nos interesan son los siguientes:

nocase (NC)

Este útil modificador hará que las expresiones regulares (o simplemente cadenas literales) que pongamos como patrón sean "case-insensitive", es decir, que el procesador no distinga entre mayúsculas y minúsculas. Esto nos puede venir bien muchas veces.

redirect (R[=codigo])

Permite redireccionar a una dirección con un código concreto de respuesta del protocolo HTTP. El rango, según el manual oficial, debe estar entre el código 300 (HTTP_MULTIPLE_CHOICES) y 400 (HTTP_BAD_REQUEST). Para conocer el significado de esas constantes y los códigos que puedes usar debes consultar las especificaciones de este protocolo.

Suele interesar que, al redireccionar por este método, el archivo .htaccess no siga siendo interpretado, para lo que usaremos el modificador L, que veremos más abajo.

Por defecto, si no se especifica un código concreto, se enví­a automáticamente el 302 (MOVED TEMPORARILY).

last (L)

Este modificador hace que la condición, en caso de que se cumpla, sea la última en interpretarse del archivo. En caso de no cumplirse seguirá su curso normal. Es bueno especificarlo casi siempre, ya que le va a ahorrar a Apache la interpretación del resto de reglas, que muy probablemente sean innecesarias, al haber detectado una que casa con las condiciones que se buscaban.

Construcción de reglas o patrones

Puedes construir tantas reglas como quieras, pero ten en cuenta que, cuanto más pesado el archivo, más le costará de interpretar a Apache. No recomiendo que pases de los 2 kB (que ya es mucho).

Se usan patrones basados en expresiones regulares (de tipo POSIX) a partir de Apache 1.2.x de manera que, si coinciden, se redirija al archivo que especifiquemos. Es realmente simple crear expresiones regulares para hacer las URI como las de esta página. Dos buenos manuales para aprender a hacer expresiones regulares efectivas son los siguientes:

Es muy importante que delimitemos el rango de caracteres correcto acorde a nuestras necesidades. Si necesitamos obtener un número… ¿para que permitir letras u otros sí­mbolos en el patrón? Esto nos ahorrará quebraderos de cabeza posteriores en lo referente a la seguridad de la aplicación final.

También suele ser necesario que, en las direcciones que puedan terminar con o sin barra, indiquemos esta eventualidad (es decir, que pongamos la barra del final como caracter opcional), algo que se podrí­a conseguir de la siguiente forma:

RewriteRule ^seccion/([0-9]+)/?$ index.php?seccion=$1

Si se diese el caso de que la barra opcional no está contemplada y es escrita en la dirección se lanzarí­a un error de tipo 404 (Página no encontrada).

Ejemplos de la vida real

Hasta ahora se ha intentado enseñar lo básico sobre este módulo de Apache y como funciona. Ahora que comprendemos un poco cómo trabaja, podemos poner unos ejemplos ambientados en la vida real.

Lo que vamos a hacer en el siguiente ejemplo es obtener y enviar un identificador numérico a partir de una URL de tipo example.com/articulo/identificador_numérico, o sea, coger el número y pasárselo a una aplicación:

RewriteEngine On
RewriteRule ^articulo/([0-9]+)/?$ articulos.php?id=$1 [L]

Si quisiésemos obtener el nombre de la sección de ese artí­culo (a partir de una dirección tipo example.com/articulo/sección/identificador_numérico) serí­a también muy sencillo:

#La sección puede contener letras, guiones y guiones bajos
RewriteRule ^articulo/([a-z_-]+)/([0-9]+)/?$ articulos.php?seccion=$1&id=$2 [NC,L]

Ojo porque el identificador numérico ya no está en $1, sino en $2, ya que es el segundo grupo de captura que hemos indicado. Al interesarnos tanto letras minúsculas como mayúsculas debemos poner el modificador NC. Problema común y final del escrito

Suele pasar que el programador, al usar el mod_rewrite por primera vez, después de haber hecho funcionar sus primeros patrones, etc. diga… ¡No me funcionan los enlaces! ¡No me carga la hoja de estilos! Es lógico, ya que seguramente se utilicen rutas relativas para hacer referencia a esos documentos (gráficos, estilo) y el "directorio" al que hace la petición el navegador no los contiene (está enmascarado, es virtual). Para solucionar esta eventualidad se debe indicar la dirección "base" de la página hacia el dominio principal e indicar el resto de rutas como relativas. Para esto tenemos el elemento <base /> de XHTML:

<head>
    <base href="http://www.example.com/" />
    …
</head>

Con ello se soluciona cualquier problema de que no cargue algo (siempre que ese algo exista, evidentemente).

Espero que se haya entendido lo mejor posible todo lo explicado. Si te ha quedado cualquier duda tienes varias opciones:

Los contenidos de esta página se rigen, a no ser que se especifique lo contrario, bajo una licencia de tipo Creative Commons

Resumen

Artículo donde se realiza una introducción al módulo mod_rewrite de Apache, para la implementación de URLs amigables (clean urls) en un sitio web, útiles para obtener direcciones más semánticas y para mejorar nuestro posicionamiento en los buscadores.

Índice

  1. Funcionamiento de mod_rewrite

Otros artículos