Cedido por guebmasterCOM.
Entre los inconvenientes de las aplicaciones dinámicas que hacen uso extensivo de una base de datos, destaca el incremento del uso de la memoria y CPU del sistema.
Cuando pedimos al servidor web que nos muestre una página estática, una página HTML normal, este nos devuelve su contenido tal cual. En cambio, cuando le pedimos que nos muestre un script de PHP, el servidor llama al motor de PHP el cual se encarga de interpretar el código del script y devolver el resultado de la ejecución de la misma. Obviamente, este segundo proceso de interpretación del código, es mucho más laborioso y por lo tanto consume más recursos del sistema.
Ante este problema, existen varias soluciones como el PHP Accelerator o el Zend Optimizer, que mediante diferentes métodos son capaces de reducir el tiempo de ejecución de los scripts o de incrementar la capacidad del servidor para mostrar páginas dinámicas. La mayorÃa de servidores tiene instalado alguna de estas soluciones, pero esto no significa que nosotros no debamos implementar un método alternativo para reducir el tiempo de ejecución de nuestros programas, asà como reducir el consumo de recursos del sistema. Y de esto precisamente trata este artÃculo, te vamos a mostrar una forma sumamente sencilla de cachear tus scripts de PHP.
El método de cachear scripts que te mostramos a continuación guarda el resultado de la ejecución de un script en un fichero HTML. Posteriormente, cada vez que llamamos a este script, en vez de ejecutarse completamente, nos muestra el fichero guardado previamente, el cual contiene el resultado de la ejecución del propio script.
Este sistema tiene un problema, que el script no muestra el resultado actual, sino el de cuando el resultado se guardo por ultima vez. Supongamos que nuestro script muestra una lista de usuarios, esta lista se obtiene de base de datos. Si añadiésemos 5 nuevos usuarios a la base de datos, el script no mostrarÃa estos 5 nuevos registros hasta que le indicáramos que volviera a ejecutarse completamente y a guardar el resultado de su ejecución en el fichero HTML. Este problema, se puede solucionar estableciendo un tiempo de caducidad al fichero HTML que sirve de caché.
Script original
Una vez explicado el funcionamiento del sistema pasemos a ver su implementación. Supongamos que tenemos un script, al cual llamaremos "mostrar.php", cuyo código podemos ver a continuación:
<html> <head> <title>Mi script</title> </head> <body> <?php include('conexion.php'); $get = mysql_query('select * from mitabla where id=''.$_GET['id'].''',$db); while($row = mysql_fetch_row($get)) { echo $row[0].' => '.$row[1].'<br>'; } ?> </body> </html>
Nuestro script simplemente hace una llamada a una base de datos MySQL del cual obtiene ciertos datos dependiendo del valor de la variable id que le pasemos mediante el método GET, es decir, desde la dirección o URL. Por ejemplo, un petición válida a nuestro script podrÃa ser:
http://dominio.com/mostrar.php?id=444
Si llamamos a nuestro script con esa dirección, le estamos pidiendo que muestre todos los registros de la tabla mitabla que tengan un valor de 444 en su campo id. El valor de la variable id, la obtendremos de $_GET['id'].
Funciones de caché
Con el objetivo de cachear el resultado del script debemos incluir en él, un script que llamaremos "cache.php" y cuyo código podemos ver a continuación:
<?php // tiempo tras el cual se "caducan" los fichero HTML $TIEMPO = 86400; // directorio donde guardar los ficheros HTML o cachés $DIR = '/home/midirectorio/cache/mostrar'; function cache_abrir() { global $TIEMPO,$DIR; // comprobar la existencia del fichero cache y si aun es valido if(file_exists($DIR.'/'.$_GET['id'].'.html') && time()-filemtime($DIR.'/'.$_GET['id'].'.html')<$TIEMPO) { // mostrar cache include($DIR.'/'.$_GET['id'].'.html'); // terminar ejecución del script exit(); } } function cache_guardar($html) { // abrir en modo escritura el fichero cache $file = @fopen($DIR.'/'.$_GET['id'].'.html','w'); // escribir el contenido de $html en el fichero cache @fwrite($file,$html); // cerrar fichero @fclose($file); } ?>
El script "cache.php" consta de dos funciones: cache_abrir() se encarga primero de comprobar la existencia del fichero HTML o caché, si existe y no esta caducado muestra su contenido y termina la ejecución del script. cache_guardar() se encarga de guardar el resultado de la ejecución completa del script. Esta última función, solo se ejecutará cuando el caché no exista o halla expirado. El valor de caducidad o expiración de los ficheros caché lo define la variable $TIEMPO. La variable $DIR define el directorio donde se guardaran todos los ficheros caché que nuestro script "mostrar.php" creara dependiendo de la petición que se le haga, es decir, dependiendo del valor de la variable id.
Modificaciones del script original
A continuación te mostramos como quedara nuestro script "mostrar.php" una vez modificado para cachearse a si mismo:
<html> <head> <title>Mi script</title> </head> <body> <?php include('conexion.php'); include('cache.php'); // si existe y no ha caducado mostrar el cache y terminar ejecución del // script en este punto cache_abrir(); // en vez de imprimir el resultado, lo conserva en la variable $html $get = mysql_query('select * from mitabla where id=''.$_GET['id'].''',$db); while($row = mysql_fetch_row($get)) { $html .= $row[0].' => '.$row[1].'<br>'; } // como no existÃa el cache o habÃa expirado guardamos el resultado // de la ejecución del script cache_guardar($html); // imprimir $html, el cual contiene el resultado de la ejecución del script echo $html; ?> </body> </html>
Tras la modificación, nuestro script ya no imprime directamente su resultado, lo tenemos que guardar en la variable $html, para que de esa forma la función cache_guardar() tenga algo que guardar, el contenido con el cual crear el fichero caché.
Es posible que te parezca que el modificar tus scripts para guardar su resultado en la variable $html en vez de imprimirlo directamente suponga demasiado trabajo. Si es asÃ, a continuación te mostramos otra forma de obtener en la variable $html el resultado de la ejecución del script:
<html> <head> <title>Mi script</title> </head> <body> <?php include('conexion.php'); include('cache.php'); // si existe y no ha caducado mostrar el cache y terminar ejecución del // script en este punto cache_abrir(); // LÃnea 1 -> A partir de aquà no se devuelve nada, todo se escribe al // buffer interno ob_start(); // en vez de imprimir el resultado, conservarlo en la variable $html $get = mysql_query('select * from mitabla where id=''.$_GET['id'].''',$db); while($row = mysql_fetch_row($get)) { echo $row[0].' => '.$row[1].'<br>'; } // LÃnea 2 -> Obtiene el contenido del buffer $html = ob_get_contents(); // LÃnea 3 -> Limpiar el buffer ob_end_clean(); // como no existÃa el cache o habÃa expirado guardamos el resultado de // la ejecución del script cache_guardar($html); // imprimir $html, el cual contiene el resultado de la ejecución del script echo $html; ?> </body> </html>
Con este nuevo método, en vez de reemplazar todos los "echo" por un "$html .=", simplemente debes agregar 3 lÃneas de código. La primera lÃnea de be ir justo después de la llamada a la función cache_abrir(), mientras que las otras dos lÃneas justo antes de la llamada a la función cache_guardar(). Estas 3 lÃneas, también podrÃas incluirlas en la funciones cache_abrir() y cache_guardar(), de esta forma los cambios que tendrás que hacer a tus scripts serán aún menores. Si asà lo prefieres, el script cache.php quedarÃa de la siguiente forma:
<?php // tiempo tras el cual se "caducan" los fichero HTML $TIEMPO = 86400; // directorio donde guardar los ficheros HTML o cachés $DIR = '/home/midirectorio/cache/mostrar'; function cache_abrir() { global $TIEMPO,$DIR; // comprobar la existencia del fichero cache y si aun es valido if(file_exists($DIR.'/'.$_GET['id'].'.html') && time()-filemtime($DIR.'/'.$_GET['id'].'.html')<$TIEMPO) { // mostrar cache include($DIR.'/'.$_GET['id'].'.html'); // terminar ejecución del script exit(); } // A partir de aquà no se devuelve nada, todo se escribe al buffer interno ob_start(); } function cache_guardar() { global $html; // Obtiene el contenido del buffer $html = ob_get_contents(); // Limpiar el buffer ob_end_clean(); // abrir en modo escritura el fichero cache $file = @fopen($DIR.'/'.$_GET['id'].'.html','w'); // escribir el contenido de $html en el fichero cache @fwrite($file,$html); // cerrar fichero @fclose($file); } ?>
Mientras que mostrar.php quedarÃa asÃ:
<html> <head> <title>Mi script</title> </head> <body> <?php include('conexion.php'); include('cache.php'); // si existe y no ha caducado mostrar el cache y terminar ejecución del // script en este punto cache_abrir(); // en vez de imprimir el resultado, conservarlo en la variable $html $get = mysql_query('select * from mitabla where id=''.$_GET['id'].''',$db); while($row = mysql_fetch_row($get)) { echo $row[0].' => '.$row[1].'<br>'; } // como no existÃa el cache o habÃa expirado guardamos el resultado de // la ejecución del script cache_guardar(); // imprimir $html, el cual contiene el resultado de la ejecución del script echo $html; ?> </body> </html>
Esta última forma es posiblemente la mejor, pero personalmente prefiero el primer método. Sobre todo porque esa es mi forma de programar, pero también porque las funciones de "Output Control Functions" (lo siento, no he encontrado una mejor traducción) limitan de cierta forma la libertad a la hora de programar.
Es preciso añadir que puedes variar la posición de las llamadas a las funciones cache_abrir() y cache_guardar(), asà como la inclusión del script "cache.php". Depende de que partes del script quieras cachear, como en el siguiente ejemplo podrÃas cachear todo el script y posiblemente mejorar el rendimiento del script:
<?php include('cache.php'); // si existe y no ha caducado mostrar el cache y terminar ejecución del // script en este punto cache_abrir(); ?> <html> <head> <title>Mi script</title> </head> <body> <?php include('conexion.php'); // en vez de imprimir el resultado, conservarlo en la variable $html $get = mysql_query('select * from mitabla where id=''.$_GET['id'].''',$db); while($row = mysql_fetch_row($get)) { echo $row[0].' => '.$row[1].'<br>'; } ?> </body> </html> <?php // como no existÃa el cache o habÃa expirado guardamos el resultado de // la ejecución del script cache_guardar(); // imprimir $html, el cual contiene el resultado de la ejecución del script echo $html; ?>
Bueno, ahora mi consejo es que empieces probando con el ejemplo de este artÃculo y una vez hallas entendido como funciona, modificar las funciones cache_abrir() y cache_guardar() para ajustarlos mejor a tus aplicaciones.