Pregunta

En este momento estoy tratando de servir archivos CSS y JS desde un servidor que no me permite habilitar mod_gzip o mod_deflate . Entonces escribí un pequeño script PHP para comprimir con GZIP y devolverlo al usuario.

Código de 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. La primera es que tengo problemas para determinar el tamaño resultante del archivo comprimido para informar al navegador de la longitud del contenido. Normalmente, incluiría esta línea:

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

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

El otro problema es que, cada vez que veo este archivo PHP en Firefox, intenta que descargue el resultado. En Chrome, solo lo muestra como era de esperar. ¿Alguna sugerencia?

Editar: Gracias a SoapBox, reemplacé el 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 el contenido! Pero todavía estoy haciendo que Firefox descargue el archivo en lugar de mostrarlo. :(

Editar de nuevo: Aquí está el código de final de código modificado, cortesía de Cletus.

// Start buffered output
ob_start();
// Check for gzip capability
if (stripos(

En este momento estoy tratando de servir archivos CSS y JS desde un servidor que no me permite habilitar mod_gzip o mod_deflate . Entonces escribí un pequeño script PHP para comprimir con GZIP y devolverlo al usuario.

Código de 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. La primera es que tengo problemas para determinar el tamaño resultante del archivo comprimido para informar al navegador de la longitud del contenido. Normalmente, incluiría esta línea:

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

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

El otro problema es que, cada vez que veo este archivo PHP en Firefox, intenta que descargue el resultado. En Chrome, solo lo muestra como era de esperar. ¿Alguna sugerencia?

Editar: Gracias a SoapBox, reemplacé el 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 el contenido! Pero todavía estoy haciendo que Firefox descargue el archivo en lugar de mostrarlo. :(

Editar de nuevo: Aquí está el código de final de código modificado, cortesía de Cletus.

<*>

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

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 descubrir por qué Firefox sigue intentando descargar el archivo.

¿Fue útil?

Solución

El problema aquí es que para conocer la longitud del contenido, debe saber si el cliente admite o no la codificación gzip y si ha delegado esa decisión utilizando ob_gzhandler. De Encabezados HTTP :

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 asumir el problema de codificación gzip usted mismo.

Otros consejos

Primero debe hacer todo el gzip y medir el resultado (ya sea guardando el contenido en la memoria o escribiéndolos en el disco mientras comprime y luego mostrando el archivo comprimido con gzip), luego escriba el encabezado Content-Length y luego enviar el contenido del archivo.

O use codificación de transferencia fragmentada .

Para resolver su problema de Firefox, creo que debe incluir el encabezado (" Content-Encoding: gzip "); para que el navegador sepa descomprimir el contenido.

En cuanto a la longitud del contenido, puede intentar simplemente dejar este valor desactivado, o tratar de encontrar una manera de usar " Transfer-Encoding: fragmentado " (no puede enviar este encabezado, debe formatear los datos especialmente para él). Es posible que ob_end_flush habilite la fragmentación automáticamente.

Te recomiendo que obtengas Wirehark y captures lo que envía tu script php y lo compares con un servidor que funcione correctamente para ver qué encabezados, etc. faltan.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top