Partielles Caching mit PHP

Thomas Darimont

Erfahrenes Mitglied
Hallo,

ich würde für meine Website gerne einen kleinen Cachingmechanismus bauen. Ich habe nicht allzu viel Ahnung von PHP
und will bevor ich mich da weiter einarbeite erstmal fragen ob mein Vorhaben überhaupt so machbar ist.

Ich habe viele kleine php Scripts die jeweils nur eine "Box" in meinem Layout generieren.

Diese sehen dann immer so aus:
(page.php)
Code:
< ? php  

code ...

? >
Da sich der Inhalt einiger Boxen relativ selten ändert würde ich diese gerne cachen und nur nach Ablauf einer gewissen Zeit
neugenerieren.

Das könnte man zum einen über eine generische caching Lösung geschehen die sich beispielsweise in dieser Form im Code widerspiegelt:
caching.php?cache=page.php -> page.php -> page.static.html

Es gibt eine caching.php welche Beispielsweise über einen Parameter in der URL die zu cachende Datei übergeben bekommt.
Beim ersten Aufruf dieser URL wird dann das page.php Script ausgeführt, die Ausgabe wird zwischengespeichert und in eine Datei
weitergeleitet -> page.static.html. Anschließend wird die zwischengespeicherte Ausgabe zum Aufrufer gesendet. Beim der nächsten
Anfrage für page.php die innerhalb eines bestimmten (Konfigurierbaren) Zeitlimits geschieht wird einfach der Inhalt aus
page.static.html zurück geliefert. Erfolgt ein Aufruf nachdem das Zeitlimit abgelaufen ist so wird die page.static.php wieder
erneut generiert.

So würde ich das eigentlich machen, leider macht mir die verwendete Drittsoftware hier einen Strich durch die Rechnung -
als Inhalt für eine "Box" in meinem template kann ich leider nur Dateien angeben und keine URLs... also fällt die generische Lösung
via: caching.php?cache=page.php weg. Weiterhin möchte ich keine der ursprünglichen Dateien (page.php) modifizieren müssen
( außer den "Aufrufern / includiern");

Alternative:

Zu jeder page.php gibts eine page.cached.php

configuration.php:
Code:
cacheInvalidationInterval=1000 * 60 * 5; //5 min

Diese macht dann (in pseudo code) ungefähr sowas

Code:
< ? php (page-cached.php)

cacheInvalidationInterval = configuration['cacheInvalidationInterval'];

file = "page.php";
cachedFile = '"page.static.html";

if( !exists(cachedFile ) || (currentTime - lastModified(cachedFile ) ) > cacheInvalidationInterval  ){

   pregeneratedOutput= include(file ); //output buffering

   store(pregeneratedOutput, cachedFile );

}else {

   pregeneratedOutput= retrieve(cachedFile );

}

   output(pregeneratedOutput); //echo ...

? >

den vorgenerierten Code kann man dann im Filesystem oder auch im Speicher (Server Variable) ablegen und über entsprechende
Strategien (Strategy Pattern) konfigurierbar machen.

Weis jemand ob man das so mit PHP umsetzen kann, gibts vielleicht Verbesserungsmöglichkeiten? Gibts vielleicht noch
kostenlose open source produkte die all das schon können und einfach einzubauen und zu konfigurieren sind?

Kann man sich vielleicht zentral in den include Mechanismus einklinken um dann deklaratives caching möglich zu machen?
Wenn das möglich wäre könnte man wunderbar sowas definieren:

CacheConfiguration.php
Code:
cacheConfiguration = new CacheConfiguration();
memoryCachingStrategy = new MemoryCachingStrategy();
fileSystemCachingStrategy = new FileSystemCachingStrategy();
cacheConfiguration.cache("bubu.php",5*1000*60,memoryCachingStrategy);
cacheConfiguration.cache("gugu.php",10*1000*60,memoryCachingStrategy);
cacheConfiguration.cache("foo.php",30*1000*60,fileSystemCachingStrategy );

Cache cache = new Cache(cacheConfiguration);
cache.registerIncludeHook();
...

Alle Anfragen an zu cachende Ressourcen gehen dann durch eine generalisierte Version des oben gezeigten Codes.
Geht sowas?

Gruß Tom
 
Hallo,

ich hab mal selbst ein wenig damit herumgespielt hier sind meine vorläufigen Ergebnisse:
caching.php
PHP:
<?php
	class Cache{
		
		private static $instance = null;
		
		private $resourceToCacheConfigurationMapping= array();

		
		function __construct(){
			Cache::register("page.php",new FileSystemCachingStrategy(), 20); //cache that page for 20 seconds (for the sake of testing ;-)
		}
		
		function register($item,ICachingStrategy $cachingStrategy,$timeToCacheInSeconds){
			$this->resourceToCacheConfigurationMapping[$item]= array($timeToCacheInSeconds,$cachingStrategy);
		}
		
		function get($item){
			if(isset($this->resourceToCacheConfigurationMapping[$item])){
				//retrieve from cache
				$timeToCacheWithStrategy = $this->resourceToCacheConfigurationMapping[$item];
				return $timeToCacheWithStrategy[1]->cacheAndRetrieve($item,$timeToCacheWithStrategy[0]);
			}
		}
		
		public static function getInstance(){
			if(self::$instance == null){
				self::$instance = new Cache();
			}
			return self::$instance;
		}
	}
	
	interface ICachingStrategy{
		function cache($item,$timeToCacheInSeconds);
		function retrieve($item);
		function cacheAndRetrieve($item,$timeToCacheInSeconds);
	}
	
	class MemoryCachingStrategy implements ICachingStrategy{
		function cache($item,$timeToCacheInSeconds){
			//todo
		}
		
		function retrieve($item){
			//todo
		}
		
		function cacheAndRetrieve($item,$timeToCacheInSeconds){
			//todo
		}
	}
	
	class FileSystemCachingStrategy implements ICachingStrategy{
		const STATIC_OUTPUT_DIRECTORY = "static/";
		const STATIC_PAGE_EXTENSION = ".static";
		
		function cache($item,$timeToCacheInSeconds){
			$staticItem = FileSystemCachingStrategy::STATIC_OUTPUT_DIRECTORY . $item . FileSystemCachingStrategy::STATIC_PAGE_EXTENSION;
			
			if(!file_exists($staticItem) || ((time() - filemtime($staticItem)) > $timeToCacheInSeconds)){
				FileSystemCachingStrategy::cacheItem($item,$staticItem);
			}	
		}
		
		function cacheAndRetrieve($item,$timeToCacheInSeconds){
			$staticItem = FileSystemCachingStrategy::STATIC_OUTPUT_DIRECTORY . $item . FileSystemCachingStrategy::STATIC_PAGE_EXTENSION;
			FileSystemCachingStrategy::cache($item,$timeToCacheInSeconds);
		 	//echo "staticfile:$staticItem filectime: ".filemtime($staticItem) ." dt: " . (time() - filemtime($staticItem)) ." " .$timeToCacheInSeconds ." ";
			return FileSystemCachingStrategy::retrieve($item);
		}
		
		function cacheItem($item,$staticItem){
			ob_start();
			include($item);
			$contents = ob_get_contents();
			ob_end_clean();
			$file = fopen($staticItem,"w");
			fwrite($file,$contents);
			fclose($file);
		}
		
		function retrieve($item){
			$staticItem = FileSystemCachingStrategy::STATIC_OUTPUT_DIRECTORY . $item . FileSystemCachingStrategy::STATIC_PAGE_EXTENSION;
			
			if(file_exists($staticItem)){
				$contents = readfile($staticItem);
			}
		}
	}
	
	//echo Cache::getInstance()->get("page.php");
	
?>

page.php:
PHP:
<?php

echo "<b>Current time: ". time() ." </b>\n";

?>

template.php:
PHP:
<?php

echo "A\n";
include("page_cached.php");
echo "B\n";

?>

page_cached.php:
PHP:
<?php

require_once 'caching.php';

echo "test";

$item = str_replace("_cached","",basename(__file__));
echo " item1 $item ";
echo Cache::getInstance()->get($item);
?>

Generierte page.php.static:
HTML:
<b>Current time: 1206391676 </b>

dann noch einen ordner "static" anlegen und schon kanns losgehen.

Das ist zumindest mal ein proof of concept. Ich finde es trotzdem unhandlich für jedes zu cachende Script ein zusätzliches
xxx_cached.php Script anzulegen welches den Caching Aspect realisiert. Das geht doch bestimmt einfacher, oder?

Sieht jemand im produktiv Betrieb da irgendwelche Probleme?

Gruß Tom
 

Anhänge

Hast du mod_rewrite zur Verfügung?
Eventuell könntest du damit die Software die du verwendest austricksen. Sprich sämtliche Requests an einen fiktiven Ordner auf deine cache.php umleiten usw. ;)

Als kleiner Idee.

Ansonsten sieht die Klasse recht solide aus. Das einzige was mich spontan stört ist die extreme Namensgebung, aber das ist halt Geschmackssache ;)

Warum benutzt du die "alten" [phpf]fopen[/phpf] Befehle, wenn du sowieso schon unter PHP5 arbeitest?
[phpf]file_get_contents[/phpf]
[phpf]file_put_contents[/phpf]
In diesem Kontext finde ich sie durchaus sinnvoll und "schöner".


Ansonsten würde ich vllt noch über Datei LOCKs nachdenken, für den Fall der Fälle beim Schreiben des Caches.
 
Hallo,

daran hab ich auch schon gedacht, aber ich dachte das geht nicht, da include Direktiven direkt auf dem Filesystem durchgeführt werden und nicht durch die Apache Pipeline gehen. Ist dem etwa nicht so? Habs noch nicht versucht...

Ansonsten würde ich vllt noch über Datei LOCKs nachdenken, für den Fall der Fälle beim Schreiben des Caches.
Kannst du mir dafür mal ein Beispiel geben? :)

Wie gesagt bin nicht so fit in PHP...

aktuelle Version:
PHP:
<?php
	class Cache{
		
		private static $instance = null;
		
		private $resourceToCacheConfigurationMapping= array();

		
		function __construct(){
			Cache::register("page.php",new FileSystemCachingStrategy(), 10); //cache that page for 10 seconds (for the sake of testing ;-)
		}
		
		function register($item,ICachingStrategy $cachingStrategy,$timeToCacheInSeconds){
			$this->resourceToCacheConfigurationMapping[$item]= array($timeToCacheInSeconds,$cachingStrategy);
		}
		
		function get($item){
			if(isset($this->resourceToCacheConfigurationMapping[$item])){
				//retrieve from cache
				$timeToCacheWithStrategy = $this->resourceToCacheConfigurationMapping[$item];
				return $timeToCacheWithStrategy[1]->cacheAndRetrieve($item,$timeToCacheWithStrategy[0]);
			}
		}
		
		public static function getInstance(){
			if(self::$instance == null){
				self::$instance = new Cache();
			}
			return self::$instance;
		}
	}
	
	interface ICachingStrategy{
		function cache($item,$timeToCacheInSeconds);
		function retrieve($item);
		function cacheAndRetrieve($item,$timeToCacheInSeconds);
	}
	
	class MemoryCachingStrategy implements ICachingStrategy{
		function cache($item,$timeToCacheInSeconds){
			//todo
		}
		
		function retrieve($item){
			//todo
		}
		
		function cacheAndRetrieve($item,$timeToCacheInSeconds){
			//todo
		}
	}
	
	class FileSystemCachingStrategy implements ICachingStrategy{
		const STATIC_OUTPUT_DIRECTORY = "static/";
		const STATIC_PAGE_EXTENSION = ".static";
		
		function cache($item,$timeToCacheInSeconds){
			$staticItem = FileSystemCachingStrategy::STATIC_OUTPUT_DIRECTORY . $item . FileSystemCachingStrategy::STATIC_PAGE_EXTENSION;
			
			if(!file_exists($staticItem) || ((time() - filemtime($staticItem)) > $timeToCacheInSeconds)){
				FileSystemCachingStrategy::cacheItem($item,$staticItem);
			}	
		}
		
		function cacheAndRetrieve($item,$timeToCacheInSeconds){
			$staticItem = FileSystemCachingStrategy::STATIC_OUTPUT_DIRECTORY . $item . FileSystemCachingStrategy::STATIC_PAGE_EXTENSION;
			FileSystemCachingStrategy::cache($item,$timeToCacheInSeconds);
		 	//echo "staticfile:$staticItem filectime: ".filemtime($staticItem) ." dt: " . (time() - filemtime($staticItem)) ." " .$timeToCacheInSeconds ." ";
			return FileSystemCachingStrategy::retrieve($item);
		}
		
		function cacheItem($item,$staticItem){
			ob_start();
			include($item);
			$contents = ob_get_contents();
			ob_end_clean();
			file_put_contents($staticItem,$contents);
		}
		
		function retrieve($item){
			$staticItem = FileSystemCachingStrategy::STATIC_OUTPUT_DIRECTORY . $item . FileSystemCachingStrategy::STATIC_PAGE_EXTENSION;
			
			if(file_exists($staticItem)){
				$contents = readfile($staticItem);
				return $contents;
			}
		}
	}
	
	//echo Cache::getInstance()->get("page.php");
	
?>

Gruß Tom
 
Wieder etwas nicht bedacht ;)
Stimmt natürlich.

Ggf. könnte man nun natürlich noch testen, inwiefern es Performancegewinne gibt, wenn man statt auf das lokale Dateisystem wirklich per fsockopen() einen HTTP Request startet und sozusagen den Inhalt holt.
Könnte natürlich ein größeres Performanceloch schaffen, als es auszubügeln versucht, wenn das für jede Box passiert.

Hier mal ein etwas älterer Versuch von mir.

PHP:
class FlexCache {
	
	protected $_cache_lifetime;
	protected $_cache_file;
	protected $_error_log;
	protected $_path;
	
	public function __construct($error_log, $path, $lifetime = false, $cache_file = false, $ob = false) 
	{
		$this->_cache_lifetime = $lifetime;
		$this->_path = $path;
		$this->_cache_file = $path.$cache_file;
		$this->_error_log = $error_log;
		
		if($ob !== false) 
		{
			ob_start();
			header('Expires: ' . gmdate("D, d M Y H:i:s", time() + $this->_cache_lifetime) . ' GMT');
			header('Cache-Control: max-age='.$this->_cache_lifetime.'\n');
			header('Last-Modified: ' . @gmdate("D, d M Y H:i:s") . ' GMT');
		}
			
		if($this->checkCache() !== false) 
		{
			header('Last-Modified: ' . @gmdate("D, d M Y H:i:s", filemtime($this->_cache_file)) . ' GMT');
			$this->getCache();
			exit;
		}
	}
	protected function _createCache() 
	{
		try 
		{
			if(@file_put_contents($this->_cache_file, ob_get_contents(), LOCK_EX) === false)
			{
				throw new Exception("Error while writing Cache");
			}
		}
		catch(Exception $e)
		{
			$this->_logError($e->getMessage());
		}
		
	}
	public function writeCache($string, $identifier)
	{
		try 
		{
			if(@file_put_contents($this->_path.$identifier, $string, LOCK_EX) === false)
			{
				throw new Exception("Error while writing Cache");
			}
		}
		catch(Exception $e)
		{
			$this->_logError($e->getMessage());
		}
	}
	public function getCache($identifier = false) 
	{
		$identifier = ( $identifier === false ? $this->_cache_file : $this->_path.$identifier );
	
		try
		{
			if(($temp = @file_get_contents($identifier)) !== false)
			{
				return print($temp);
			}
			throw new Exception("Error while reading Cache");
		}
		catch(Exception $e)
		{
			$this->_logError($e->getMessage());
		}
		
	}
	public function emptyCache($complete = false)
	{
		foreach(glob($this->_path."*") as $filename)
		{
			echo $filename;
			unlink($filename);
		}
	}
	public function checkCache($lifetime = false, $identifier = false) 
	{
		$lifetime = ( $lifetime === false ? $this->_cache_lifetime : $lifetime );
		$cache_file = ( $identifier === false ? $this->_cache_file : $this->_path.$identifier );
		
		if(@file_exists($cache_file) === true 
		   && @filemtime($cache_file) >= (time() - $lifetime)
		   && @filesize($cache_file) != 0)
		{ 
				return true;
		}
		else 
		{
			return false;
		}
	}
	public function cache()
	{
		$this->_createCache();
		ob_end_flush();
	}
	protected function _logError($msg) 
	{
		@file_put_contents($this->_error_log, @date("d.m.y H:i").'-'.$msg."\n", FILE_APPEND);
	}
}

PHP:
<?php
error_reporting(E_ALL);
require_once("./FlexCache.class.php");

$path = "./tmp/";
$section = "index";
$error_log = "error.log";
$lifetime = "3600"; // 1h in seconds

$cache = new FlexCache($error_log, $path, $lifetime, $section, true);

for($i = 0; $i < 100; $i++) {
	echo ' Called for ' . $i . ' times<br/>';
}
$cache->cache();
?>

Es funktioniert, ist aber leider nicht die schönste Klasse ;)

/edit:
PHP:
function retrieve($item){
            $staticItem = FileSystemCachingStrategy::STATIC_OUTPUT_DIRECTORY . $item . FileSystemCachingStrategy::STATIC_PAGE_EXTENSION;
            
            if(file_exists($staticItem)){
                $contents = readfile($staticItem);
                return $contents;
            }
        }
Ich glaube das wird dir keinen Spaß bringen, weil readfile() direkt in den Ausgabepuffer schreibt.
 
Hallo,

dankefür die Tipps :)

Hmmm kann man da vielleicht was mit auto_prepend_file anfangen?
Kann man irgendwie in einem Script mitbekommen von welchem anderen Script man gerade inkludiert wird?
auto_prepend_file

This tells PHP to automatically tack on the file defined with this directive to the beginning of any file parsed by the PHP engine. This is very useful for defining global variables and making database connections.

Example:
Automatically prepend the file pre.php.
auto_prepend_file = pre.php

so update:
PHP:
<?php
	class Cache{
		
		private static $instance = null;
		
		private $resourceToCacheConfigurationMapping= array();

		
		function __construct(){
			Cache::register("page.php",new FileSystemCachingStrategy(), 10); //cache that page for 10 seconds (for the sake of testing ;-)
		}
		
		function register($item,ICachingStrategy $cachingStrategy,$timeToCacheInSeconds){
			$this->resourceToCacheConfigurationMapping[$item]= array($timeToCacheInSeconds,$cachingStrategy);
		}
		
		function get($item){
			if(isset($this->resourceToCacheConfigurationMapping[$item])){
				$timeToCacheWithStrategy = $this->resourceToCacheConfigurationMapping[$item];
				return $timeToCacheWithStrategy[1]->cacheAndRetrieve($item,$timeToCacheWithStrategy[0]);
			}
		}
		
		public static function getInstance(){
			if(self::$instance == null){
				self::$instance = new Cache();
			}
			return self::$instance;
		}
	}
	
	interface ICachingStrategy{
		function cache($item,$timeToCacheInSeconds);
		function retrieve($item);
		function cacheAndRetrieve($item,$timeToCacheInSeconds);
	}
	
	class MemoryCachingStrategy implements ICachingStrategy{
		function cache($item,$timeToCacheInSeconds){
			//todo
		}
		
		function retrieve($item){
			//todo
		}
		
		function cacheAndRetrieve($item,$timeToCacheInSeconds){
			//todo
		}
	}
	
	class FileSystemCachingStrategy implements ICachingStrategy{
		const STATIC_OUTPUT_DIRECTORY = "static/";
		const STATIC_PAGE_EXTENSION = ".static";
		
		function cacheAndRetrieve($item,$timeToCacheInSeconds){
			$staticItem = FileSystemCachingStrategy::STATIC_OUTPUT_DIRECTORY . $item . FileSystemCachingStrategy::STATIC_PAGE_EXTENSION;
			$this->cache($item,$timeToCacheInSeconds);
			return $this->retrieve($item);
		}
		
		function cache($item,$timeToCacheInSeconds){
			$staticItem = FileSystemCachingStrategy::STATIC_OUTPUT_DIRECTORY . $item . FileSystemCachingStrategy::STATIC_PAGE_EXTENSION;
			if(!file_exists($staticItem) || ((time() - filemtime($staticItem)) > $timeToCacheInSeconds)){
				$this->cacheItem($item,$staticItem);
			}	
		}
				
		function cacheItem($item,$staticItem){
			ob_start();
			include($item);
			$contents = ob_get_contents();
			ob_end_clean();
			file_put_contents($staticItem,$contents,LOCK_EX);
		}
		
		function retrieve($item){
			$staticItem = FileSystemCachingStrategy::STATIC_OUTPUT_DIRECTORY . $item . FileSystemCachingStrategy::STATIC_PAGE_EXTENSION;
			
			if(file_exists($staticItem)){
				return  file_get_contents($staticItem);
			}
		}
	}
	
	//echo Cache::getInstance()->get("page.php");
	
?>

Kleines Beispiel:
wenn man damit eine Datei bubu.php cachen will so legt man eine bubu_cached.php in dem selben Ordner an mit folgendem Inhalt:
PHP:
<?php
require_once 'caching.php';
echo Cache::getInstance()->get(str_replace("_cached","",basename(__file__)));
?>

Anschließend inkludiert man nur noch bubu_cached.php.
Die Konfiguration würde ich aber noch zentral machen. Vor allem müsste man noch über sinnvolle Defaults nachdenken.

Gruß Tom
 
Hmm,
auto_prepend_file hängt es ja grundsätzlich davor, sprich es wäre nicht nur für die Boxen aktiv, sondern für sämtliche PHP Dateien (es sei denn wir würden es per ini_set nur während der Generierung der Boxen anmachen... Aber das halte ich auch wieder für einen großen Eingriff). Das erzeugt m. M. n. wieder einen Overhead.
Da wäre ein kleiner require() in sämtlichen Boxen effektiver, vermute ich.
 
Hallo,

jo denke ich auch... am besten wäre wenn man sich an diesen Includemechanismus hängen könnte... gibts da keinen Handler den man registrieren kann um seinen eigenen Include Mechanismus zu bauen, oder der aufgerufen wird wenn ein bestimmtes Include nicht gefunden wird?
Gruß Tom
 
Das leider nicht, aber was wäre wenn, wenn wir die Caching Dateien etwas anders aufbauen, nämlich als Inhalt einer PHP Variable...

showroom_cached.php
PHP:
<?php
$var = '<div>showroom box</div>';
return $var;
?>

cache.php
PHP:
<?php
$showroom = @include('showroom_cached.php');
if($showroom !== false)
{
  echo $showroom;
}
else
{
  generateCacheAndView();
}
?>

Und per CronJob iteriert alle 1-2 Minuten ein Skript durch den Cache Ordner und löscht die alten Dateien.Mit Dateilock.
 
Hallo,

und wo liegt da der Vorteil? Meine Variante macht das ganze Lazy, also wenn niemand auf eine "box" zugreift wird ihre statische auch nicht (neu) generiert und ist noch entsprechend Konfigurierbar. Mach dazu doch mal ein kleines (komplettes) Beispiel so wie ich oben.


hier nochmal ein Update:
Im Verzeichnis /caching

Cache.class.php
PHP:
<?php
require_once("ICachingStrategy.class.php");

include("caching.config.php");

class Cache{
		private static $instance = null;
		private $resourceToCacheConfigurationMapping= array();
		private $cachingStrategyNameToStrategyMapping = array();
		private $defaultCachingStrategyName = "FileSystem";
		
		static function registerCachingStrategy($cachingStrategyName,$cachingStrategy){
			Cache::getInstance()->cachingStrategyNameToStrategyMapping[$cachingStrategyName]=$cachingStrategy;
		}
		
		function registerItem($item,$cachingStrategyName,$timeToCacheInSeconds){
   		    $currentCachingStrategy = $this->cachingStrategyNameToStrategyMapping[$cachingStrategyName];
			if(!isset($currentCachingStrategy)){
				$currentCachingStrategy=$this->cachingStrategyNameToStrategyMapping[$this->defaultCachingStrategyName];
			}
			$this->resourceToCacheConfigurationMapping[$item]= array($timeToCacheInSeconds,$currentCachingStrategy);
		}
		
		function getCached($item){
			if(isset($this->resourceToCacheConfigurationMapping[$item])){
				$timeToCacheWithStrategy = $this->resourceToCacheConfigurationMapping[$item];
				return $timeToCacheWithStrategy[1]->cacheAndRetrieve($item,$timeToCacheWithStrategy[0]);
			}
		}
		

		public static function getInstance(){
			if(self::$instance == null){
				self::$instance = new Cache();
			}
			return self::$instance;
		}
		
		
		/**
		 * Shortcut method
		 *
		 * @param unknown_type $item
		 */
		static function get($item){
			return Cache::getInstance()->getCached($item);
		}
		
		/**
		 * Shortcut method
		 *
		 * @param unknown_type $item
		 * @param ICachingStrategy $cachingStrategyName
		 * @param unknown_type $timeToCacheInSeconds
		 */
		static function register($item,$cachingStrategyName,$timeToCacheInSeconds){
			Cache::getInstance()->registerItem($item,$cachingStrategyName,$timeToCacheInSeconds);
		}
		
	}
	
	//echo Cache::getInstance()->get("page.php");
?>

ICachingStrategy.class.php:
PHP:
<?php
interface ICachingStrategy{
		function cache($item,$timeToCacheInSeconds);
		function retrieve($item);
		function cacheAndRetrieve($item,$timeToCacheInSeconds);
}
?>

FileSystemCachingStrategy.class.php
PHP:
<?php

class FileSystemCachingStrategy implements ICachingStrategy{
		const STATIC_OUTPUT_DIRECTORY = "static/";
		const STATIC_PAGE_EXTENSION = ".static";
		
		function cacheAndRetrieve($item,$timeToCacheInSeconds){
			$staticItem = FileSystemCachingStrategy::STATIC_OUTPUT_DIRECTORY . $item . FileSystemCachingStrategy::STATIC_PAGE_EXTENSION;
			$this->cache($item,$timeToCacheInSeconds);
			return $this->retrieve($item);
		}
		
		function cache($item,$timeToCacheInSeconds){
			$staticItem = FileSystemCachingStrategy::STATIC_OUTPUT_DIRECTORY . $item . FileSystemCachingStrategy::STATIC_PAGE_EXTENSION;
			if(!file_exists($staticItem) || ((time() - filemtime($staticItem)) > $timeToCacheInSeconds)){
				$this->cacheItem($item,$staticItem);
			}	
		}
				
		function cacheItem($item,$staticItem){
			ob_start();
			include($item);
			$contents = ob_get_contents();
			ob_end_clean();
			file_put_contents($staticItem,$contents,LOCK_EX);
		}
		
		function retrieve($item){
			$staticItem = FileSystemCachingStrategy::STATIC_OUTPUT_DIRECTORY . $item . FileSystemCachingStrategy::STATIC_PAGE_EXTENSION;
			
			if(file_exists($staticItem)){
				return  file_get_contents($staticItem);
			}
		}
}
?>

MemoryCachingStrategy.class.php
PHP:
<?php

class MemoryCachingStrategy implements ICachingStrategy{
		function cache($item,$timeToCacheInSeconds){
			//todo
		}
		
		function retrieve($item){
			//todo
		}
		
		function cacheAndRetrieve($item,$timeToCacheInSeconds){
			//todo
		}
}
?>

caching.config.php:
PHP:
<?php
require_once("FileSystemCachingStrategy.class.php");
require_once("MemoryCachingStrategy.class.php");

Cache::registerCachingStrategy("Memory",new MemoryCachingStrategy());
Cache::registerCachingStrategy("FileSystem",new FileSystemCachingStrategy());

Cache::register("page.php","FileSystem", 10); //cache that page for 10 seconds (for the sake of testing ;-)
?>

in /
template.php

PHP:
<?php

echo "A ";
include("page_cached.php");
echo " B";

?>

page.php:
PHP:
<?php

echo "<b>Current time: ". time() ." </b>\n";

?>

page_cached.php:
PHP:
<?php
require_once ("./caching/Cache.class.php");
echo Cache::get(str_replace("_cached","",basename(__file__)));
?>

in /static liegt dann beispielsweise:
page.php.static
HTML:
<b>Current time: 1206437690 </b>

Weis jemand wie die die MemoryCachingStrategy aussehen müsste?



Gruß Tom
 

Anhänge

Zurück