2009-05-03 5 views
13

지금은 mod_gzip 또는 mod_deflate을 사용 가능하게하지 않는 서버에서 CSS 및 JS 파일을 제공하려고합니다. 그래서 저는 GZIP로 압축하고 사용자에게 돌아가는 작은 PHP 스크립트를 작성했습니다.gzipped 파일의 Content-Length를 결정하는 방법은 무엇입니까?

예제 코드 : 내가 지금이 문제가 발생

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

. 첫 번째는 브라우저에 content-length를 알리기 위해 압축 된 파일의 크기를 결정하는 데 문제가 있습니다. 내가 할 경우 더 많은 데이터를 기다리는 동안, 브라우저가 응답,

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

하지만 : 일반적으로,이 라인을 포함한다. 총 크기를 계산하는 방법이 있습니까? 아니면이 헤더 지시어를 무시해야합니까?

다른 문제는 Firefox에서이 PHP 파일을 볼 때마다 결과를 다운로드하도록 시도한다는 것입니다. 크롬에서는 예상대로 표시합니다. 어떤 제안?

편집 :

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

이는 내용 길이 위대한 작품 : 비누 상자에 덕분에, 나는이와 코드의 끝을 교체! 하지만 여전히 파일을 다운로드하는 대신 Firefox에서 파일을 다운로드하도록하고 있습니다. :(다시

편집 : 여기 수정 된 최종의 코드 코드, 클리 터스의 예의입니다 나는 파이어 폭스하려고 계속 이유를 알아 내기 위해 새로운 질문을 시작하겠습니다

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

.

+0

답변에 언급 된 헤더 중 몇 가지 오류가 있습니다. 이중 Cache-Control, Cache-Control : Expires ...와 같은 줄은 Expires : ...이어야하며 ETag는 ETag 여야합니다. –

답변

18

여기에서 문제는 컨텐츠 길이를 알기 위해서는 클라이언트가 gzip 인코딩을 지원하는지 여부와 ob_gzhandler를 사용하여 해당 결정을 위임했는지 여부를 알아야한다는 것입니다.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 

전체 버전 :

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

이는 GZIP 인코딩 문제를 스스로 복용보다는 훨씬 낫다.

1

먼저 gzip 전체를 수행하고 결과를 측정해야합니다 (압축하여 gzip 파일을 stat'ing 한 후 내용을 메모리에 저장하거나 내용을 기록해야합니다). 그런 다음 내용을 작성하십시오 -Length 헤더를 입력하고 파일 내용을 보냅니다.

또는 chunked transfer encoding을 사용하십시오.

+0

함수'file_put_contents'가 작동해야합니다. – hyip

1

파이어 폭스 문제를 해결하려면 브라우저가 콘텐츠의 압축을 풀 수 있도록 header("Content-Encoding: gzip");을 포함시켜야한다고 생각합니다.

콘텐츠 길이는이 값을 그대로 두거나 "Transfer-Encoding : chunked"(이 헤더를 전송할 수 없습니다. 형식을 지정해야합니다. 특별히 그것을위한 데이터). ob_end_flush은 청크를 자동으로 활성화 할 수 있습니다.

wireshark를 받고 PHP 스크립트가 보내는 것을 캡쳐하고 올바르게 작동하는 서버와 비교하여 누락 된 헤더 등을 확인하는 것이 좋습니다.

+0

실제로 클라이언트가 지원하는 경우 ob_start ("ob_gzhandler")가 수행하는 작업입니다. – cletus

관련 문제