Cachear de forma sencilla una página dinámica en PHP

¿Te ha pasado alguna vez que tienes una web desde hace un montón de años, que la hiciste tú y a veces te da problemas de saturación por exceso de visitas? Pues a mi sí y, aunque llevaba tiempo pensando en alguna forma de cachear, que acababa siendo hipercompleja, hoy me ha dado por pensar alguna forma sencilla basándome en unas pruebas que había hecho hacía poco.

La cuestión es que sabía cómo hacerlo, iba por el camino, pero entre unas cosas y otras “nunca encontraba el momento”, hasta ahora. El sistema es bastante simple y en principio se podría aplicar a cualquier sitio. El código sería algo tal que este:

<?php
$md5 = md5($_SERVER["REQUEST_URI"]); // convertimos la URL a único identificador
$file = "cache/".$md5.".html"; // donde se guardará el fichero
$hora = filemtime($file); // comprobamos la hora del fichero si ya existiera
if(time() <= $hora+86400) { // asignamos un tiempo de cache de 86400 segundos
    include($file); // incluimos el contenido del fichero cacheado
    echo "<!-- ".date('YmdHis', $hora)." -->"; // (opcional) añadimos al pie de página la fecha-hora de la caché
    exit; // salimos
}
ob_start(); // abrimos la memoria
?>
AQUI VA LA WEB NORMAL
<?php
$fp = fopen($file, 'w+'); // abrimos el fichero de caché
fwrite($fp, ob_get_contents()); // guardamos el contenido de la página generada en el fichero
fclose($fp); // cerramos el fichero
ob_end_flush(); // devolvemos la página que se ha generado y cerramos la memoria
?>

Con este sistema podremos incrementar una página dinámica tranquilamente entre un 50% y un 1.000% la velocidad, dependiendo de la carga de base de datos o cálculo que tuviera anteriormente.

10 comentarios en “Cachear de forma sencilla una página dinámica en PHP”

  1. Hola Javier, te felicito por tu libro de WPO que me he leído recientemente y es muy interesante.

    Respecto a este artículo me gustaría añadir un detalle que hará que aumente el rendimiento en número de peticiones por segundo (es lo que implementa el WP-SuperCache): si en vez de guardar el fichero cacheado en md5(request_uri) usas directamente request_uri los ficheros de caché se almacenan en disco duro de la misma manera que los nombres de las URLs existen en la web, de esta manera usando mod_rewrite en Apache (o en otros servidores web como Nginx) puedes hacer que si existe el fichero se sirva directamente desde disco, sin necesidad de cargar el intérprete PHP.

    Saludos

  2. Muchísimas gracias por compartirlo Javier, sin duda que me va a ser muy útil este código. Un saludo.

  3. Hola Daniel!

    Sí, por supuesto, crear un fichero “real” con la estructura del sitio es lo mejor, pero si tienes un blog que se actualiza mucho o con muchos comentarios se vuelve bastante ingestionable en el momento en el que crece…

    De todas formas, este código tampoco está tan enfocado a páginas en WordPress sino a páginas que son dinámicas y no tienen ningún tipo de caché, ni memcached, nginx, varnish, etc…

  4. En vez del include($file), es mejor usar readfile($file).
    El include intenta interpretar el php que hubiera en el fichero (en este caso es todo html, así que se pierde tiempo), el readfile escribe directamente el fichero en el buffer de salida.

  5. Hola Javi, gracias por la respuesta.
    Lo de la zona de users es las páginas con log/pass, no?
    Para una web de recetas que actualiza contenido de 10 a 20 post al día ¿crees que mejorará?
    Tiene sobre unas 2000 visitas al día y casi 500.000 page indexadas en google, Es la del link de mi nombre.

  6. Muy bueno el código, lo que puede hacer cada uno que lo ve es probarlo en un servidor en su pc (Wamp por ej) y hacerle un bucle de miles de veces e ir retocando algunas cosas con el fin que sea lo mas rápido posible (a veces cosas pequeñas hacen que todo vaya mas rápido). En este caso yo probaría poner todo dentro de un if en vez de hacerlo separado, habría que probar la velocidad como para ver si vale la pena.
    Ahora bien, si la página es entregada al cliente de acuerdo al navegador me parece que esto fallaría no?. Slds!

Deja un comentario