2009-05-03 3 views
13

Im Moment versuche ich CSS und JS-Dateien von einem Server, der mich nicht aktivieren mod_gzip oder mod_deflate ermöglichen. Also habe ich ein kleines PHP-Skript geschrieben, um es mit GZIP zu komprimieren und zum Benutzer zurückzukehren.Wie ermittle ich die Inhaltslänge einer gezippten Datei?

Beispielcode:

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

Ich habe zwei jetzt Probleme. Der erste ist, ich habe Probleme, die resultierende Größe der komprimierten Datei zu bestimmen, um den Browser über die Länge des Inhalts zu informieren. Normalerweise würde ich diese Zeile enthält:

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

Aber, wenn ich es tue, hängt der Browser während auf weitere Daten warten zu versuchen. Gibt es eine Möglichkeit, die Gesamtgröße zu berechnen? Oder sollte ich diese Header-Direktive ignorieren?

Das andere Problem ist, wenn ich diese PHP-Datei in Firefox anzeigen, versucht es, dass ich das Ergebnis herunterladen. In Chrome wird es nur so angezeigt, wie ich es erwartet hätte. Irgendwelche Vorschläge?

Edit: Dank SoapBox, ich ersetzt das Ende des Codes mit diesem:

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

Dies funktioniert gut für den Inhalt Länge! Aber ich bekomme immer noch Firefox, um die Datei herunterzuladen anstatt sie anzuzeigen. :(

Erneut bearbeiten: Hier ist der modifizierte End-of-Code-Code, mit freundlicher Genehmigung von 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(); 

ich eine neue Frage beginnen werde, um herauszufinden, warum hält Firefox zu versuchen. Laden Sie die Datei herunter

+0

Einige der Header in den Antworten erwähnt haben ein paar Fehler; Der Doppel-Cache-Control, der mit Cache-Control läuft: Läuft ab .... sollte abgelaufen sein ... ... und Etag sollte ETag sein. –

Antwort

18

Das Problem hier ist, dass Sie wissen müssen, ob der Client die GZIP-Codierung unterstützt, oder nicht, und Sie haben diese Entscheidung mithilfe von ob_gzhandler delegiert.Von 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 

Vollversion:

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

Dies ist viel besser als sich auf der gzip-Codierung Problem nehmen.

1

Sie müssen zuerst das gesamte gzip machen und das Ergebnis messen (entweder den Inhalt im Speicher halten oder sie auf die Festplatte schreiben, während Sie die gezippte Datei komprimieren und dann setzen) -Length Header und dann senden Sie den Dateiinhalt

Oder verwenden Sie chunked transfer encoding.

+0

Die Funktion 'file_put_contents' sollte funktionieren. – hyip

1

Um Ihr Firefox-Problem zu lösen, müssen Sie header("Content-Encoding: gzip"); mit einschließen, damit der Browser den Inhalt entpacken kann.

Wie für die Länge des Inhalts, können Sie versuchen, lassen Sie einfach diesen Wert aus, oder versuchen Sie eine Möglichkeit zu finden "Transfer-Encoding: Chunked" (Sie können nicht nur diese Header senden, müssen Sie die Daten speziell dafür). Es ist möglich, dass ob_end_flush automatisch Chunking aktiviert.

Ich empfehle Ihnen, wireshark und erfassen, was Ihr PHP-Skript sendet und vergleichen Sie es mit einem einwandfrei benehmen Server, um zu sehen, welche Header usw. fehlen.

+0

Das ist eigentlich was ob_start ("ob_gzhandler") tut, wenn der Client es unterstützt. – cletus