PHP-Klasse AhCache

PHP-Klasse zum Cachen von Content

Steckbrief :: ahCache

Dateibasierter Cache für alle serialisierbaren Objekte

Typ:
Klasse
Die Caching Klasse legt pro Applikation je einen Ordner an und speichert darin basierend auf einem Identifier einen Inhalt. Man kann Strings, Integer, Arrays oder Objekte cachen lassen. Neben den eigentlichen Daten kann man einen TTL Wert mitgeben, um zu bestimmen, ob der Cache abgelaufen ist. Ohne TTL kann man das Alter des Cache ermitteln oder aber mit dem Zeitstempel einer angegebenen Datei vergleichen lassen. Cleanup-Funktionen runden den Funktionsumfang ab.

Anforderungen:
  • PHP 7 oder 8 (es läuft unter PHP 5, wird aber nicht supportet)

Features:
  • Caches werden applikationsweise mit einer ID abgelegt: im Cache-Ordner kann man so die Caches einer Applikation löschen
  • Caches können mit und ohne eine Ablaufzeit (TTL) gespeichert werden
  • Zum Zeitvergleich: man kann das Alter des Caches bestimmen, bei gespeichertem TTL: ob er angelaufen ist und man kann das Alter mit einer Referenz-Datei vergleichen.
  • Cleanup applikationsbasiert als auch über alle Cachedateien

Lizenz:
  • GNU GPL v3 (Opensource)

Einleitung

For information in English see the Docs.

Manche Aufgaben beim verarbeiten eines Webserver-Requests brauchen Zeit. Sei es ein rekursiver Verzeichnisscan, ein aufwändiges Query oder Requests auf andere Server.
Solche zeitaufwändigen Aufgaben möchte man nicht bei jedem Seitenaufruf ausführen, weil es den Seitenaufbau immer arg verlangsamt, sondern nur "gelegentlich". Dazu speichert man einmalig das Ergebnis in einem Cache und verwendet den Cache solange man es für sinnvoll erachtet.

Diese Klasse verwende ich auf dieser Webseite zum Cachen von HTML-Code, RSS-Daten und Grafiken.
Weiterhin war diese Klasse in Version 1 auch mehrere Jahre auf der Webseite des Schweizer Radio DRS (www.drs.ch; nun SRF Radio) im Einsatz.

cache-class.png

Versionsgeschichte

  • 2014-03-31 - Version 2.3
    • private Methode _setup() includet nun custom settings - damit kann man den Cache Pfad ausserhalb der Klasse definieren
    • für sehr viele Cacheitems (zuu viele Dateien in einem Verzeichnis sind nicht gut): neue Variable zum Anlegen kürzerer, aber dann verschachtelter Cache-Verzeichnisnamen
  • 2014-02-27 - Version 2.2
    • Umbenennung von Cache nach AhCache
    • _cleanup Methode prüft mit file_exists
  • 2012-05-17 - Version 2.1
    • geänderte Methode: isExpired() liefert Wert als bool (vorher Wert in Sekunden);
    • neue Methode: iExpired() liefert Wert in Sekunden
  • 2012-01-31 - Version 2.0
    • neu: es können alle serialisierbaren Variablen gecacht werden - also auch Arrays und Objekte - nicht nur Strings, wie in Version 1
    • Methode write() erweitert: als 2. Parameter kann eine Verfallszeit mitgegeben werden, die mit in der Cachedatei gespeichert wird
    • neue Methode: isExpired() zum einfacheren Feststellen, ob Cache veraltet ist (bedingt Verwendung des neuen 2. Parameters für write())
    • neue Methode: isNewerThanFile([Referenzdatei]) - zum einfacheren Feststellen, ob Cache veraltet ist
    • neue Methode: cleanup() - Löschen alter Cachedateien
  • 2011-08-27 - Version 1.1 - mehr Kommentare im PHP Code; sCacheFile is private
  • 2009-07-20 - Version 1.0 - erste öffentliche Version

Installation

Kopieren Sie die Datei cache.class.php (und optional die Datei cache.class_config.php) in ihr PHP-Verzeichnis. Sie kann auch in einem beliebigen Unterordner abgelegt werden.

Einbindung in deine Webseite

Basics: Füllen und Lesen des Caches

(1)
Mit einer include_once/ require_once ist die Klasse zu laden.

(2)
Mit der Initialisierung sind 2 Parameter anzugeben:

  • der Name deiner Applikation / deines Moduls
    Im Hintergrund wird für die Applikation ein Unterverzeichnis angelegt. Dann können verschiedene Module dieselbe ID verwenden. Und man kann einfacher das Cacheverzeichnis eines Moduls leeren.
  • eine ID für die Daten
    Die ID kann ein beliebiger Text oder auch eine Zahl sein. Bei RSS Feeds kann man so direkt die URL des Feeds mitgeben; bei Datenbank-Queries kann es eine Basis ID sein, für die die Daten ermittelt wurden.


(3)
Die Funktionen read() und write([Daten , [Expire]]) lesen bzw. schreiben den Cache-Inhalt.

(4)
Mit am wichtigsten ist die Frage: wie lange man ich den Cache verwenden und wann muss ich diesen erneuern?
Es gibt mehrere Varianten:

  1. Zunächst werden die Daten mit write([Daten]) geschrieben.
    Mit der Funktion getAge() kann man das Alter des Caches in Sekunden ermitteln. Ist es false, so gibt es noch keinen Cache.
    Man kann den Cache anlegen/ erneuern lassen, wenn noch kein Cache existiert oder das Alter des Cache eine Toleranzschwelle übersteigt.
    Das ist eine Methode von Version 1; es sollte bevorzugt eine der nachfolgend erwähnten Varianten gewählt werden.
  2. mit der Methode write() gibt man als 2. Paramter eine Verfallszeit (Expire) in Sekunden mit. Diese Verfallszeit wird mit in der Cachedatei abgelegt.
    Dann kann man mit isExpired() feststellen, ob der Cache veraltet ist (negative Werte = Zeit in Sekunden bis Verfall; positive Werte = wie lange der Cache verfallen ist)
  3. Wenn man den Cache basierend auf einer anderen Datei aufbaut, kann man die Zeitstempel von Quelldatei und Cachedatei zum Vergleich heranziehen.
    Die Funktion isNewerThanFile([Dateiname-der-Referenzdatei]) gibt die Differenz der letzten Änderung in Sekunden zurück (negative Werte = Cachdatei ist älter als Referenzdatei).
    Die Referenzdatei ist der komplette Dateiname, den der Webserver finden können muss (lokal oder NFS Share etc.).
    Beispiele wären: ein verkleinertes Vorschaubild wird erst dann erneuert, wenn sich die Quelldatei geändert hat; oder: meine Tabelle mit Batch-Kommandos und Beispielen basieren auf einer CSV Datei - der Cache wird erst neu geschrieben, wenn ich die CSV Datei aktualisiere.

Ein Coderumpf als Ausgangslage zu 2) für eigene Entwicklungen sieht so aus:

$sContent='';  
$iTtl=60*5; // 5 min als max. zulaessiges Alter  
  
require_once("/php/cache.class.php");  
$myCache=new AhCache("mein-modul","Aufgaben-ID");  
  
if($myCache->isExpired()) {  
    // Cache existiert nicht oder ist veraltet  
    // hier folgt Code, der $sContent neu auffuellt ...  
    $sContent=...  
  
    // ... und im Cache ablegen  
    $myCache->write($sContent, $iTtl);  
  
} else {  
    // Cache-Daten lesen  
    $sContent=$myCache->read();  
}  
  
// Ausgabe  
echo $sContent;

... und ein Beispiel zu 3) zum Vergleich des Zeitstempels. $sCsvFile enthält nachfolgend den Dateinamen des Quellfiles:

require_once("/php/cache.class.php");
$sCsvFile="Name_der_Quelldatei.csv"  
  
$myCache=new AhCache("mein-modul","Aufgaben-ID");
$sContent=$myCache->read(); // einmal den Inhalt lesen  
  
// Vergleich des Alters des Cache mit dem einer Referenzdatei  
if (!$sContent || !$myCache->isNewerThanFile($sCsvFile)) {  
  
    // hier folgt Code, der $sContent neu auffuellt ...  
    $sContent=...  
  
    // ... und im Cache ablegen  
    $myCache->write($sContent);  
};  
  
// Ausgabe  
echo $sContent;

Zugriff auf div. Zeiten und Alter bestimmen

Hilfreich ist es, wenn ein Time to live Wert (TTL) bei der Methode write() als zweiter Parameter angegeben wird:

$myCache->write($sContent, $iTtl);

Dann kann man mit

$myCache->isExpired()

recht einfach abfragen, ob der Cache abgelaufen ist.

Es gibt aber auch Methoden für detailliertere Zeitangaben:

  • getAge()
    gibt das Alter der geschriebenen Cache-Datei in Sekunden zurück
     
  • getExpire() (*)
    gibt einen Unix-Zeitstempel zurück, wann der Cache abgelaufen ist
     
  • getTtl() (*)
    gibt den TTL Wert des Caches zurück; Wert ist in Sekunden
     
  • iExpired() (*)
    gibt an wie lange der Cache abgelaufen ist; negative Werte besagen, wie lange der Cache noch gültig ist; Wert ist in Sekunden
     
  • isNewerThanFile($sRefFile)
    vergleicht, ob das Cachefile (immernoch) neuer ist, als eine angegebene Referenzdatei.
     

(*) - dies ist nur verfügbar, wenn TTL bei der write-Methode mitgegeben wurde

$myCache->write($sContent, $iTtl);


All die obigen Methoden sind Lesezugriffe.
Schreibende Wirkung haben diese Methoden:

  • setTtl($iTtl)
    setzt den TTL-Wert des Objektes in Sekunden
    Es muss anschliessend noch die write()-Methode ausgeführt werden (dies kann nach setTtl ohne den 2. Parameter erfolgen), damit der neue TTL-Wert "dauerhaft" für nachfolgende Requests in das Cachefile geschrieben wird. Beachte: Damit wird das Expire ab dem aktuellen Zeitpunkt neu gesetzt.
     
  • touch()
    Erneuern des Cache-Objektes mit den bisherigen Daten. Der Inhalt des Caches wird beibehalten; das Expire-Datum wird mit dem bisherigen TTL neu ab dem aktuellen Zeitpunkt gesetzt.
     
  • write( $data = false, $iTtl = -1)
    Schreibt die zu cachenden Daten; bei Angabe 2er Parameter ist der zweite der TTL-Wert des Objektes in Sekunden

Löschen von Cachefiles

Man kann von einem zu cachenden Inhalt einen einzelnen Cache gezielt löschen. Dazu muss das entsprechende Objekt initialisiert und die die Methode delete() aufgerufen werden.

  1. require_once("/php/cache.class.php");
  2. $myCache=new Cache("mein-modul","Aufgaben-ID");
  3. $myCache->delete(); // einzelnen Cache loeschen
PHP: cache - Beispiel mit Vergleich des Zeitstempels einer Referenzdatei


Um im Cacheverzeichnis alle Cache-Dateien löschen, die älter als n Sekunden sind, gibt es die cleanup-Methode. Das Cache-Objekt ist mit einer beliebigen Modul-ID zu initialisieren.

  1. require_once("/php/cache.class.php");
  2. $o=new Cache("mein-modul");
  3. $o->cleanup(60*60*24*1); // alle Cachefiles des Moduls "mein-modul" älter 1 Tag löschen
PHP: Löschen des Caches eines Moduls



Initialisiert man die Klasse ganz ohne Modul und ruft die cleanup Methode auf, so werden alle cachefiles aller Module aufgeräumt.

  1. require_once("/php/cache.class.php");
  2. $o=new Cache();
  3. $o->cleanup(0); // alle Cachefiles aller Module löschen
PHP: Löschen des Caches aller Module


Anm.:

  • Der Parameter von cleanup() ist das max. erlaubte Alter der Cachedateien in Sekunden. Ist der Wert 0, so werden *alle* Cachedateien gelöscht.
  • Die cleanup()-Mehode ignoriert alle anderen Dateitypen, die keine Cachedateien sind.
  • Leere Verzeichnisse ab dem Cache-Root werden gelöscht.