2009-12-28 39 views
51

Tengo un sitio web PHP 5.1.0 (en realidad es 5.2.9 pero también debe ejecutarse en 5.1.0+).Cómo usar los encabezados de caché HTTP con PHP

Las páginas se generan dinámicamente, pero muchas de ellas son principalmente estáticas. Por estático me refiero a que el contenido no cambia, pero la "plantilla" alrededor del contenido puede cambiar con el tiempo.

Sé que ya existen varios sistemas de caché y marcos de PHP, pero mi servidor no tiene instalados APC o Memcached y no estoy usando ningún marco para este proyecto en particular.

Quiero que las páginas se guarden en caché (creo que por defecto PHP "no permite" el caché). Hasta el momento estoy usando:

session_cache_limiter('private'); //Aim at 'public' 
session_cache_expire(180); 
header("Content-type: $documentMimeType; charset=$documentCharset"); 
header('Vary: Accept'); 
header("Content-language: $currentLanguage"); 

He leído muchos tutoriales pero no puedo encontrar algo simple (sé caché es algo complejo, pero solo me falta algunas cosas básicas).

¿Cuáles son los encabezados "obligatorios" que se deben enviar para ayudar a almacenar en caché?

Gracias!

+5

Bienvenido a StackOverflow. Gran primera pregunta! – Sampson

Respuesta

40

Es posible que desee utilizar en lugar de private_no_expireprivate, pero establecer una larga caducidad para el contenido que usted sabe que no va a cambiar y asegúrese de procesar y if-modified-sinceif-none-match peticiones similares al post de Emil.

$tsstring = gmdate('D, d M Y H:i:s ', $timestamp) . 'GMT'; 
$etag = $language . $timestamp; 

$if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false; 
$if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? $_SERVER['HTTP_IF_NONE_MATCH'] : false; 
if ((($if_none_match && $if_none_match == $etag) || (!$if_none_match)) && 
    ($if_modified_since && $if_modified_since == $tsstring)) 
{ 
    header('HTTP/1.1 304 Not Modified'); 
    exit(); 
} 
else 
{ 
    header("Last-Modified: $tsstring"); 
    header("ETag: \"{$etag}\""); 
} 

Dónde $etag podría ser una suma de control basado en el contenido o el ID de usuario, el lenguaje y de marca de tiempo, por ejemplo,

$etag = md5($language . $timestamp); 
+2

Lo que has descrito sería una E-Tag Débil y debería tener un prefijo "W /". –

+0

También agregaría el encabezado "Caduca", ya que algunos proveedores de hosting (por ejemplo, los servidores) lo envían de todos modos y lo hacen con la fecha en el pasado, mientras que creo que debería ser en el futuro. – Sasho

+5

Si no obtiene 304s con lo anterior, verifique que no haya comillas parásitas en HTTP_IF_NONE_MATCH. Reemplace '$ if_none_match == $ etag' con' rtrim (ltrim ($ if_none_match, "'\" "),"' \ "") == $ etag' para estar seguro. – ReactiveRaven

7
<?php 
header("Expires: Sat, 26 Jul 2020 05:00:00 GMT"); // Date in the future 
?> 

Establecer una fecha de caducidad para la página en caché es una forma útil de almacenarla en el lado del cliente.

+0

Bueno, y el uso de session_cache_limiter y session_cache_expire ya se ha cuidado de esto. – AlexV

6

¡Haga su elección o úselas todas! :-)

 
header('Expires: Thu, 01-Jan-70 00:00:01 GMT'); 
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); 
header('Cache-Control: no-store, no-cache, must-revalidate'); 
header('Cache-Control: post-check=0, pre-check=0', false); 
header('Pragma: no-cache'); 
+0

session_cache_limiter y session_cache_expire ya controla Expires, Cache-Control, Last-Modified y Pragma ... – AlexV

+0

Veo. Sí, tiene usted razón. Y también veo que no leí tu pregunta lo suficientemente bien. lo siento –

11

usted debe tener un Expira cabecera. Técnicamente, hay otras soluciones, pero el encabezado Expires es realmente el mejor, porque le dice al navegador que no vuelva a revisar la página antes de la fecha y hora de vencimiento, y solo sirve el contenido de la memoria caché. ¡Funciona realmente genial!

También es útil buscar un encabezado If-Modified-Since en la solicitud del navegador. Este encabezado se envía cuando el navegador no está seguro si el contenido en su caché sigue siendo la versión correcta. Si su página no se ha modificado desde ese momento, simplemente envíe de vuelta un código HTTP 304 (No modificado). Aquí hay un ejemplo que envía un código 304 durante diez minutos:

<?php 
if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { 
    if(strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) < time() - 600) { 
    header('HTTP/1.1 304 Not Modified'); 
    exit; 
    } 
} 
?> 

Usted puede poner esta comprobación al comienzo de su código para ahorrar recursos del servidor.

+0

Esto no es bueno si no está usando apache. – Geoffrey

2

que estaba haciendo el almacenamiento en caché en el servidor JSON procedente de alimentación facebook nada estaba trabajando hasta que me puso al ras y escondí el informe de errores. Conozco este código demonio pero quería una solución rápida lo antes posible.

error_reporting(0); 
    $headers = apache_request_headers(); 
    //print_r($headers); 
    $timestamp = time(); 
    $tsstring = gmdate('D, d M Y H:i:s ', $timestamp) . 'GMT'; 
    $etag = md5($timestamp); 
    header("Last-Modified: $tsstring"); 
    header("ETag: \"{$etag}\""); 
    header('Expires: Thu, 01-Jan-70 00:00:01 GMT'); 

    if(isset($headers['If-Modified-Since'])) { 
      //echo 'set modified header'; 
      if(intval(time()) - intval(strtotime($headers['IF-MODIFIED-SINCE'])) < 300) { 
       header('HTTP/1.1 304 Not Modified'); 
       exit(); 
      } 
    } 
    flush(); 
//JSON OP HERE 

funcionaba como encanto.

+1

Puede que no funcione si no establece el nombre de campo $ headers ['If-Modified-Since'] en mayúsculas -> $ encabezados ['IF-MODIFIED-SINCE] –

6

Aquí hay una clase pequeña que hace caché de http para usted. Tiene una función estática llamada 'Init' que necesita 2 parámetros, una marca de tiempo de la fecha en que la página (o cualquier otro archivo solicitado por el navegador) fue modificada por última vez y la edad máxima, en segundos, que esta página se puede guardar en caché por el navegador.

class HttpCache 
{ 
    public static function Init($lastModifiedTimestamp, $maxAge) 
    { 
     if (self::IsModifiedSince($lastModifiedTimestamp)) 
     { 
      self::SetLastModifiedHeader($lastModifiedTimestamp, $maxAge); 
     } 
     else 
     { 
      self::SetNotModifiedHeader($maxAge); 
     } 
    } 

    private static function IsModifiedSince($lastModifiedTimestamp) 
    { 
     $allHeaders = getallheaders(); 

     if (array_key_exists("If-Modified-Since", $allHeaders)) 
     { 
      $gmtSinceDate = $allHeaders["If-Modified-Since"]; 
      $sinceTimestamp = strtotime($gmtSinceDate); 

      // Can the browser get it from the cache? 
      if ($sinceTimestamp != false && $lastModifiedTimestamp <= $sinceTimestamp) 
      { 
       return false; 
      } 
     } 

     return true; 
    } 

    private static function SetNotModifiedHeader($maxAge) 
    { 
     // Set headers 
     header("HTTP/1.1 304 Not Modified", true); 
     header("Cache-Control: public, max-age=$maxAge", true); 
     die(); 
    } 

    private static function SetLastModifiedHeader($lastModifiedTimestamp, $maxAge) 
    { 
     // Fetching the last modified time of the XML file 
     $date = gmdate("D, j M Y H:i:s", $lastModifiedTimestamp)." GMT"; 

     // Set headers 
     header("HTTP/1.1 200 OK", true); 
     header("Cache-Control: public, max-age=$maxAge", true); 
     header("Last-Modified: $date", true); 
    } 
} 
+0

¡¡¡Gracias !! Buen trabajo !! –

Cuestiones relacionadas