Nachdem ich ja vor einiger Zeit meinen Vorschlag gemacht habe, dass man Javascript und CSS Dateien doch gemeinsam über PHP parsen und ausgeben konnte kam natürlich gleich die Frage, ob und wie man das dann cachen kann. Nach einigen harten Fehlschlägen ist hier meine aktuelle Strategie dynamische Bilder, Skripte etc. den Browser (zumindest die Meisten) cachen zu lassen.
Also nach meinen ersten Recherchen bin ich erstmal auf die
header('HTTP/1.1 304 Not Modified');
Funktionalität gestoßen. Die ist an sich schon mal ziemlich gut. Nur leider brauchte ich danach eine Möglichkeit zu unterscheiden, ob der Client die Seite schon mal geladen hat, weil der Browser ist nämlich sonst so doof, dass er evtl. zu laden aufhört, auch wenn er die Datei noch niemals gesehen hat. Also ging es weiter in die tiefen der Request und Response Header.
Das nächste Resultat waren dann die
header("Last-Modified: " . $modTime);
header("Expires: " . gmdate('D, d M Y H:i:s', mktime(date('h') + 24)) . ' GMT');
Header, mit denen man sagt, wann die Datei zuletzt modifiziert wurde und wie lange sie im Cache aktuell sein soll. Die Datei oben soll gefälligst erst nach einem Tag wieder neu geladen werden. Schon ganz gut. Nur wie bekommt man die Last-Modified Zeit? Hier speichere für Skripte immer die neueste filemtime()
$time = 0;
foreach($media as $v) {
$time = (filemtime($v) > $time) ? filemtime($v) : $time;
}
$modTime = gmdate('D, d M Y H:i:s', $time) . ' GMT';
Damit habe ich am Ende in $time immer die letzte Aktualisierung. Diese benutze ich dann in dem Header.
Gut, aber noch nicht gut genug, weil ich muss ja schließlich noch rausfinden, was der Browser sagt, wann er die Datei zuletzt erhalten hat, um zu unterscheiden, ob ich jetzt neu laden lassen muss, oder ob er seinen Cache benutzen kann. Dabei bin ich noch auf eine tolle Erweiterung der Header-Funktionen gestoßen, die normalerweise automatisch für Bilder etc. genutzt wird. Der eTag. Der eTag ist ein beliebiger String, den ihr selber generieren könnt, den der Browser auch mitschickt und gegen den ihr dann vergleichen könnt.
$hash = md5(serialize($media));
$eTag = 'foo-' . dechex(crc32($hash.$time));
header('ETag: "'.$eTag.'"');
So jetzt geht es nur noch darum, dass man die beiden Tags, Last-Modified und ETag, auch noch in seinem Skript wieder nutzen kann. Dafür gibt es zwar eine PHP-Funktion apache_request_headers(), da diese aber nur funktioniert, wenn PHP als Modul läuft, zeige ich euch gleich den Weg, der (so gut wie) überall funktioniert. Ihr braucht nämlich mod_rewrite, aber das geht mittlerweile eigentlich bei jedem Webhoster. Also eine .htaccess ins Root-Verzeichnis.
RewriteEngine On
RewriteRule .* - [E=HTTP_IF_MODIFIED_SINCE:%{HTTP:If-Modified-Since}]
RewriteRule .* - [E=HTTP_IF_NONE_MATCH:%{HTTP:If-None-Match}]
Dann kann man über die $_SERVER Globale auf die beiden Tags zugreifen.
if ((strpos($_SERVER['HTTP_IF_NONE_MATCH'], $eTag)) && ($modTime == $_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
header('HTTP/1.1 304 Not Modified');
header('ETag: "'.$eTag.'"');
} else {
//normale Abarbeitung
}
So. Damit könnt ihr die Last auf eurem Server ein wenig reduzieren und alles, was ihr da so dynamisch raus haut auch mal schön cachen lassen.
Ein letzter Tipp, den ich noch gelesen habe, aber noch nicht weiter untersucht habe. Wenn ihr Sessions in eurer Applikation benutzt, dann sagte mir mal jemand, dass Seiten, die Cookies setzen erstmal nicht gecacht werden. Aber mit einem
session_cache_limiter('public, must-revalidate');
Soll man da Abhilfe schaffen können. Also viel Spaß beim cachen. Hat bei mir eine signifikante Verbesserung der Ladezeiten der Seite gebracht.

















