Cacheando tus scripts para máxima optimización

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.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR

SIGUIENTE ARTÍCULO