HTTP Response Header Last-Modified und ETag mit PHP für Caching setzen

Bei statischen Dateien braucht man sich um das Thema Caching in der Regel wenig Sorgen machen. Natürlich können auch statische Dateien den Server ganz ordentlich beschäftigen, insbesondere wenn eine Webseite gut besucht wird und man den schwer gewichtigen Apache als Frontend-Webserver eingerichtet hat. In diesem Fall und natürlich auch für Projekte in denen PHP zum Einsatz kommt, kann ich Varnish Cache sehr empfehlen.

Jedoch hat nicht jeder die Möglichkeit so weit ins System einzugreifen und manchmal möchte oder muss man auch auf PHP-Ebene entscheiden, ob eine vom Client (Browser) gecachte Datei noch aktuell ist oder nicht. Und hier kommen diverse HTTP Response Header ins Spiel, die man mit PHP setzen kann.

So kann man am Anfang eines Programms zum Beispiel abfragen, wann ein Artikel aus einem Shop das letzte Mal geändert wurde. Oder will einfach nur schauen, ob sich eine spezielle Datei seit der letzten Anfrage des Clients geändert hat.

Diesen serverseitig errechneten „zuletzt modifiziert“ Zeitstempel vergleicht man dann mit dem Zeitstempel, den der Client an den Server mitgeschickt hat. Ist die gecachte Version noch aktuell, kann das Programm sofort abgebrochen werden – man sagt dem Client einfach: „Deine Version ist noch aktuell, es hat sich hier nix geändert.“

Komplexe und eventuell Ressourcen fressende Routinen müssen damit nicht mehr ausgeführt werden, der Server wird entlastet und hat wieder Luft für die nächste Anfrage.

Damit der Einbau möglichst einfach gestaltet werden kann, habe ich hier einmal die von mir geschriebene Funktion gepostet (die jeder gerne frei nutzen kann):

Und so könnte der Einbau aussehen:

Manchmal hat man aber nicht nur einen Zeitstempel $timestamp auf den man sich beziehen möchte, sondern auch noch einen oder mehrere andere Faktoren. Als Beispiel könnte es sein, dass für die verschlüsselte Version (https) eine andere Seite ausgeben werden soll als für die unverschlüsselte Version (http). Vielleicht soll es auch pro Sprache, Land der IP und/oder diverser anderer Eigenschaften jeweils eine eigene gecachte Version geben. Hier kommt der zweite Parameter $identifier der Funktion ins Spiel:

Noch ein paar Hinweise zum Schluss:

  • Standardmäßig werden vom Client beide Request Header HTTP_IF_NONE_MATCH (Gegenstück zu, Server Response Header ETag) und HTTP_IF_MODIFIED_SINCE (Gegenstück zu, Server Response Header Last-Modified) gesendet. Dieses muss aber nicht zwingend der Fall sein.
  • Von der Funktion werden standardmäßig nur dann beide Werte verglichen, wenn auch beide Request Header gesendet werden, ansonsten reicht standardmäßig auch eine Übereinstimmung.
  • Man kann die Funktion zwingen immer nur dann 304 Not Modified (alles noch aktuell) zurückzumelden, wenn beide Werte gesetzt sind und auch beide Werte übereinstimmen. In diesem Fall muss der dritte Parameter $strict auf true gesetzt werden.

Es gibt eine sehr gute Seite, auf der man das Ergebnis prüfen kann: REDbot

Das könnte dich auch interessieren...

2 Antworten

  1. Max Steinweber sagt:

    Also eigentlich mag ich es nicht Kommentare auf Blogs zu schreiben. Die Anzahl der Kommentare in den letzten 10 Jahren kann man wohl an 2 Händen abzählen. Aber der Beitrag ist einer von denen, die es verdient haben ;)

    Gefällt mir wirklich gut und schön erklärt mit gutem Beispiel. Lediglich ein kleiner Fehler ist in deinem Script.

    $client_etag sollte mit str_replace(‚"‘,'“‚,trim($_SERVER[‚HTTP_IF_NONE_MATCH‘])) ermittelt werden. Es ist nicht immer garantiert, dass es ein “ ist.
    Alternativ könnte man natürlich auch alles andere raus filtern und beide ETags „blank“ vergleichen. Dann würde ich aber eher zu strpos( ) raten um aktuellen tag mit dem übermittelten client-etag zu prüfen.

    • Ansas sagt:

      Hi Max,

      danke für Deinen Kommentar. Ich habe die Funktion direkt einmal angepasst (sicher ist sicher), so dass die Anführungszeichen oder was auch immer der Client ggf. daraus macht keine Rolle mehr spielt.

      In dem Zuge ist mir aufgefallen, dass REDbot scheinbar einen neuen Check eingebaut hat. Entsprechend berücksichtige ich nun beim generieren des ETags auch noch die vom Client akzeptierten Encodings. Diese sollten sich pro Client eigentlich nicht ändern, so dass sich für den einzelnen Client nichts ändert.

      LG Ansas

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.