2009-05-03 25 views
13

En este momento estoy tratando de servir a los archivos CSS y JS de un servidor que no me deja activo el mod_gzip o mod_deflate. Así que escribí un pequeño script PHP para comprimir con GZIP y devolverlo al usuario.Cómo determinar la longitud del contenido de un archivo descomprimido?

Código Ejemplo:

$filename = "style.css"; 

if (!file_exists($filename) || !($info = stat($filename))) { 
    header("HTTP/1.1 404 Not Found"); 
    die(); 
} 

header("Date: ".gmdate("D, j M Y H:i:s e", time())); 
header("Cache-Control: max-age=2592000"); 
header("Last-Modified: ".gmdate("D, j M Y H:i:s e", $info['mtime'])); 
header("Etag: ".sprintf("\"%x-%x-%x\"", $info['ino'], $info['size'], $info['mtime'])); 
header("Accept-Ranges: bytes"); 
header("Cache-Control: Expires ".gmdate("D, j M Y H:i:s e", $info['mtime']+2592000)); 
header("Content-Type: text/html"); 

ob_start("ob_gzhandler"); 
echo file_get_contents($filename); 
ob_end_flush(); 

estoy teniendo dos problemas en este momento. El primero es que tengo problemas para determinar el tamaño resultante del archivo comprimido para informar al navegador de la longitud del contenido. Normalmente, me gustaría incluir esta línea:

header("Content-Length: ".$info["size"]); 

Pero, si lo hago, el navegador se cuelga al tratar de esperar para más datos. ¿Hay alguna manera de calcular el tamaño total? O debería ignorar esta directiva de encabezado.

La otra cuestión es, cada vez que veo este archivo PHP en Firefox, se trata de tener me descarga el resultado. En Chrome, simplemente lo muestra como era de esperar. ¿Alguna sugerencia?

Editar: Gracias a SoapBox, que sustituyó a la final del código con esto:

header("Content-Encoding: gzip"); 
$compressed = gzencode(file_get_contents($filename), 5); 
header("Content-Length: ".strlen($compressed)); 
die($compressed); 

Esto funciona muy bien para la longitud de contenido! Pero sigo pidiendo a Firefox que descargue el archivo en lugar de mostrarlo. :(

Editar Una vez más: Aquí está el código modificado de fin de código, cortesía de Cletus

// Start buffered output 
ob_start(); 
// Check for gzip capability 
if (stripos($_SERVER['HTTP_ACCEPT_ENCODING'], "gzip") !== false) { 
    ob_start("ob_gzhandler"); 
    echo file_get_contents($filename); 
    ob_end_flush(); 
} else 
    echo file_get_contents($filename); 

// Write the content length 
header('Content-Length: '.ob_get_length()); 
ob_end_flush(); 

Voy a comenzar una nueva pregunta para averiguar por qué Firefox sigue intentando. descargue el archivo

+0

Algunos de los encabezados mencionados en las respuestas tienen algunos errores; El doble Cache-Control, la línea con Cache-Control: expira .... debe ser Expira: ... Y Etag debe ser ETag. –

Respuesta

18

El problema aquí es que para conocer la longitud de contenido que necesita saber si el cliente es compatible con la codificación gzip y usted ha delegado dicha decisión mediante el uso de ob_gzhandler.De HTTP Headers:

ob_start(); 
ob_start('ob_gzhandler'); 

    ... output the page content... 

ob_end_flush(); // The ob_gzhandler one 

header('Content-Length: '.ob_get_length()); 

ob_end_flush(); // The main one 

versión completa:

$filename = "style.css"; 

if (!file_exists($filename) || !($info = stat($filename))) { 
    header("HTTP/1.1 404 Not Found"); 
    die(); 
} 

header("Date: ".gmdate("D, j M Y H:i:s e", time())); 
header("Cache-Control: max-age=2592000"); 
header("Last-Modified: ".gmdate("D, j M Y H:i:s e", $info['mtime'])); 
header("ETag: ".sprintf("\"%x-%x-%x\"", $info['ino'], $info['size'], $info['mtime'])); 
header("Accept-Ranges: bytes"); 
header("Expires: ".gmdate("D, j M Y H:i:s e", $info['mtime']+2592000)); 
header("Content-Type: text/css"); // note: this was text/html for some reason? 

ob_start(); 
ob_start("ob_gzhandler"); 
echo file_get_contents($filename); 
ob_end_flush(); 
header('Content-Length: '.ob_get_length()); 
ob_end_flush(); 

Esto es mucho mejor que tomar en la codificación gzip problema por sí mismo.

1

Primero necesita hacer todo el gzip y medir el resultado (ya sea manteniendo el contenido en la memoria, o escribiéndolo en el disco mientras comprime y luego coloca el archivo comprimido), luego escriba el Contenido -Length encabezado y luego enviar el contenido del archivo

O use chunked transfer encoding.

+0

La función 'file_put_contents' debería funcionar en él. – hyip

1

para resolver su problema de Firefox, creo que es necesario incluir header("Content-Encoding: gzip"); para que el navegador sabe para descomprimir el contenido.

En cuanto a la longitud del contenido, puede intentar simplemente dejar este valor fuera de servicio, o tratar de encontrar la manera de usar "Transferir-Codificar: fragmentado" (no puede enviar este encabezado, necesita formatear el datos especialmente para ello). Es posible que ob_end_flush active automáticamente la fragmentación.

que recomendamos obtener una Wireshark y capturar lo que el script php es el envío y compararlo con un servidor adecuadamente comportarse para ver qué cabeceras, etc están desaparecidos.

+0

En realidad, eso es lo que hace ob_start ("ob_gzhandler") si el cliente lo admite. – cletus

Cuestiones relacionadas