2008-09-07 10 views
8

Ich habe ein paar Websites auf einem freigegebenen Host, der Apache 2 ausgeführt wird. Ich möchte die HTML, CSS und Javascript komprimieren, die an den Browser geliefert wird. Der Host hat mod_deflate und mod_gzip deaktiviert, daher sind diese Optionen nicht verfügbar. Ich habe jedoch PHP 5 zur Verfügung, also könnte ich die gzip-Komponente davon verwenden.Beste Möglichkeit, HTML, CSS & JS mit mod_deflate und mod_gzip zu komprimieren

mir derzeit Platzierung folgend in meiner .htaccess-Datei:

php_value output_handler ob_gzhandler

Dies ist jedoch nur die HTML komprimiert und die CSS und JS auslässt.

Gibt es eine zuverlässige Möglichkeit, die Ausgabe von CSS und JS transparent zu komprimieren, ohne jede Seite ändern zu müssen? Ich habe Google durchsucht und eine Reihe von Lösungen vorgestellt, aber ich muss noch einen zur Arbeit bringen. Wenn jemand eine Lösung vorschlagen könnte, von der er weiß, dass sie funktioniert, würde das sehr dankbar sein.

Hinweis, Methode 2 in The Definitive Post on Gzipping your CSS sieht aus wie eine gute Lösung, aber ich konnte es nicht funktioniert bekommen. Hat jemand anderes diese Methode erfolgreich angewendet?

+0

nur neugierig - warum hat das Host-Unternehmen mod_deflate und mod_gzip deaktiviert ?! Es ist eigentlich ihr Interesse, sie eingeschaltet zu haben! – scunliffe

Antwort

1

Sie können Ihr Glück mit mod_rewrite versuchen.

Erstellen Sie ein Skript, das einen lokalen statischen Dateinamen als Eingabe über z. $_SERVER['QUERY_STRING'] und gibt es in komprimierter Form aus. Viele Provider erlauben es nicht, mod_rewrite mit .htaccess Dateien zu konfigurieren oder es vollständig deaktiviert zu haben.

Wenn Sie zuvor nicht umgeschrieben haben, empfehle ich eine gute Anleitung für Anfänger, wie wahrscheinlich this one. Auf diese Weise können Sie den Apache veranlassen, alle Anfragen für eine statische Datei an ein PHP-Skript umzuleiten. style.css wird zum Beispiel zu compress.php? style.css umgeleitet.

Wie immer extrem vorsichtig auf die Eingabe, die Sie akzeptieren, oder Sie haben eine XSS Exploit auf Ihre Hände!

+0

@macbirdie, vielen Dank für diesen Vorschlag. Können Sie Beispiele für diesen Ansatz bereitstellen oder auf diese verweisen? Ich wäre auch daran interessiert, einige allgemeine Techniken zur Sicherung eines solchen Skripts zu hören. –

4

Was ich mache:

  • Ich stelle Skripte in einem js und Stylesheets in einem css dir sind.
  • In der Apache-Konfiguration, ich hinzufügen Richtlinien wie folgt:

    <Directory /data/www/path/to/some/site/js/> 
        AddHandler application/x-httpd-php .js 
        php_value auto_prepend_file gzip-js.php 
        php_flag zlib.output_compression On 
    </Directory> 
    <Directory /data/www/path/to/some/site/css/> 
        AddHandler application/x-httpd-php .css 
        php_value auto_prepend_file gzip-css.php 
        php_flag zlib.output_compression On 
    </Directory> 
    
  • gzip-js.php im js Verzeichnis sieht wie folgt aus:

    <?php 
        header("Content-type: text/javascript; charset: UTF-8"); 
    ?> 
    
  • ... und gzip-cs.php im css Verzeichnis sieht wie folgt aus:

    <?php 
        header("Content-type: text/css; charset: UTF-8"); 
    ?> 
    

Dies ist vielleicht nicht die eleganteste Lösung, aber es ist ganz sicher ein einfaches, dass einige Änderungen erforderlich und funktioniert gut.

+0

Ich habe das gerade probiert und ich konnte es leider nicht zum laufen bringen. Wenn ich die Anweisungen wie vorgeschlagen hinzufüge, erhalte ich einen internen Serverfehler. –

1

, was immer Sie tun, seien Sie vorsichtig über Caching auf der Client-Seite:

Browser tut alle Arten von Tricks, um zu versuchen, die Bandbreite zu minimieren und es gibt viele Möglichkeiten, in dem HTTP-Protokoll, das zu tun, von denen alle werden von Apache behandelt - wenn Sie nur eine lokale Datei bedienen.

Wenn Sie nicht sind, dann es ist Ihre Verantwortung.

Schauen Sie sich zumindest die ETag und die If-Modified-Since-Mechanismen an, die von allen aktuellen Browsern unterstützt werden und die stabilste Möglichkeit zu sein scheinen, den Server nach aktualisierten Inhalten abzufragen.

Eine Möglichkeit, eine CSS-Datei-Browser mit der If-Modified-Since-Header ist so etwas wie dies (die leeren Header schalten Sie alle nicht-Caching-Header PHP sendet per default) zu dienen:

$p = 'path/to/css/file' 
$i = stat($p); 
if ($_SERVER['HTTP_IF_MODIFIED_SINCE']){ 
    $imd = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']); 
    if (($imd > 0) && ($imd >= $i['mtime'])){ 
     header('HTTP/1.0 304 Not Modified'); 
     header('Expires:'); 
     header('Cache-Control:'); 
     header('Last-Modified: '.date('r', $i['mtime'])); 
     exit; 
    } 
} 
header('Last-Modified: '.date('r', $i['mtime'])); 
header('Content-Type: text/css'); 
header('Content-Length: '.filesize($p)); 
header('Cache-Control:'); 
header('Pragma:'); 
header('Expires:'); 
readfile($p); 

Der Code verwendet den if-modified-since-header, den der Browser sendet, um zu überprüfen, ob sich die tatsächliche Datei auf dem Server seit dem Datum geändert hat, das der Browser angegeben hat. Wenn dies der Fall ist, wird die Datei gesendet, andernfalls wird 304 Not Modified zurückgegeben und der Browser muss den gesamten Inhalt nicht erneut herunterladen (und wenn er intelligent genug ist, hält er das geparste CSS auch im Speicher).

Es gibt noch einen weiteren Mechanismus, bei dem der Server einen eindeutigen ETag-Header für jedes Stück Inhalt sendet. Der Client sendet das mit einem If-None-Match-Header zurück, so dass der Server nicht nur über das Datum der letzten Änderung, sondern auch über den Inhalt selbst entscheiden kann.

Dies macht aber nur den Code komplizierter, also habe ich es weggelassen. FF, IE und Opera (wahrscheinlich auch Safari) senden alle den If-Modified-Since-Header, wenn sie Inhalte mit einem Last-Modified-Header empfangen, also funktioniert das gut.

Denken Sie auch daran, dass bestimmte Versionen von IE (oder die JScript-Runtime, die es verwendet) noch Probleme mit GZIP-übertragenen Inhalt haben.

Oh. Und ich weiß, dass das nicht Teil der Frage ist, aber auch Acrobat in einigen Versionen. Ich habe Fälle und Fälle von weißen Bildschirmen gehabt, während ich PDFs mit gzip Übertragungsverschlüsselung gedient habe.

+0

Haben Sie eine Quelle/URL für die IE/JScript-Probleme mit GZIP-Inhalt? Ich erinnere mich an ältere Versionen von IE (z. B. vor IE6), die gzip nicht unterstützen, aber das bedeutet nur, dass sie den langsameren unkomprimierten Inhalt erhalten. Wenn es immer noch Probleme mit dem IE gibt, würde ich es gerne wissen! – scunliffe

+0

Ich hatte Fälle, in denen IE externe JS-Dateien, die mit gzip übertragen wurden, nicht analysieren konnte. Und einige Versionen (auch aktuell) des Acrobat Plugins können auch keine Komprimierung verarbeiten, obwohl sie dies behaupten können. – pilif

7

Sorry wegen der Verzögerung - es ist eine arbeitsreiche Woche für mich.

Annahmen:

  • .htaccess als compress.php
  • statische Dateien in der gleichen Datei sind in static Unterverzeichnis von Einstellung folgende Richtlinien in

Ich begann meine Lösung komprimiert werden.htaccess:

RewriteEngine on 
RewriteRule ^static/.+\.(js|ico|gif|jpg|jpeg|png|css|swf)$ compress.php [NC] 

Es ist erforderlich, dass Ihr Provider Sie mod_rewrite Optionen in .htaccess Dateien überschrieben werden können. Dann wird die compress.php Datei selbst wie folgt aussehen:

<?php 

$basedir = realpath(dirname($_SERVER['SCRIPT_FILENAME'])); 
$file = realpath($basedir . $_SERVER["REQUEST_URI"]); 

if(!file_exists($file) && strpos($file, $basedir) === 0) { 
    header("HTTP/1.0 404 Not Found"); 
    print "File does not exist."; 
    exit(); 
} 

$components = split('\.', basename($file)); 
$extension = strtolower(array_pop($components)); 

switch($extension) 
{ 
    case 'css': 
     $mime = "text/css"; 
     break; 
    default: 
     $mime = "text/plain"; 
} 

header("Content-Type: " . $mime); 
readfile($file); 

Sie sollten natürlich mehr Mime-Typen auf die Switch-Anweisung hinzufügen. Ich wollte die Lösung nicht von der pecl fileinfo Erweiterung oder anderen magischen MIME-Typ-Erkennungsbibliotheken abhängig machen - das ist der einfachste Ansatz.

Wie für die Sicherung des Skripts - ich eine Übersetzung in einen realen Pfad im Dateisystem, so dass keine gehackten '../../../etc/passwd' oder andere Shellscript-Dateipfade nicht durchlaufen.

dass die

$basedir = realpath(dirname($_SERVER['SCRIPT_FILENAME'])); 
$file = realpath($basedir . $_SERVER["REQUEST_URI"]); 

Schnipsel ist. Obwohl ich ziemlich sicher bin, dass die meisten Pfade, die sich in einer anderen Hierarchie als $ basedir befinden, vom Apache behandelt werden, bevor sie überhaupt das Skript erreichen.

Auch ich überprüfe, ob der resultierende Pfad innerhalb der Verzeichnisstruktur des Skripts ist. Fügen Sie die Header für die Cache-Steuerung hinzu, wie von pilif vorgeschlagen, und Sie sollten eine funktionierende Lösung für Ihr Problem haben.

+0

Danke, ich werde es versuchen. Ich wünschte, SOF hätte E-Mail-Benachrichtigungen, die Ihnen sagen, wenn eine Frage aktualisiert wird. –

+0

Hey, mit diesem würde ich es benutzen. Ich speichere das als compress.php korrekt? Benütze ich ein Include? – Coughlin

+0

Dieses Skript geht davon aus, dass es von der Apache Rewrite-Regel ausgeführt wird und einen Dateinamen als URI-Parameter erhält. – macbirdie

1

Anstatt im laufenden Betrieb zu entpacken, wenn Benutzer die CSS- und JavaScript-Dateien anfordern, können Sie sie im Voraus herunterladen. Solange Apache ihnen die richtigen Header anbietet, bist du golden.

Zum Beispiel auf Mac OS X, eine Datei auf der Kommandozeile Gzipping ist so einfach wie:

gzip -c styles.css > styles-gzip.css 

Könnte nicht die Art von Workflow sein, wenn für Sie arbeitet.