domingo, 10 de junio de 2012

Manipulación de parámetros GET con PHP en la URL


Lamento muchísimo haber dejado mi blog por más de un año.
La vergüenza me agobia así que no seguiré más con este asunto. Directo al grano.

Es increíble que nadie se haya chocado con esta necesidad. Seguro que muchos se valen de frameworks que hacen lo que explicaré ahora en pocas líneas de código PHP

Muchas veces necesitamos pasar parámetros en la URL. Esto es importante cuando el objetivo es mantener en la URL ciertos parámetros de personalización en nuestra web. Así, para el usuario, es muy funcional copiar y pegar un link en donde estén todas las opciones personalizadas que él ha seleccionado durante su visita en una web.

¿No me dejé entender? Así hablo yo, súper confuso. Mejor con un ejemplo.

Un visitante entra a un catálogo virtual. La empresa por defecto muestra su portal en inglés (aunque la mejor opción sería detectar automáticamente el idioma). El usuario luego selecciona la opción "Ver en español". Allí podría ser necesario utilizar un parámetro en la URL que sea por ejemplo lang. Luego el usuario entra a determinada categoría y se muestra una lista con los productos. Obviamente esta lista tiene una paginación. Pero además, el usuario decide ordenar de forma ascendente por precio y filtrar los productos que cuesten más de $100 dólares por ejemplo.

¿Para qué tendríamos que colocar todas estas personalizaciones en nuestra URL? Imagínense que el visitante desea enviar el resultado de su búsqueda a un amigo: "Hey, mira, estas son las camisas que te recomiendo comprar". El amigo ya no tendrá que nuevamente elegir el idioma, seleccionar la categoría, ir a la página ni ordenar ascendentemente por precio. Todas estas personalizaciones deberían estar en la URL.

Nuestra URL debería quedar de la siguiente manera:

server/Camisas-Hawaianas/?lang=es&pag=5&orderBy=precio&order=asc

¿Notaron que la categoría no está como un parámetro GET? Sería un error poner algo como cat=74 ya que perderíamos una oportunidad de SEO. Sin embargo, la paginación y el idioma no nos ayudan como URLs amigables y éstas sí pueden estar como parámetros GET.

Estamos en el escenario en el que no estamos utilizando ningún framework y estamos construyendo nuestro HTML manualmente. ¿Cómo podríamos imprimir en HTML una paginación con links que cambien el parámetro pag pero que dejen intactos los otros parámetros?

Tenemos que parsear la cadena de la URL. En uno de mis trabajos hice esto, espero que les sirva:


public static function addParameterURL($parName, $value, &$urlLink)  {
if (strchr($urlLink,"?")) {
if (strstr($urlLink,$parName)) {
$from = strpos($urlLink,$parName)+strlen($parName)+1;
$to = strpos($urlLink,"&",$from);
if (!$to) {
$urlLink = substr_replace($urlLink,$value,$from);
} else {
$urlLink = substr_replace($urlLink,$value,$from,$to-$from);
}
} else {
$urlLink .= "&".$parName."=".$value;
}
} else {
$urlLink .= "?".$parName."=".$value;
}
}



Lo que hace la función es reemplazar en la cadena $urlLink (que está como referencia) el valor $value correspondiente al parámetro con nombre $parName. Si el parámetro no existe en la cadena, lo agrega al final. Y si la cadena no contiene ningún parámetro GET, agrega este parámetro como si fuera el primero. A continuación, 3 ejemplos de qué es lo que devolvería la función.

Ejemplo 1: El parámetro se encuentra presente en cualquier parte de la cadena.


Si la entrada es:
$parName = date , $value = 1-3-2012 , $urlLink = ?pag=1&date=4-5-2011&option=ACTION

La función devuelve
$urlLink = ?pag=1&date=1-3-2012&option=ACTION


Ejemplo 2: El parámetro no se encuentra presente, se agrega al final de la cadena


Si la entrada es:
$parName = date , $value = 1-3-2012 , $urlLink = ?pag=1&option=ACTION

La función devuelve
$urlLink = ?pag=1&option=ACTION&date=1-3-2012


Ejemplo 3: La cadena no contiene ningún parámetro. Entonces se agrega el parámetro como el primero.


Si la entrada es:
$parName = date , $value = 1-3-2012 , $urlLink = 

La función devuelve
$urlLink = ?date=1-3-2012

Esta es una función general. Veamos ahora cómo es que yo la utilizo para hacer mi paginación como ejemplo. Lo primero, para crear un widget de paginación, como todos sabemos, es hallar el total de registros, el número de página y la cantidad de registros por página.


$totalPag = ceil($total/$perPage);

addParameterURL("pag","###",$urlLink);

for ($i = 1; $i<=$totalPag; $i++) {
?><a href="<?=str_replace("###",$i,$urlLink)?>"><?=$i?></a>
<?
}



Lo primero que hacemos es hallar el total de páginas. Luego, en la segunda línea, vemos que estoy manipulando la cadena $urlLink para que, en el parámetro pag, reemplace el valor por "###".
Esto lo hago porque, luego en la iteración que continúa, reemplazaré esa "aguja" (la cadena "###") por el iterador $i que es el número de página. Y así tengo todos mis links, uno para cada página, con el valor del parámetro pag que le corresponde y sin alterar los demás parámetros.

Yo no he encontrado mejor manera, y estoy seguro de que muchos frameworks utilizan un parseo similar. Si alguien conoce alguna manera más eficiente de hacerlo, estaré encantado de recibir sugerencias.