Gestion de cache

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

15 juin 2006, 19:13

Ne mettre que la partie du milieu en cache est absurde dans ce cas: seul le header et le footer vont dépendre de l'utilisateur ? À quoi donc sert-il d'être un utilisateur enregistré ? Si ça doit avoir la moindre utilité c'est que le changement est un peu plus important que "mon nom en haut à gauche". Il faut tout mettre en cache, ou rien.

Si on choisit de tout mettre en cache, la mise en cache doit donc dépendre :
- de l'url (et donc également de $_GET)
- de $_POST (retour de formulaire, à la rigueur on pourrait choisir de ne jamais mettre en cache les pages résultant d'un appel de formulaire en POST mais c'est discutable).
- de $_SESSION (un utilisateur n'a pas le même cache qu'un autre).
- de la date de génération du cache (et de sa date d'expiration)

Et voilà comment on recrée jpcache.

Ne fais pas les choses à moitié, et ne réinvente pas la poudre :)

Mammouth du PHP | 1511 Messages

16 juin 2006, 01:44

Ok je vais voir ca, mais ca fait très lourd tout de même, faut avoir de la place sur le serveur :?
Et sinon, au lieu du pseudo, on peut utiliser l'identifiant de session non(phpsessid)?
@+

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

16 juin 2006, 07:57

Non moi je te parle de $_SESSION au complet, pas du pseudo.

Un process de ce genre serait pas mal par exemple, code très rapide surtout pour comprendre le concept :
// variables de configuration (par défaut)
if (!isset($cache_dir))     $cache_dir = '/cache/'; // avec le '/' final
if (!isset($cache_gzip))    $cache_gzip = true; // compresser les fichiers cache
if (!isset($cache_timeout)) $cache_timeout = 3600; // durée de validité du fichier cache (secondes)

// on ne met pas en cache les pages résultant de formulaires
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    return false;
}

// calcul du nom du fichier cache (url, GET, SESSION, COOKIE)
$cache_filename = $cache_dir . md5(
    serialize($_SERVER['REQUEST_URI']) . 
    serialize($_SESSION) . 
    serialize($_COOKIE)
);

// fonction de construction du fichier cache
function build_cache($page_contents) {
    global $cache_filename, $cache_gzip;
    $fp = fopen($cache_filename, 'w');
    fputs($fp, $cache_gzip 
        ? gzcompress($page_contents,9) 
        : $page_contents
    );
    fclose($fp);
    return $page_contents;
}

// vérification de la date d'expiration du fichier cache
if (filemtime($cache_filename) + $cache_timeout < time()) {
    unlink($cache_filename);
}

// vérification de l'existence du fichier cache, et de sa date d'expiration
$cache_exists = file_exists($cache_filename);
$cache_expired = !$cache_exists ||
    filemtime($cache_filename)+$cache_timeout > time();
if (!$cache_exists || $cache_expired) {
    ob_start('build_cache');
    return false;
}

// sinon on ressert la page en cache
$cached_contents = file_get_contents($cache_filename);
if ($cache_gzip)
    $cached_contents = gzuncompress($cached_contents);
echo $cached_contents;
exit(0);
Pour activer la mise en cache d'un fichier il suffit d'inclure ce script au tout début. Pour personnaliser la mise en cache page par page, il suffit de définir les variables de configuration juste avant d'inclure le script. Ce script est une version très simplifiée de ce qu'effectue jpcache en gros.

J'attends maintenant tes questions sur les points que tu n'as pas compris ;)
Modifié en dernier par naholyr le 16 juin 2006, 12:13, modifié 1 fois.

Mammouth du PHP | 1511 Messages

16 juin 2006, 10:32

Juste un truc au niveau du
filemtime($cache_filename) + $cache_timeout > time()
Ce serait pas plutôt
filemtime($cache_filename) + $cache_timeout < time()
Sinon, tu garde les vieux caches et tu supprimes les bons...
Tant que la date de modif du fichier plus le timeout est superieure a time, c'est bon, mais c'est des que ca devient inférieur a time qu'il faut supprimer !
@+

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

16 juin 2006, 12:12

Tu as tout à fait raison, c'est une boulette, j'ai édité.

Mammouth du PHP | 1511 Messages

16 juin 2006, 16:18

Par contre, juste un truc, quel est l'avantage de la compression gzip?
De combien peut on esperer reduire son fichier par rapport a un fichier non-compressé?
@+

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

16 juin 2006, 16:32

Dans un fichier html classique, la compression est d'environ 80%. Cette efficacité vient du fait que beaucoup de suites de caractères sont souvent répétés à l'identique (toutes les balises) et ça se compresse donc très bien.

Si la gestion de cache te fait peur à cause de l'espace disque, tu peux donc passer par la compression gzip des fichiers cache.

De plus, ça ouvre la porte à une mise en place de la compression gzip du flux de communication directement au niveau de la gestion de cache : du coup dans le cas où la page est déjà en cache il suffit de la redonner telle quelle, pas besoin de décompresser (économie de cpu).
Modifié en dernier par naholyr le 16 juin 2006, 17:56, modifié 1 fois.

ViPHP
fab
ViPHP | 2657 Messages

16 juin 2006, 17:29

pour tester la compression d'une page : http://www.whatsmyip.org/mod_gzip_test/
Seul l'intelligent a le pouvoir de se trouver con
try { work(); } catch(FlemmeExeption $e) { sleep(84600); }

Mammouth du PHP | 1511 Messages

16 juin 2006, 18:02

Ca y est, j'ai fini la fonction cache() de ma class de templates :p
	function cache()
	{
		$replace = array('=', '?', '&');
		$id_string = md5(serialize(session_id()).serialize($_SESSION['user_id']));
		$url = $_SERVER['PHP_SELF'].'_'.$_SERVER['QUERY_STRING'].'_'.$id_string;
		$cache_file = 'cache/'.str_replace($replace, '_', $url).'.cache';
		$limite = '180';
		if(file_exists($cache_file))
		{
			if(filemtime($cache_file) + $limite < time())
			{
				unlink($cache_file);
				$cache = fopen($cache_file, 'w+');
				fputs($cache, gzcompress($this->template));

				fclose($cache);
			}
			elseif(filemtime($cache_file) + $limite > time())
			{
				$this->template = file_get_contents($url);
				$this->template = gzuncompress($this->template);
			}
		}
		elseif(!file_exists($cache_file))
		{
			$cache = fopen($cache_file, 'w+');
			fputs($cache, gzcompress($this->template));

			fclose($cache);
		}
	}
	function parse($echo = true)
	{
		if(!empty($this->error))
		{
			die($this->error);
		}
		if($this->enable_cache = true)
		{
			$this->cache()
		}
		else
		{
			$this->afficher_blocs();
			if($this->type == 'common')
			{
				
			}
			elseif($this->type == 'notification')
			{
				
			}
		}
	}
Ca correspond correctement?

Mammouth du PHP | 1511 Messages

26 sept. 2006, 22:06

Bonsoir,
je me permets de faire remonter un peu ce sujet, en vous montrant l'évolution de ma classe, et pour vous poser une pitite question.
Voici ma classe telle qu'elle est:
<?php
/*
cache.class.php
classe de cache
(c)2006 geekimo
Geekimo : [email protected]
*/
class cache
{
	private $cache_file_status;//status du fichier cache(true = fichier cache nickel, false = fichier cache a regenerer)
	private $cache_content;//contenu du cache si retour vers utilisateur ou remplissage du fichier cache
	private $cache_error;//variable d' erreurs
	private $cache_file;//variable du nom du fichier cache
	private $limite;//variable de limitation de durée du cache
	public function verif()
	{
		$replace = array('=', '?', '&');//caractéres a supprimer dans le nom du fichier cache
		$id_string = md5(serialize(session_id()).serialize($_SESSION['user_id']));//composition de l'id du fichier cache
		$url = $_SERVER['PHP_SELF'].'_'.$_SERVER['QUERY_STRING'].'_'.$id_string;//compositin du nom du fichier cache
		$this->cache_file = 'cache/'.str_replace($replace, '_', $url).'.cache';//url du fichier cache
		$this->limite = '120';//durée du cache en secondes
		if(file_exists($this->cache_file))
		{
			if(filemtime($this->cache_file) + $this->limite < time())//test si peremtion du fichier est inférieure a date actuelle, si oui, cache invalide
			{
				$this->cache_file_status = false;// le fichier cache n'est pas bon
			}
			elseif(filemtime($this->cache_file) + $this->limite > time())//test si peremtion du fichier est supérieure a date actuelle, si oui, cache valide
			{
				$this->cache_file_status = true;// le fichier cache est ok
			}
		}
		elseif(!file_exists($this->cache_file))
		{
			$this->cache_file_status = false;// le fichier cache n'est pas bon
		}
		return $this->cache_file_status;
	}
	public function get($echo)
	{
		if(!empty($this->cache_file_status))
		{
			if($this->cache_file_status)
			{
				$this->cache_content = file_get_contents($this->cache_file);	
			}
			elseif(!$this->cache_file_status)
			{
				throw new Exception('le fichier cache est périmé, la fonction $this->get() ne peut donc pas être utilisée!<br />');
			}
			if($echo)
			{
				echo $this->cache_content;
			}
			else
			{
				return $this->cache_content;
			}
		}
		elseif(empty($this->cache_file_status))
		{
			throw new Exception('Le fichier cache n\'a pas été testé avant d\'utiliser $this->get(), vous devez utiliser $this->verif<br />');
		}
	}
	public function store($template)
	{
		if(is_bool($this->cache_file_status))
		{
			if($this->cache_file_status)
			{
				throw new Exception('Le fichier cache n\'est pas périmé, la fonction $this->store() ne peut donc pas être utilisée! <br />');
			}
			elseif(!$this->cache_file_status)
			{
				if(file_exists($this->cache_file))
				{
					unlink($this->cache_file);
				}			
				$cache = fopen($this->cache_file, 'w+');
				fputs($cache, gzcompress($template));
				$cache_store = fclose($cache);
				if($cache_store)
				{
					return true;
				}
				else
				{
					return false;
				}
			}
		}
		elseif(!is_bool($this->cache_file_status))
		{
			throw new Exception('Le fichier cache n\'a pas été testé avant d\'utiliser $this->store(), vous devez utiliser $this->verif<br />');
		}
	}
	public function clear()
	{
		$this->limite_cache = 3;
		$index_cache = get_file('cache/', '*.cache');
		$limit = count($index_cache);
		for($i = 0;$i != $limit; $i++)
		{
			if(filemtime($index_cache['name']) + $this->limite < time())
			{
				unlink($index_cache['name']);
			}
		}
	}
}
?>
Actuellement, elle est en version pré-finale et je me pose une petite question car j'ai fait quelques tests et j'ai quelques problèmes au niveau de l'id de session...
Celui-ci change t'il constamment a chaque nouvelle page?
Car après avoir fait un joli F5 sur ma page en de test dans un temps inférieur au timeout prévu ($this->limite), je me suis retrouvé avec un second fichier cache...
Je vous remercie donc d'avance pour l'aide que vous pourriez m'apporter.
@+ ;)

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

26 sept. 2006, 22:27

Je n'ai pas la réponse à tes questions car je n'ai fait que survoler ton post mais un passage a attiré mon attention:
if(file_exists($this->cache_file))
{
	if(filemtime($this->cache_file) + $this->limite < time())
	{
		$this->cache_file_status = false;
	}
	elseif(filemtime($this->cache_file) + $this->limite > time())
	{
		$this->cache_file_status = true;
	}
}
elseif(!file_exists($this->cache_file))
{
	$this->cache_file_status = false;
}
J'ai retiré les commentaires pour des questions de lisibilité (au passage, je recommande vraiment de mettre les commentaires sur leur propre ligne et avant le code en question).

Pour commencer, tu n'as pas besoin d'utiliser elseif, des else fonctionneraient parfaitement. Si la condition de if est fausse, inutile de vérifier qu'elle est bien fausse dans un elseif. Si on est dans le else alors on sait que l'expression de if est fausse.

...ce qui m'amène à l'autre erreur de ce code:
if(filemtime($this->cache_file) + $this->limite < time())
{
	$this->cache_file_status = false;
}
elseif(filemtime($this->cache_file) + $this->limite > time())
{
	$this->cache_file_status = true;
}
D'abord tu testes si le cache est plus vieux que la "date limite de validité", puis tu vérifies s'il est plus récent que cette même date... que se passe-t'il s'il est égal à cette date ? Je pense que ce que tu voulais faire est:
if(filemtime($this->cache_file) + $this->limite < time())
{
	// Timestamp plus ancien que la date fatidique
	$this->cache_file_status = false;
}
else
{
	// Timestamp égal ou supérieur
	$this->cache_file_status = true;
}
D'ailleurs, on pourrait le résumer à cette ligne: (le (bool) est optionnel)
$this->cache_file_status = (bool) (filemtime($this->cache_file) + $this->limite >= time());
(rappel: le contraire de < c'est >=, pas >)

Pour le reste, je n'ai pas vraiment regardé mais ça peut être lié au bug ci-dessus.