Pergunta

Agora eu estou tentando servir arquivos CSS e JS de um servidor que não me deixa permitir mod_gzip ou mod_deflate. Então eu escrevi um script PHP pequeno a compressa com GZIP e retorno para o usuário.

Exemplo de código:

$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();

Eu estou tendo dois problemas agora. O primeiro é, estou tendo problemas para determinar o tamanho resultante do arquivo compactado para informar o navegador do conteúdo de comprimento. Normalmente, eu iria incluir esta linha:

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

Mas, se o fizer, os trava navegador ao tentar esperar por mais dados. Existe uma maneira de calcular o tamanho total? Ou devo ignorar esta directiva cabeçalho.

A outra questão é, sempre que eu ver este arquivo PHP no Firefox, ele tenta ter me baixar o resultado. No Chrome, apenas a exibe como eu poderia esperar. Alguma sugestão?

Editar: Graças ao SoapBox, eu substituiu o final do código com o seguinte:

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

Isso funciona muito bem para o conteúdo de comprimento! Mas eu ainda estou recebendo Firefox para baixar o arquivo em vez de exibi-lo. : (

Editar Novamente:. Aqui está o código de fim de código modificado, cortesia 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();

Eu vou começar uma nova pergunta para descobrir por que o Firefox continua tentando baixar o arquivo.

Foi útil?

Solução

O problema aqui é que saber o tamanho do conteúdo que você precisa saber se deve ou não os suportes cliente gzip codificação e você delegado essa decisão usando ob_gzhandler. De cabeçalhos 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

versão 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();

Esta é muito melhor do que tomar sobre o gzip codificação problema sozinho.

Outras dicas

Você precisa primeiro fazer todo o gzip e medir o resultado (ou segurando o conteúdo na memória, ou gravá-los no disco como você comprimir e, em seguida, stat'ing o arquivo compactado), em seguida, escrever o cabeçalho Content-Length e depois enviar o conteúdo do arquivo.

Ou uso Chunked codificação de transferência .

Para resolver o problema firefox, eu acho que você precisa incluir header( "Content-Encoding: gzip" ); para que o navegador sabe para descomprimir o conteúdo.

Como para o tamanho do conteúdo, você pode tentar apenas deixar este valor off, ou tentar descobrir uma maneira de usar "Transfer-Encoding: blocos" (você não pode jsut enviar este cabeçalho, você precisa formatar os dados especialmente para ele). É possível que ob_end_flush automaticamente permite chunking.

Eu recomendo que você obter wireshark e captura o que o seu script php está enviando e compará-lo a um servidor corretamente comportar para ver o que cabeçalhos, etc estão faltando.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top