URL amigables genéricas

21 de September, 2007

Las URL amigables se están usando hace ya bastante tiempo, consiste en acortar las URL y hacerlas lo mas “humanas” posibles. ¿Para qué? estética, optimizacion para buscadores, lograr URL mas fáciles de recordar, etc. Con ésta técnica intentamos pasar de una url como la que sigue:

www.example.com/index.php?categoria=15&pagina=3&orden=asc

A una como esta:

www.example.com/categoria/15/pagina/3/orden/asc

o bien:

www.example.com/15/3/asc

¿Cómo se logran?

Depende con que servidor trabajes. Si trabajas con Internet Information Server (IIS) podrás lograrlas con ISAPI_Rewrite entre otros. Si trabajas sobre APACHE, podrás lograrlas a través de un fichero .htaccess solo si tenés activado mod_rewrite.
Seguramente haya algunas alternativas más, yo solo conozco estas.

En este artículo explicaré como hacerlo con APACHE, mod_rewrite y un .htaccess (mas un poco de ayuda de PHP, claro), usando un archivo index.php como receptor de todas las peticiones, tal como sucedía en el sencillo ejemplo de mvc que comente el otro día.

Probando el .htaccess

El .htaccess de prueba(y definitivo) que debes usar es el siguiente:

<ifmodule mod_rewrite.c>
RewriteEngine On

#Si la url solicitada no es un fichero(existente), continuar...
RewriteCond %{REQUEST_FILENAME} !-f

#Si la url solicitada no es una carpeta(existente), continuar...
RewriteCond %{REQUEST_FILENAME} !-d

#se toma todo ese -query_string- y se pasa como parametro route
RewriteRule ^(.*)$ index.php?route=$1 [L,QSA]
</ifmodule>

Y un archivo .php para probar:

1
< ?php echo $_GET['route']?>

Estos dos archivos los podrias subir a un directorio-de-prueba de tu sitio y la url para probar si todo funciona seria:

www.tusitio.com/directorio-de-prueba/esto/funciona/bien

Si se imprime por pantalla “esto/funciona/bien” estas de suerte, todo está perfecto, de lo contrario, al final del artículo te doy algunas opciones.

Recuperando las variables de la URL

Como habrás visto en el ejemplo, la gracia es que todas esas variables que intentamos pasar como si directorios fueran, quedan almacenadas en una variable GET (de las de verdad) llamada route gracias a la tarea que realiza el .htaccess y el mod_rewrite. Ya sabes donde están las variables, ahora tenes que decidir como las vas a usar.

Nombre – Valor

Si vas a pasar por URL el nombre de la variable y su correspondiente valor tal como en el siguiente ejemplo:

www.example.com/categoria/15/pagina/3/orden/asc

El contenido de tu index.php deberá ser algo como lo que sigue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
< ?php
function getVariables($url)
{
	//quitamos la barra del final
	$url = preg_replace('/\/$/', '', $url);
 
	//separamos las partes de la url y las contamos
	$partes = explode('/', $url);
	$cantPartes = count($partes);
 
	//si la cantidad de partes no es par retornamos false, al ser impar una variable se quedaria sin valor y esto no es posible
	if($cantPartes % 2 != 0)
		return false;
 
	$variables = array();
	for($c = 0; $c < $cantPartes; $c = $c + 2)
	{
		//Acumulamos los pares de valores(para nosotros variables) en el arreglo
		$nombre = limpiar($partes[$c]);
		$valor = limpiar($partes[$c + 1]);
		$variables[$nombre] = $valor;
	}
 
	return $variables;
}
 
function limpiar($valor)
{
	//permitimos solo letras(a-Z), numeros y guiones
	return preg_replace('/[^a-zA-Z0-9-_]/', '', $valor);
}
 
$_GET = getVariables($_GET['route']);
 
if($_GET)
{
	echo '< pre>';
	print_r($_GET);
	echo '< /pre>';
}else{
	echo 'No hay variables GET';
}
?>

Ejemplo en mi sitio: urls-genericas/valores/mivariable/valor/otravariable/otrovalor

1
2
3
4
5
Array
(
    [mivariable] => valor
    [otravariable] => otrovalor
)

Solo valores

Si con el ejemplo anterior te parece que la URL queda muy larga, podés quitar el nombre de las variables y recibir los valores como un simple arreglo. Eso si, debes tener mucho cuidado de ser ordenado y mantener un orden en los parámetros o te harás un lió.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
< ?php
function getVariables($url)
{
	//quitamos la barra del final
	$url = preg_replace('/\/$/', '', $url);
 
	//separamos las partes/variables de la url y las contamos
	$variables = explode('/', $url);
	$cantVariables = count($variables);
 
	for($c = 0; $c < $cantVaraibles; $c++)
	{
		//Acumulamos los valores en un arreglo
		$variables[$c] = limpiar($variables[$c]);
	}
 
	return $variables;
}
 
function limpiar($valor)
{
	//permitimos solo letras(a-Z), numeros y guiones
	return preg_replace('/[^a-zA-Z0-9-_]/', '', $valor);
}
 
$misVariablesGet = getVariables($_GET['route']);
 
if($misVariablesGet)
{
	echo '< pre>';
	print_r($misVariablesGet);
	echo '< /pre>';
}else{
	echo 'No hay variables GET';
}
?>

Ejemplo en mi sitio: urls-genericas/valores/valor/otrovalor

Array
(
    [0] => valor
    [1] => otrovalor
)

A tener en cuenta

Por las reglas que pusimos en nuestro .htaccess estamos pidiendo que todo “query_string” que no exista(lo que comúnmente arroja un error 404) sea dirigido a nuestro index.php. Es necesario que lo tengas en cuenta, porque si entro a tu sitio y busco un fichero que no existe, seré redirigido a tu index.php (inténtalo en mi blog, verás donde eres redirigido). Aprovecha esto para hacer una página de error 404 personalizada para tus usuarios, como la de mi blog por ejemplo.

Por otro lado, si pretendes utilizar una URL como misitio.com/seccion/3 es necesario que tengas en cuenta que para que te llegue la variable sección a tu index.php no debería haber ningún directorio con dicho nombre o lo que veras es el contenido de ese directorio y no tu index.php

¿Por qué en el titulo dice URL genéricas?

Intentaba expresar que era un mini sistema que funciona para cualquier numero de variables, sin necesidad de andar cambiando el fichero .htaccess a cada momento.

¿Es todo?

Por ahora si. Tené en cuenta que es un simple ejemplo y de seguro se puede mejorar. Por lo pronto yo mejoraría un poco el filtro(función limpiar y demas) ya que lo que hace actualmente es borrar caracteres no deseados cuando en realidad debería arrojar un error 404 o similar. La idea es que no haya varias URL diferentes apuntando al mismo contenido, podés leer mas sobre el tema buscando sobre posicionamiento en buscadores.

Podés descargar los ficheros para probarlos desde aquí.

Problemas al usar .htaccess

Si al subir el .htaccess y probarlo te tira un error es probable que no tengas activado el mod_rewrite o tu host no te permite utilizar ficheros .htaccess, contacta con el soporte técnico pero mientras tanto borra el fichero para que no siga tirando error. En algunos hosts cuando subes el archivo .htaccess, este desaparece o se oculta, en este caso si te tira error y no podes borrar el fichero porque no lo ves, sube otro .htaccess vacio para que sobrescriba el anterior.

Si estás trabajando en tu servidor local y tenés problemas es muy probable que los soluciones editando el archivo httpd de apache/conf y habilitando el mod_rewrite, debes descomentar la linea que dice #LoadModule rewrite_module quitandole el # que lleva por delante. Si usas XAMPP, ImZyos te explica como habilitarlo. Si usas WAMP5, creo que te alcanza con acceder al menú->apache_modules->rewrite_module.

Popularity: 13% [?]

Otros artículos

28 comentarios en “URL amigables genéricas”

  1. ImZyos! Dijo:

    Jejeje, bien, yo puse un post en mi blog, pero es de risa al lado del tuyo ^^ exelente trabajo Federico

  2. ImZyos! Dijo:

    yo dejo mi función haber si a alguien le sirve:

    extract(getVars());

    function getVars()
    {
    $vars = explode(‘/’, preg_replace(‘/\/$/’, ”, $_GET['route']));
    foreach($vars as $value)
    $var[$value] = $value;
    return $var;
    }

  3. Federico Dijo:

    Hola ImZyos!

    Parece mas sencillo tu código, de hecho no me explico por que use for en lugar de foreach :D Lo único que cambiaría es que a extract le agregaría el parámetro EXTR_SKIP para que no sobrescriba variables existentes, por las dudas ya sabes jeje.

    Saludos!

  4. Arcadio Dijo:

    Muy buen post…

  5. ImZyos! Dijo:

    Jajaja, bueno eso si, en general yo me brinco la seguridad de mis funciones por algo simple, yo las mando a llamar, asi qeu si hay error sera mio por sobre escribir una variable duplicada, pero ya esta hecho el cambio ^^, gracias por el link.

  6. DooBie Dijo:

    Pues yo lo he probado, y para lo que quiero, me funciona sin problemas.
    Lo único que he tenido mas quebraderos de cabeza, han sido los caracteres especiales, ya que, si pasaba en la variable $_GET['route'] algún caracter inválido (la ñ, los acentos óáè o caracteres especiales como ¿¡!?) no los codificaba bien, con lo que he tenido que usar la función urlencode() de php para solventar el problema (la cual, no había usado hasta ahora :p)

    Gracias por el aporte compañero!

  7. Federico Dijo:

    Hola DooBie, gracias por compartir el inconveniente y solución.

    La otra es hacer como me parece que hace Wordpress, convierte las ñ en n, los acentos los pasa de é a e y borra todos los caracteres especiales.

    Saludos

  8. Daniel Dijo:

    Excelente articulo!!! me fue de mucha utilidad, lo unico que tuve que modificar en el .htaccess fue la siguiente linea:

    RewriteRule ^(.*)$ index.php?route=$1 [L,QSA]

    por

    RewriteRule .* /index.php?route=$1 [L,QSA]

    Me estaba dando un error 500 y de esa forma ya no sucede.

    Gracias!

  9. Daniel Dijo:

    Perdón, de esa forma no me pasaba la variable, la forma correcta es:

    RewriteRule ^(.*)$ /index.php?route=$1 [L,QSA]

    Saludos!!!

  10. Federico Dijo:

    Hola Daniel, gracias por compartirlo, de seguro le servira a alguien mas.

  11. Johnny Dijo:

    Muy bueno el post gracias

  12. Franco Dijo:

    bacan todo pero como se podria hacer esto de las variables amigables primero con varios archivos no solo el index.php es decir que recoja con otros archivos los valores, por ejemplo http://misitio/usuarios.php/user/2345.
    Así de lo anterior recojera variable user=2345
    Gracias de antemano por su respuesta..

  13. tikitakfire Dijo:

    muy buen post! no lo habia visto

    gracias por la info!

  14. andreco Dijo:

    exelente POST de verdad muy bueno, hata ahora visito tu blog y esta m,uy bueno… sigue asi te felicito

  15. andreco Dijo:

    Mi web experimento cambios en el diseño, no carla las imagenes, que pudo ser???

  16. Federico Dijo:

    Hola andreco, gracias por el comentario. Creo que olvide mencionarlo, pero seguro el problema se debe a la falta del tag base que debes agregar cuando utilizas url amigables.

    Referencia: Tag base

    Con este tag debes indicar el directorio raiz de tu sitio, para que asi pueda encontrar las carpetas/imagenes.

    Un saludo

  17. andreco Dijo:

    entiendo ahora el saunto es: para cargar css??? y cosas de este estilo, hay mas especificaciones??????

  18. Federico Dijo:

    Andreco, es el tag base solamente, no entiendo como se me pasó!

    Y cuenta tanta para las imagenes como para los estilos.

    Si tu url es http://www.sitio.com/index.php, el tag base deberia contener:

    http://www.sitio.com/

    Saludos

  19. andreco Dijo:

    asi lo tengo yop

    RewriteEngine On

    #Si la url solicitada no es un fichero(existente), continuar…
    RewriteCond %{REQUEST_FILENAME} !-f

    #Si la url solicitada no es una carpeta(existente), continuar…
    RewriteCond %{REQUEST_FILENAME} !-d

    RewriteRule ^(.*)$ index.php?route=$1 [L,QSA]

    pero no se , es muy extrano la web no carga la imagende fondo y la capa css, estoy dandole por todo lado y nada que puedo..

  20. Federico Dijo:

    Pasame un link y veo si te puedo ayudar. Si queres usar el formulario de contacto.

    Saludos

  21. Jose Dijo:

    si tienes problemas con las rutas de la imagen o css
    por haber puesto : /images/tuimagen.jpg (ejemplo)

    debes de reemplazarlo por la ruta completa :

    http://tuwebsite.com/images/tuimagen.jpg

    Suerte..

  22. Gustavo Dijo:

    Te felicito es de lo mas claro que he encontrado!
    saludos y gracias

  23. Rolando Dijo:

    Pues comento que el tag base solo sirve para imagenes y links mas no para las imagenes de fondo.

    Saludos,
    Muy buen Post

  24. Rolando Dijo:

    jaja, lo siento, error mio… si funciona….

  25. jokin Dijo:

    Hola, el ejemplo es genial, mi enhorabuena, pero yo tengo la necesidad de implantar esto no solo en el index, tambien en otras paginas aparte de la raiz como por ej. articulo.php?id=xx
    Lo he probado pero no funciona, supongo que será cambiando el script del lado php. Alguna sugerencia? Saludos y gracias de antemano, habeis hecho un buen trabajo.

  26. diseño web Dijo:

    cual seria el codigo en el .htaccess para transformar la url http://www.misitio.com/pagina.php?id=5&seccion=noticias&titulo=lomejor a http://www.misitio.com/pagina/5/lomejor, osea sacar la variable seccion

  27. Diego Morales Dijo:

    Hola soy muy nuevo en esto, eh probado tu script y realmente me he quedado con una duda.

    URL: http://metrics2b.com/diego/seo-htacces/nombre-valor/valor1/1/valor2/2

    mediante el print_r conocemos lo valores como no lo has mostrado quedando lo siguiente como resultado.

    Array
    (
    [valor1] => 1
    [valor2] => 2
    )

    Pero qué debo hacer para ocupar eso valores, por ejemplo en una suma ?? ó imprimir cada uno con un simple echo

  28. CalinSoft Dijo:

    Hola buen post, yo hice uno similar pero con regExp inspirado en WP_rewrite-api la de WordPress http://www.calinsoft.com/2008/08/urls-amigables-basado-en-wp_rewrite-api.html saludos.

Deja tu comentario

XHTML: Puedes usar estos tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

El blog funciona con Wordpress y Simpla theme