La teoría
Para lograr nuestro objetivo tan solo necesitaremos dos archivos (aunque después siempre se pueden utilizar más, como en todo): .htaccess
y index.php
. El primero, para quien no lo sepa, es, por así decirlo, un archivo de configuración para un directorio. Toda petición pasará por él. Si realizamos una petición al directorio raíz se ejecutará el .htaccess
que se encuentre ahí, mientras que si la petición es a la carpeta /app
, el archivo que se ejecutará será /app/.htaccess
.
Llegados a este punto, si se realiza una petición a una ruta que no exista en el servidor, se ejecutará el .htaccess
del directorio raíz. En nuestro script haremos que este redirija a index.php
, con el que después interpretaremos la URL y mostraremos el contenido deseado.
Paso 1:.htaccess
El contenido del archivo será el siguiente:
RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [QSA,L]
Así todas las URL apuntarán a index.php
.
Paso 2:index.php
Este archivo irá alrededor de la variable $_SERVER['REQUEST_URI']
, la cual contendrá el segmento de la URL actual sin el nombre del servidor. Aquí está el código documentado:
// Dividimos la URL. $requestURI = explode( '/', $_SERVER['REQUEST_URI'] ); // Eliminamos los espacios del principio y final // y recalculamos los índices del vector. $requestURI = array_values( array_filter( $requestURI ) );
Por ejemplo, si tuviesemos /app/page/param1
, $requestURI
nos quedaría de la siguiente manera:
Array ( [0] => app [1] => page [2] => param1 )
Ejemplos prácticos
Tenemos la teoría. Solo falta una cosa: aplicar los datos que hemos obtenido. Esto es algo que cada cual debe adaptar a su manera. De todos modos, yo presento a continuación un par de aplicaciones prácticas que podrían serviros en vuestras webs.
Cargar un controlador
Comenzaremos nuestro index.php
definiendo algunas funciones y alguna constante de configuración.
Nota: la ruta que utilizaremos a partir de ahora será /controller/method/param1/param1/
para que nos sea más fácil comprender el funcionamiento.
/** * Función original de Laravel4. * * Convierte una cadena separada por guiones o barras bajas * a PascalCase. Ej: hola-mundo = HolaMundo */ function studlyCase( $value ) { $value = ucwords( str_replace( array( '-', '_' ), ' ', $value ) ); return str_replace( ' ', '', $value ); } // Configuración. define( 'CONTROLLER_PATH', 'controllers/' ); define( 'EXT', '.php' );
Ahora ya podemos utilizar nuestro código de más arriba para conseguir $requestURI
. Después de eso, comprobaremos si estamos en la página principal con un simple if
.
if ( empty( $requestURI ) ) { // Página principal. echo 'Prueba a escribir <a href="/controller/method/param1/param2"><code>controller/method/param1/param2</code></a> en la URL.'; } else { // Código (sigue leyendo). try { } catch // ... }
En el caso de que sea la página principal ejecutamos lo que queramos. Si no lo es, continuaremos con el código. Lo que haremos será hacer unas cuantas comprobaciones de seguridad ayudándonos de excepciones y cargar el controlador siguiendo un patrón.
Lo siguiente será el código dentro del bloque try
.
// Guardamos el nombre del controlador y la // ruta de su archivo para utilizarlas más tarde. $controllerName = studlyCase( $requestURI[0] ); $controllerPath = CONTROLLER_PATH . $controllerName . EXT; // Guardamos el nombre del método a llamar. $method = $controllerName . '::' . studlyCase( $requestURI[1] ); // Eliminamos el controlador y el método de // $requestURI para quedarnos sólo con los parámetros. $arguments = array_slice( $requestURI, 2 ); // Comprobamos que el archivo del controlador existe. if ( ! file_exists( $controllerPath ) ) { throw new DomainException( 'El archivo <code>' . $controllerPath . '</code> no existe.', 404 ); } // Cargamos el archivo. require_once $controllerPath; // Comprobamos que el archivo contenga el controlador. if ( ! class_exists( $controllerName ) ) { throw new RuntimeException( 'El archivo <code>' . $controllerPath . '</code> debe contener un objeto <code>' . $controllerName . '</code>.' ); } // Comprobamos que el método definido en la URL esté disponible. if ( ! is_callable( $method ) ) { throw new DomainException( 'El archivo <code>' . $controllerPath . '</code> no contiene un método <code>' . $requestURI[1] . '</code>.', 404 ); } // Creamos un nuevo método reflejo de $method. $reflection = new ReflectionMethod( $method ); // Comprobamos que la URL tiene todos los // parámetros requeridos por el método. if ( $reflection->getNumberOfRequiredParameters() > count( $arguments ) ) { throw new DomainException( 'No hay suficientes parámetros como para ejecutar el método <code>' . $method . '</code>', 404 ); } // Llamamos a la función. call_user_func_array( $method, $arguments );
Para finalizar con el archivo, definiremos los bloques catch
.
catch ( RuntimeException $e ) { echo $e->getMessage(); } catch ( DomainException $e ) { echo '<strong>Error ' . $e->getCode() . '</strong>: ' . $e->getMessage(); // O bien escribimos un mensaje de página no encontrada. }
Ahora solo tendremos que crear un controlador para la ruta que deseemos. Para poner un ejemplo, crearemos el archivo controllers/Controller.php
.
<?php class Controller { public static function Method( $param1, $param2 = 'No especificado' ) { echo "Parámetro 1: $param1"; echo '<br>'; echo "Parámetro 2: $param2"; } } ?>
De esta forma podrémos llamar a la URL controller/method/param1
o bien controller/method/param1/param2
ya que el segundo parámetro es opcional. Hay muchas más cosas que se le podrían añadir al código, por ejemplo que al llamar a la URL controller
se busque un método index()
en el controlador al igual que hacen muchos frameworks. Aún así esto es algo que os dejo a vosotros, esto es tan solo un código básico para enseñar el funcionamiento del sistema.
Cargar un controlador “RESTful”
REST es un tipo de arquitectura web por así decirlo, el cual se basa en que cada URL tenga distintos funcionamientos. Si sabéis algo de formularios recordareis que el método de envio puede ser POST, GET, DELETE, PUT… Esto para un formulario simple carece de mucho sentido, pero es de suma importancia a la hora de desarrollar aplicaciones RESTful ya que dependiendo del método de la petición se ejecutará una acción u otra.
Pongamos el ejemplo de una aplicación común para la gestión de noticias:
URL | Acción |
---|---|
/show/$id | Mostrar una noticia. |
/edit/$id | Editar una noticia. |
/delete/$id | Eliminar una noticia. |
/add | Añadir una noticia. |
Ahora bien, si nuestra página estuviese basada en REST, las URLs se comportarían de la siguiente manera:
URL | Método de petición | Acción |
---|---|---|
/news/$id | GET | Mostrar una noticia. |
/news/$id | PUT | Actualizar una noticia. |
/news/$id | DELETE | Eliminar una noticia. |
/news/$id | POST | Añadir una noticia. |
Para adaptar nuestro código anterior no tendremos más que cambiar un par de líneas, de modo que si se llama a method
y la petición es GET, el método del controlador al que accederemos será getMethod()
.
Tan sólo necesitaremos cambiar una variable en index.php
.
$method = $controllerName . '::' . strtolower( $_SERVER['REQUEST_METHOD'] ) . studlyCase( $requestURI[1] );
Y muchas opciones más…
Estos ejemplos que he dado son los más básicos actualmente en aplicaciones web, pero se pueden hacer tantas cosas con las URL como a nuestra imaginación se le ocurra. Como siempre es cosa de investigar.
Espero que este pequeño truquito os haya servido para aumentar vuestros conocimientos. Como siempre no dudéis en comentar, tanto si tenéis dudas como si no, es algo que me hace escribir más tutoriales y motivarme. Un abrazo.