[PHP] Einfacher Cache für Webseiten mit PHP

Hallo zusammen,

heute möchte ich mal ein paar Denkanstöße zum Thema Webseite Cachen geben.

Frei übersetzt heißt “cache”: Zwischenspeicher. Und genau das ist es auch. Es wird etwas Zwischengespeichert um etwas schneller zu machen. In diesem Fall die Webseite.
Doch warum Zwischenspeichern? Was bringt das? Hierzu ein kleines Beispiel, welches ich die letzten Tage erfahren durfte.

Ich habe eine Webseite die sich automatisch Inhalte besorgt und in eine Datenbank schreibt. Dazu generiert es automatisch Keywords. Das hat auch alles immer gut geklappt, bis jetzt mein Server ständig in die Knie gegangen ist. Es hat nicht lange gedauert bis ich diese Webseite als den Übeltäter herausgefischt hatte. Dazu muss ich sagen das ich bei der Programmierung ein wenig geschlampt habe. Aber für unser Beispiel ist es optimal.

Also die Webseite ist eine Art Shop. Mit Kategorien und Artikeln. Über 70.000 Artikeln! Und bei jedem Aufruf durch einen Besucher wird die angeforderte Seite generiert. Die Daten werden aus der Datenbank abgefragt und in das Template eingefügt. Dazu gibt es noch Tag-Clouds und ähnliche Artikel. Das sind pro Seite enorme Belastungen für die Datenbank.

Doch schlussendlich sind die einzelnen Seiten immer gleich. Artikel A ist immer Artikel A und die Seite wird daher immer gleich bleiben. Nur die Tags in der Tag-Cloud ändern sich.
Also ist die beste Lösung ein Caching System. Denn mit einem Cache-System wird die Seite einmal generiert und in einem Cache abgelegt. Ruft der nächste Besucher die gleiche Seite noch einmal auf, dann wird die Seite nicht neu erzeugt, sondern aus dem Cache geladen. Das schon die Datenbank und steigert die Performance enorm.

Doch wie funktioniert solch ein Caching System? Eigentlich ganz einfach. Der logische Ablauf ist ja ganz einfach:

Seite muss ja beim ersten Aufruf definitiv generiert werden. Dabei wird der Inhalt im PHP-Cache gehalten und am Ende in eine (Cache)Datei geschrieben und auch ausgegeben. Wird die selbe Seite noch einmal aufgerufen, wird geprüft ob die Cache-Datei vorhanden ist. Wenn ja, dann die Cache-Datei laden und ausgeben. Wenn nicht dann ist es ein “erster Aufruf”.

Soweit die groben Gedanken. Jetzt etwas Detailierter.

Wie ordnen wir denn eine URL einer Datei zu?
Ich habe das mit einem SHA1-Hash gemacht. Damit kann ich eine URL in einen Hash verwandeln, den ich dann als Dateinamen benutze. Somit kann ich einfach prüfen ob eine URL schon gecached ist.

Wird meine Seite jetzt statisch?
Teilweise ja. Aber ein Cache sollte auch mal erneuert werden. Wie oft, das muss jeder individuell entscheiden. Ich Lösche zwischengespeicherte Seiten nach 6 Stunden in der Regel wieder. Warum? Weil sich immer mal etwas ändern kann.
Wie macht man das? Ganz einfach prüfen wann die Cache-Datei erstellt wurde. Wenn Datum länger her ist als 6 Stunden (z.B.) dann die Datei löschen und neu erstellen.

Was ist wenn ich in meiner Seite dynamische Elemente habe?
Ein Cache schaltet grundsätzlich erst einmal alle dynamischen Teile einer Seite aus, da die Seite statisch in eine Datei geschrieben wird. Deswegen muss der Cache auch ab und zu mal wieder gelöscht werden.
Gibt es nun aber Inhalte auf der Seite die bei jedem Aufruf geändert bzw. dynamisch sein sollen, so muss das System so angepasst werden, das dies möglich ist. Zum Beispiel kann man im Template einen Code einbauen, der jedes mal dann ersetzt wird. Wird die Zwischengespeicherte Seite nun ausgelesen so muss der Code vor der Ausgabe ersetzt werden. Das ist gar nicht so schwer wie es sich anhört ;)

Ich werde es am besten mal an ein wenig Code erklären :)

Am Anfang der PHP-Datei (am besten Auslagern oder eine zentrale PHP-Datei haben):

//CACHING Function
// ===================================
define(CACHE_TIME, 43200);
$url = sha1($_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
if ((file_exists(ROOT_FOLDER.'cache/'.$url.'.pcae') == true) && (filemtime( ROOT_FOLDER.'cache/'.$url.'.pcae' ) >= ( mktime()-CACHE_TIME ))) {
        //load cache file
        $content = file_get_contents(ROOT_FOLDER.'cache/'.$url.'.pcae');
        include(ROOT_FOLDER.'/funktionen/funktionen/is_chached_functions.php');
        print_r($content);
        exit;
}
elseif ((file_exists(ROOT_FOLDER.'cache/'.$url.'.pcae') == true) && (filemtime( ROOT_FOLDER.'cache/'.$url.'.pcae') < ( mktime()-CACHE_TIME ))) {
        //old cache file, delete
        unlink(ROOT_FOLDER.'cache/'.$url.'.pcae');
}

ob_start();

Und am Ende der Datei (vor jeder Ausgabe):

$content = ob_get_contents();
ob_end_clean();

if (file_exists(ROOT_FOLDER.'cache/'.$url.'.pcae') == true) {
        //delete old cache file
        unlink(ROOT_FOLDER.'cache/'.$url.'.pcae');
}
//Write new cache file
file_put_contents(ROOT_FOLDER.'cache/'.$url.'.pcae', $content);

//functions which shouldn't be cached!
include(ROOT_FOLDER.'/funktionen/funktionen/is_chached_functions.php');
print_r($content);
unset($content);
exit;

Gehen wir das noch einmal Zeile für Zeile durch. Fangen wir oben an.
Ich habe mir hier in CACHE_TIME die Zeit gespeichert, wie oft die Zwischengespeicherte Seite erneuert werden soll. Zeit in Sekunden.
Dann erstelle Ich den SHA1-Hash der aktuellen URL mit Parametern (Wichtig!).
Nun wird geprüft ob die Datei schon existiert und wie alt sie ist. ROOT_FOLDER ist mein Stammverzeichnis auf meinem Server.

Existiert die Datei schon und ist noch nicht veraltet, dann wird der Inhalt geladen. In meiner Datei “is_chached_functions.php” sind Funktionen enthalten die dynamische Inhalte im Template ersetzen. Was ich vorhin kurz angesprochen hatte. Solch ein Inhalt kann im Template mit “<!– UHRZEIT –>” vermerkt sein. In der Funktion würde nun stehen “$content = str_replace(“”<!– UHRZEIT –>”, date(“H:i:s”), $content);”. Damit hätten wir trotz Cache dynamisch die Uhrzeit in die Seite eingefügt.
Und letztendlich wird die Seite ausgegeben.

Existiert die Datei zwar, ist aber veraltet, dann wird sie einfach gelöscht und das Scipt läuft normal weiter und baut die Seite neu auf. Wichtig ist ob_start(). Damit wird angegeben das keine direkte Ausgabe erfolgt, sondern die Seite im PHP Speicher Zwischengespeichert wird.

Der untere Teil:

Hier schreiben wir nun den PHP Zwischenspeicher in die Variable $content und leeren ihn. Dann prüfen wir noch einmal ob die Datei evtl. existiert und löschen sie einfach, falls ja. (Kann ja mal passieren.)
Dann schreiben wir die erzeugte Seite aus $content in die Cache-Datei.
Nicht vergessen auch hier die dynamischen Inhalte zu ersetzen (in unserem Beispiel die Uhrzeit).
Dann noch die Seite ausgeben und fertig. Nun wurde eine neue Cache-Datei erzeugt, die dann beim nächsten Aufruf ausgegeben wird, anstatt die Seite komplett neu aufzubauen.

Der Server wird es danken ;) Der Hoster übrigens auch :) Und der Besucher auch :) Alle werden sich über mehr Performance, weniger Ressourcenverbrauch und schnellere Ladezeiten freuen ;)

Viele Grüße
Gordon

0 Kommentare

Hinterlasse einen Kommentar

An der Diskussion beteiligen?
Hinterlasse uns deinen Kommentar!

Schreibe einen Kommentar

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

Ich stimme der Datenschutzerklärung zu