Subversion Repositories Applications.framework

Rev

Rev 291 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 291 Rev 299
1
<?php
1
<?php
2
// declare(encoding='UTF-8');
2
// declare(encoding='UTF-8');
3
/**
3
/**
4
 * Classe Cache permettant de mettre en cache des données.
4
 * Classe Cache permettant de mettre en cache des données.
5
 * Basée sur les principes de Zend_Cache (Copyright (c) 2005-2010, Zend Technologies USA, Inc. All rights reserved.)
5
 * Basée sur les principes de Zend_Cache (Copyright (c) 2005-2010, Zend Technologies USA, Inc. All rights reserved.)
6
 *
6
 *
7
 * @category	php 5.2
7
 * @category	php 5.2
8
 * @package	Framework
8
 * @package	Framework
9
 * @author		Jean-Pascal MILCENT <jpm@tela-botanica.org>
9
 * @author		Jean-Pascal MILCENT <jpm@tela-botanica.org>
10
 * @copyright	Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
10
 * @copyright	Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
11
 * @license	http://framework.zend.com/license/new-bsd Licence New BSD
11
 * @license	http://framework.zend.com/license/new-bsd Licence New BSD
12
 * @license	http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
12
 * @license	http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
13
 * @license	http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
13
 * @license	http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
14
 * @version	$Id$
14
 * @version	$Id: Cache.php 299 2011-01-18 14:03:46Z jpm $
15
 * @link		/doc/framework/
15
 * @link		/doc/framework/
16
 */
16
 */
17
class Cache {
17
class Cache {
18
	/** Socke les enregistrements du cache dans des fichiers textes de façon extremement simple. */
18
	/** Socke les enregistrements du cache dans des fichiers textes de façon extremement simple. */
19
	const STOCKAGE_MODE_SIMPLE = "FichierSimple";
19
	const STOCKAGE_MODE_SIMPLE = "FichierSimple";
20
	/** Socke les enregistrements du cache dans des fichiers textes. */
20
	/** Socke les enregistrements du cache dans des fichiers textes. */
21
	const STOCKAGE_MODE_FICHIER = "Fichier";
21
	const STOCKAGE_MODE_FICHIER = "Fichier";
22
	/** Socke les enregistrements du cache dans une base de données SQLite. */
22
	/** Socke les enregistrements du cache dans une base de données SQLite. */
23
	const STOCKAGE_MODE_SQLITE = "Sqlite";
23
	const STOCKAGE_MODE_SQLITE = "Sqlite";
24
	
24
	
25
	/** 'tous' (par défaut) : supprime tous les enregistrements. */
25
	/** 'tous' (par défaut) : supprime tous les enregistrements. */
26
	const NETTOYAGE_MODE_TOUS = "tous";
26
	const NETTOYAGE_MODE_TOUS = "tous";
27
	/** 'expiration' : supprime tous les enregistrements dont la date d'expériration est dépassée. */
27
	/** 'expiration' : supprime tous les enregistrements dont la date d'expériration est dépassée. */
28
	const NETTOYAGE_MODE_EXPIRATION = "expiration";
28
	const NETTOYAGE_MODE_EXPIRATION = "expiration";
29
	/** 'avecLesTags' : supprime tous les enregistrements contenant tous les tags indiqués. */
29
	/** 'avecLesTags' : supprime tous les enregistrements contenant tous les tags indiqués. */
30
	const NETTOYAGE_MODE_AVEC_LES_TAGS = "avecLesTags";
30
	const NETTOYAGE_MODE_AVEC_LES_TAGS = "avecLesTags";
31
	/** 'sansLesTags' : supprime tous les enregistrements contenant aucun des tags indiqués. */
31
	/** 'sansLesTags' : supprime tous les enregistrements contenant aucun des tags indiqués. */
32
	const NETTOYAGE_MODE_SANS_LES_TAGS = "sansLesTags";
32
	const NETTOYAGE_MODE_SANS_LES_TAGS = "sansLesTags";
33
	/** 'avecUnTag' : supprime tous les enregistrements contenant au moins un des tags indiqués. */
33
	/** 'avecUnTag' : supprime tous les enregistrements contenant au moins un des tags indiqués. */
34
	const NETTOYAGE_MODE_AVEC_UN_TAG = "avecUnTag";
34
	const NETTOYAGE_MODE_AVEC_UN_TAG = "avecUnTag";
35
	
35
	
36
	/**
36
	/**
37
	 * Dernier identifiant de cache utilisé.
37
	 * Dernier identifiant de cache utilisé.
38
	 *
38
	 *
39
	 * @var string $dernier_id
39
	 * @var string $dernier_id
40
	 */
40
	 */
41
	private $dernier_id = null;
41
	private $dernier_id = null;
42
	
42
	
43
	/**
43
	/**
44
	 * Les options disponibles pour le cache :
44
	 * Les options disponibles pour le cache :
45
	 * ====> (string) stockage_mode :
45
	 * ====> (string) stockage_mode :
46
	 * Indique le mode de stockage du cache à utiliser parmis :
46
	 * Indique le mode de stockage du cache à utiliser parmis :
47
	 * - Cache::STOCKAGE_MODE_FICHIER : sous forme d'une arborescence de fichiers et dossier
47
	 * - Cache::STOCKAGE_MODE_FICHIER : sous forme d'une arborescence de fichiers et dossier
48
	 * - Cache::STOCKAGE_MODE_SQLITE : sous forme d'une base de données SQLite
48
	 * - Cache::STOCKAGE_MODE_SQLITE : sous forme d'une base de données SQLite
49
	 * 
49
	 * 
50
	 * ====> (string) stockage_chemin :
50
	 * ====> (string) stockage_chemin :
51
	 * Chemin vers :
51
	 * Chemin vers :
52
	 * - Cache::STOCKAGE_MODE_FICHIER : le dossier devant contenir l'arborescence.
52
	 * - Cache::STOCKAGE_MODE_FICHIER : le dossier devant contenir l'arborescence.
53
	 * - Cache::STOCKAGE_MODE_SQLITE : le fichier contenant la base SQLite.
53
	 * - Cache::STOCKAGE_MODE_SQLITE : le fichier contenant la base SQLite.
54
	 * 
54
	 * 
55
	 * ====> (boolean) controle_ecriture :
55
	 * ====> (boolean) controle_ecriture :
56
	 * - Active / Désactive le controle d'écriture (le cache est lue jute après l'écriture du fichier pour détecter sa corruption)
56
	 * - Active / Désactive le controle d'écriture (le cache est lue jute après l'écriture du fichier pour détecter sa corruption)
57
	 * - Activer le controle d'écriture ralentira légèrement l'écriture du fichier de cache mais pas sa lecture
57
	 * - Activer le controle d'écriture ralentira légèrement l'écriture du fichier de cache mais pas sa lecture
58
	 * Le controle d'écriture peut détecter la corruption de fichier mais ce n'est pas un système de controle parfait.
58
	 * Le controle d'écriture peut détecter la corruption de fichier mais ce n'est pas un système de controle parfait.
59
	 *
59
	 *
60
	 * ====> (boolean) mise_en_cache :
60
	 * ====> (boolean) mise_en_cache :
61
	 * - Active / Désactive la mise en cache
61
	 * - Active / Désactive la mise en cache
62
	 * (peut être très utile pour le débogage des scripts utilisant le cache
62
	 * (peut être très utile pour le débogage des scripts utilisant le cache
63
	 *
63
	 *
64
	 * =====> (string) cache_id_prefixe :
64
	 * =====> (string) cache_id_prefixe :
65
	 * - préfixe pour les identifiant de cache ( = espace de nom)
65
	 * - préfixe pour les identifiant de cache ( = espace de nom)
66
	 *
66
	 *
67
	 * ====> (boolean) serialisation_auto :
67
	 * ====> (boolean) serialisation_auto :
68
	 * - Active / Désactive la sérialisation automatique
68
	 * - Active / Désactive la sérialisation automatique
69
	 * - Peut être utilisé pour sauver directement des données qui ne sont pas des chaines (mais c'est plus lent)
69
	 * - Peut être utilisé pour sauver directement des données qui ne sont pas des chaines (mais c'est plus lent)
70
	 *
70
	 *
71
	 * ====> (int) nettoyage_auto :
71
	 * ====> (int) nettoyage_auto :
72
	 * - Désactive / Régler le processus de nettoyage automatique
72
	 * - Désactive / Régler le processus de nettoyage automatique
73
	 * - Le processus de nettoyage automatiques détruit les fichier trop vieux (pour la durée de vie donnée)
73
	 * - Le processus de nettoyage automatiques détruit les fichier trop vieux (pour la durée de vie donnée)
74
	 *   quand un nouveau fichier de cache est écrit :
74
	 *   quand un nouveau fichier de cache est écrit :
75
	 *	 0			   => pas de nettoyage automatique
75
	 *	 0			   => pas de nettoyage automatique
76
	 *	 1			   => nettoyage automatique systématique
76
	 *	 1			   => nettoyage automatique systématique
77
	 *	 x (integer) > 1 => nettoyage automatique toutes les 1 fois (au hasard) sur x écriture de fichier de cache
77
	 *	 x (integer) > 1 => nettoyage automatique toutes les 1 fois (au hasard) sur x écriture de fichier de cache
78
	 *
78
	 *
79
	 * ====> (int) duree_de_vie :
79
	 * ====> (int) duree_de_vie :
80
	 * - Durée de vie du cache (en secondes)
80
	 * - Durée de vie du cache (en secondes)
81
	 * - Si null, le cache est valide indéfiniment.
81
	 * - Si null, le cache est valide indéfiniment.
82
	 *
82
	 *
83
	 * @var array $options les options disponibles pour le cache .
83
	 * @var array $options les options disponibles pour le cache .
84
	 */
84
	 */
85
	protected $options = array(
85
	protected $options = array(
86
		'stockage_mode'				 => self::STOCKAGE_MODE_FICHIER,
86
		'stockage_mode'				 => self::STOCKAGE_MODE_FICHIER,
87
		'stockage_chemin'				 => null,	
87
		'stockage_chemin'				 => null,	
88
		'controle_ecriture'			 => true,
88
		'controle_ecriture'			 => true,
89
		'mise_en_cache'		  		 => true,
89
		'mise_en_cache'		  		 => true,
90
		'cache_id_prefixe'		  		 => null,
90
		'cache_id_prefixe'		  		 => null,
91
		'serialisation_auto'		  	 => false,
91
		'serialisation_auto'		  	 => false,
92
		'nettoyage_auto'				 => 10,
92
		'nettoyage_auto'				 => 10,
93
		'duree_de_vie'			 		 => 3600,
93
		'duree_de_vie'			 		 => 3600,
94
	);
94
	);
95
	
95
	
96
	protected $stockage = null;
96
	protected $stockage = null;
97
	
97
	
98
	public function __construct($options = array(), $options_stockage = array()) {
98
	public function __construct($options = array(), $options_stockage = array()) {
99
		$this->initialiserOptionsParConfig();
99
		$this->initialiserOptionsParConfig();
100
		$this->setOptions($options);
100
		$this->setOptions($options);
101
		if ($this->options['stockage_mode'] == self::STOCKAGE_MODE_FICHIER) {
101
		if ($this->options['stockage_mode'] == self::STOCKAGE_MODE_FICHIER) {
102
			$this->stockage = new CacheFichier($options_stockage, $this);
102
			$this->stockage = new CacheFichier($options_stockage, $this);
103
			$this->stockage->setEmplacement($this->options['stockage_chemin']);
103
			$this->stockage->setEmplacement($this->options['stockage_chemin']);
104
		} else if ($this->options['stockage_mode'] == self::STOCKAGE_MODE_SQLITE) {
104
		} else if ($this->options['stockage_mode'] == self::STOCKAGE_MODE_SQLITE) {
105
			$this->stockage = new CacheSqlite($options_stockage, $this);
105
			$this->stockage = new CacheSqlite($options_stockage, $this);
106
			$this->stockage->setEmplacement($this->options['stockage_chemin']);
106
			$this->stockage->setEmplacement($this->options['stockage_chemin']);
107
		} else {
107
		} else {
108
			trigger_error("Ce mode de stockage n'existe pas ou ne supporte pas la création par le constructeur", E_USER_WARNING);
108
			trigger_error("Ce mode de stockage n'existe pas ou ne supporte pas la création par le constructeur", E_USER_WARNING);
109
		}
109
		}
110
	}
110
	}
111
	
111
	
112
	private function initialiserOptionsParConfig() {
112
	private function initialiserOptionsParConfig() {
113
		while (list($nom, $valeur) = each($this->options)) {
113
		while (list($nom, $valeur) = each($this->options)) {
114
			if (Config::existe($nom)) {
114
			if (Config::existe($nom)) {
115
				$this->options[$nom] = Config::get($nom);
115
				$this->options[$nom] = Config::get($nom);
116
			}
116
			}
117
		}
117
		}
118
	}
118
	}
119
	
119
	
120
	private function setOptions($options) {
120
	private function setOptions($options) {
121
		while (list($nom, $valeur) = each($options)) {
121
		while (list($nom, $valeur) = each($options)) {
122
			if (!is_string($nom)) {
122
			if (!is_string($nom)) {
123
				trigger_error("Nom d'option incorecte : $nom", E_USER_WARNING);
123
				trigger_error("Nom d'option incorecte : $nom", E_USER_WARNING);
124
			}
124
			}
125
			$nom = strtolower($nom);
125
			$nom = strtolower($nom);
126
			if (array_key_exists($nom, $this->options)) {
126
			if (array_key_exists($nom, $this->options)) {
127
				$this->options[$nom] = $valeur;
127
				$this->options[$nom] = $valeur;
128
			}
128
			}
129
		}
129
		}
130
	}
130
	}
131
	
131
	
132
	/**
132
	/**
133
	 * Permet de (re-)définir l'emplacement pour le stockage du cache.
133
	 * Permet de (re-)définir l'emplacement pour le stockage du cache.
134
	 * En fonction du mode de stockage utilisé , l'emplacement indiqué correspondra au chemin du :
134
	 * En fonction du mode de stockage utilisé , l'emplacement indiqué correspondra au chemin du :
135
	 *  - dossier où stocker les fichiers pour le mode "fichier".
135
	 *  - dossier où stocker les fichiers pour le mode "fichier".
136
	 *  - fichier de la base de données pour le mode "sqlite". 
136
	 *  - fichier de la base de données pour le mode "sqlite". 
137
	 * @param string $emplacement chemin vers dossier (Cache::STOCKAGE_MODE_FICHIER) ou fichier base Sqlite (Cache::STOCKAGE_MODE_SQLITE)
137
	 * @param string $emplacement chemin vers dossier (Cache::STOCKAGE_MODE_FICHIER) ou fichier base Sqlite (Cache::STOCKAGE_MODE_SQLITE)
138
	 * @return void 
138
	 * @return void 
139
	 */
139
	 */
140
	public function setEmplacement($emplacement) {
140
	public function setEmplacement($emplacement) {
141
		if ($emplacement != null) {
141
		if ($emplacement != null) {
142
			$this->executerMethodeStockage('setEmplacement', array($emplacement));
142
			$this->executerMethodeStockage('setEmplacement', array($emplacement));
143
		} else {
143
		} else {
144
			trigger_error("L'emplacement ne peut pas être null.", E_USER_WARNING);
144
			trigger_error("L'emplacement ne peut pas être null.", E_USER_WARNING);
145
		}
145
		}
146
	}
146
	}
147
	
147
	
148
	public static function fabriquer($mode, $options = array()) {
148
	public static function fabriquer($mode, $options = array()) {
149
		if ($mode == self::STOCKAGE_MODE_SIMPLE) {
149
		if ($mode == self::STOCKAGE_MODE_SIMPLE) {
150
			return new CacheSimple($options);
150
			return new CacheSimple($options);
151
		} else {
151
		} else {
152
			trigger_error("Le mode '$mode' de stockage n'existe pas ou ne supporte pas la création par fabrique", E_USER_WARNING);
152
			trigger_error("Le mode '$mode' de stockage n'existe pas ou ne supporte pas la création par fabrique", E_USER_WARNING);
153
		}
153
		}
154
		return false;
154
		return false;
155
	}
155
	}
156
	
156
	
157
	/**
157
	/**
158
	 * Teste si un cache est disponible pour l'identifiant donné et (si oui) le retourne (false dans le cas contraire)
158
	 * Teste si un cache est disponible pour l'identifiant donné et (si oui) le retourne (false dans le cas contraire)
159
	 *
159
	 *
160
	 * @param  string  $id Identifiant de cache.
160
	 * @param  string  $id Identifiant de cache.
161
	 * @param  boolean $ne_pas_tester_validiter_du_cache Si mis à true, la validité du cache n'est pas testée
161
	 * @param  boolean $ne_pas_tester_validiter_du_cache Si mis à true, la validité du cache n'est pas testée
162
	 * @return mixed|false Cached datas
162
	 * @return mixed|false Cached datas
163
	 */
163
	 */
164
	public function charger($id, $ne_pas_tester_validiter_du_cache = false) {
164
	public function charger($id, $ne_pas_tester_validiter_du_cache = false) {
165
		$donnees = false;
165
		$donnees = false;
166
		if ($this->options['mise_en_cache'] === true) {
166
		if ($this->options['mise_en_cache'] === true) {
167
			$id = $this->prefixerId($id);
167
			$id = $this->prefixerId($id);
168
			$this->dernier_id = $id;
168
			$this->dernier_id = $id;
169
			self::validerIdOuTag($id);
169
			self::validerIdOuTag($id);
170
			$donnees = $this->executerMethodeStockage('charger', array($id, $ne_pas_tester_validiter_du_cache));
170
			$donnees = $this->executerMethodeStockage('charger', array($id, $ne_pas_tester_validiter_du_cache));
171
			$donnees = $this->deserialiserAutomatiquement($donnees);
171
			$donnees = $this->deserialiserAutomatiquement($donnees);
172
		}
172
		}
173
		return $donnees;
173
		return $donnees;
174
	}
174
	}
175
	
175
	
176
	/**
176
	/**
177
	 * Test if a cache is available for the given id
177
	 * Test if a cache is available for the given id
178
	 *
178
	 *
179
	 * @param  string $id Cache id
179
	 * @param  string $id Cache id
180
	 * @return int|false Last modified time of cache entry if it is available, false otherwise
180
	 * @return int|false Last modified time of cache entry if it is available, false otherwise
181
	 */
181
	 */
182
	public function tester($id) {
182
	public function tester($id) {
183
		$resultat = false;
183
		$resultat = false;
184
		if ($this->options['mise_en_cache'] === true) {
184
		if ($this->options['mise_en_cache'] === true) {
185
		  	$id = $this->prefixerId($id);
185
		  	$id = $this->prefixerId($id);
186
			self::validerIdOuTag($id);
186
			self::validerIdOuTag($id);
187
			$this->dernier_id = $id;
187
			$this->dernier_id = $id;
188
			$resultat = $this->executerMethodeStockage('tester', array($id));
188
			$resultat = $this->executerMethodeStockage('tester', array($id));
189
		}
189
		}
190
		return $resultat;
190
		return $resultat;
191
	}
191
	}
192
	
192
	
193
	/**
193
	/**
194
	 * Sauvegarde en cache les données passées en paramètre.
194
	 * Sauvegarde en cache les données passées en paramètre.
195
	 *
195
	 *
196
	 * @param  mixed $donnees Données à mettre en cache (peut être différent d'une chaine si serialisation_auto vaut true).
196
	 * @param  mixed $donnees Données à mettre en cache (peut être différent d'une chaine si serialisation_auto vaut true).
197
	 * @param  string $id	 Identifiant du cache (s'il n'est pas définit, le dernier identifiant sera utilisé).
197
	 * @param  string $id	 Identifiant du cache (s'il n'est pas définit, le dernier identifiant sera utilisé).
198
	 * @param  array $tags Mots-clés du cache.
198
	 * @param  array $tags Mots-clés du cache.
199
	 * @param  int $duree_de_vie_specifique Si != false, indique une durée de vie spécifique pour cet enregistrement en cache (null => durée de vie infinie)
199
	 * @param  int $duree_de_vie_specifique Si != false, indique une durée de vie spécifique pour cet enregistrement en cache (null => durée de vie infinie)
200
	 * @return boolean True si aucun problème n'est survenu.
200
	 * @return boolean True si aucun problème n'est survenu.
201
	 */
201
	 */
202
	public function sauver($donnees, $id = null, $tags = array(), $duree_de_vie_specifique = false) {
202
	public function sauver($donnees, $id = null, $tags = array(), $duree_de_vie_specifique = false) {
203
		$resultat = true;
203
		$resultat = true;
204
		if ($this->options['mise_en_cache'] === true) {
204
		if ($this->options['mise_en_cache'] === true) {
205
			$id = ($id === null) ? $this->dernier_id : $this->prefixerId($id);
205
			$id = ($id === null) ? $this->dernier_id : $this->prefixerId($id);
206
	
206
	
207
			self::validerIdOuTag($id);
207
			self::validerIdOuTag($id);
208
			self::validerTableauDeTags($tags);
208
			self::validerTableauDeTags($tags);
209
			$donnees = $this->serialiserAutomatiquement($donnees);
209
			$donnees = $this->serialiserAutomatiquement($donnees);
210
			$this->nettoyerAutomatiquement();
210
			$this->nettoyerAutomatiquement();
211
			
211
			
212
			$resultat = $this->executerMethodeStockage('sauver', array($donnees, $id, $tags, $duree_de_vie_specifique));
212
			$resultat = $this->executerMethodeStockage('sauver', array($donnees, $id, $tags, $duree_de_vie_specifique));
213
			
213
			
214
			if ($resultat == false) {
214
			if ($resultat == false) {
215
				// Le cache étant peut être corrompu, nous le supprimons
215
				// Le cache étant peut être corrompu, nous le supprimons
216
				$this->supprimer($id);
216
				$this->supprimer($id);
217
			} else {
217
			} else {
218
				$resultat = $this->controlerEcriture($id, $donnees);
218
				$resultat = $this->controlerEcriture($id, $donnees);
219
			}
219
			}
220
		}
220
		}
221
		return $resultat;
221
		return $resultat;
222
	}
222
	}
223
	
223
	
224
	/**
224
	/**
225
	 * Supprime un enregistrement en cache.
225
	 * Supprime un enregistrement en cache.
226
	 *
226
	 *
227
	 * @param  string $id Identificant du cache à supprimer.
227
	 * @param  string $id Identificant du cache à supprimer.
228
	 * @return boolean True si ok
228
	 * @return boolean True si ok
229
	 */
229
	 */
230
	public function supprimer($id) {
230
	public function supprimer($id) {
231
		$resultat = true;
231
		$resultat = true;
232
		if ($this->options['mise_en_cache'] === true) {
232
		if ($this->options['mise_en_cache'] === true) {
233
			$id = $this->prefixerId($id);
233
			$id = $this->prefixerId($id);
234
			self::validerIdOuTag($id);
234
			self::validerIdOuTag($id);
235
		   $resultat = $this->executerMethodeStockage('supprimer', array($id));
235
		   $resultat = $this->executerMethodeStockage('supprimer', array($id));
236
		}
236
		}
237
		return $resultat;
237
		return $resultat;
238
	}
238
	}
239
	
239
	
240
	/**
240
	/**
241
	 * Nettoyage des enregistrements en cache
241
	 * Nettoyage des enregistrements en cache
242
	 * 
242
	 * 
243
	 * Mode de nettoyage disponibles :
243
	 * Mode de nettoyage disponibles :
244
	 * 'tous' (défaut)	=> supprime tous les enregistrements ($tags n'est pas utilisé)
244
	 * 'tous' (défaut)	=> supprime tous les enregistrements ($tags n'est pas utilisé)
245
	 * 'expiration'		=> supprime tous les enregistrements dont la date d'expériration est dépassée ($tags n'est pas utilisé)
245
	 * 'expiration'		=> supprime tous les enregistrements dont la date d'expériration est dépassée ($tags n'est pas utilisé)
246
	 * 'avecLesTag'		=> supprime tous les enregistrements contenant tous les tags indiqués
246
	 * 'avecLesTag'		=> supprime tous les enregistrements contenant tous les tags indiqués
247
	 * 'sansLesTag'		=> supprime tous les enregistrements contenant aucun des tags indiqués
247
	 * 'sansLesTag'		=> supprime tous les enregistrements contenant aucun des tags indiqués
248
	 * 'avecUnTag'			=> supprime tous les enregistrements contenant au moins un des tags indiqués
248
	 * 'avecUnTag'			=> supprime tous les enregistrements contenant au moins un des tags indiqués
249
	 *
249
	 *
250
	 * @param string $mode mode de nettoyage
250
	 * @param string $mode mode de nettoyage
251
	 * @param array|string $tags peut être un tableau de chaîne ou une simple chaine.
251
	 * @param array|string $tags peut être un tableau de chaîne ou une simple chaine.
252
	 * @return boolean True si ok
252
	 * @return boolean True si ok
253
	 */
253
	 */
254
	public function nettoyer($mode = self::NETTOYAGE_MODE_TOUS, $tags = array()) {
254
	public function nettoyer($mode = self::NETTOYAGE_MODE_TOUS, $tags = array()) {
255
		$resultat = true;
255
		$resultat = true;
256
		if ($this->options['mise_en_cache'] === true) {
256
		if ($this->options['mise_en_cache'] === true) {
257
			if (!in_array($mode, array(Cache::NETTOYAGE_MODE_TOUS,
257
			if (!in_array($mode, array(Cache::NETTOYAGE_MODE_TOUS,
258
				Cache::NETTOYAGE_MODE_EXPIRATION,
258
				Cache::NETTOYAGE_MODE_EXPIRATION,
259
				Cache::NETTOYAGE_MODE_AVEC_LES_TAGS,
259
				Cache::NETTOYAGE_MODE_AVEC_LES_TAGS,
260
				Cache::NETTOYAGE_MODE_SANS_LES_TAGS,
260
				Cache::NETTOYAGE_MODE_SANS_LES_TAGS,
261
				Cache::NETTOYAGE_MODE_AVEC_UN_TAG))) {
261
				Cache::NETTOYAGE_MODE_AVEC_UN_TAG))) {
262
				trigger_error("Le mode de nettoyage du cache indiqué n'est pas valide", E_USER_WARNING);
262
				trigger_error("Le mode de nettoyage du cache indiqué n'est pas valide", E_USER_WARNING);
263
			}
263
			}
264
			self::validerTableauDeTags($tags);
264
			self::validerTableauDeTags($tags);
265
			
265
			
266
			$resultat = $this->executerMethodeStockage('nettoyer', array($mode, $tags));
266
			$resultat = $this->executerMethodeStockage('nettoyer', array($mode, $tags));
267
		}
267
		}
268
		return $resultat;
268
		return $resultat;
269
	}
269
	}
270
 
270
 
271
	/**
271
	/**
272
	 * Return an array of stored cache ids
272
	 * Return an array of stored cache ids
273
	 *
273
	 *
274
	 * @return array array of stored cache ids (string)
274
	 * @return array array of stored cache ids (string)
275
	 */
275
	 */
276
	public function getIds() {
276
	public function getIds() {
277
		$ids = $this->executerMethodeStockage('getIds');
277
		$ids = $this->executerMethodeStockage('getIds');
278
		$ids = $this->supprimerPrefixe($ids);
278
		$ids = $this->supprimerPrefixe($ids);
279
		return $ids;
279
		return $ids;
280
	}
280
	}
281
 
281
 
282
	/**
282
	/**
283
	 * Return an array of stored tags
283
	 * Return an array of stored tags
284
	 *
284
	 *
285
	 * @return array array of stored tags (string)
285
	 * @return array array of stored tags (string)
286
	 */
286
	 */
287
	public function getTags() {
287
	public function getTags() {
288
		return $this->executerMethodeStockage('getTags');
288
		return $this->executerMethodeStockage('getTags');
289
	}
289
	}
290
	
290
	
291
	/**
291
	/**
292
	 * Return an array of stored cache ids which match given tags
292
	 * Return an array of stored cache ids which match given tags
293
	 *
293
	 *
294
	 * In case of multiple tags, a logical AND is made between tags
294
	 * In case of multiple tags, a logical AND is made between tags
295
	 *
295
	 *
296
	 * @param array $tags array of tags
296
	 * @param array $tags array of tags
297
	 * @return array array of matching cache ids (string)
297
	 * @return array array of matching cache ids (string)
298
	 */
298
	 */
299
	public function getIdsAvecLesTags($tags = array()) {
299
	public function getIdsAvecLesTags($tags = array()) {
300
		$ids = $this->executerMethodeStockage('getIdsAvecLesTags', array($tags));
300
		$ids = $this->executerMethodeStockage('getIdsAvecLesTags', array($tags));
301
		$ids = $this->supprimerPrefixe($ids);
301
		$ids = $this->supprimerPrefixe($ids);
302
		return $ids;
302
		return $ids;
303
	}
303
	}
304
 
304
 
305
	/**
305
	/**
306
	 * Return an array of stored cache ids which don't match given tags
306
	 * Return an array of stored cache ids which don't match given tags
307
	 *
307
	 *
308
	 * In case of multiple tags, a logical OR is made between tags
308
	 * In case of multiple tags, a logical OR is made between tags
309
	 *
309
	 *
310
	 * @param array $tags array of tags
310
	 * @param array $tags array of tags
311
	 * @return array array of not matching cache ids (string)
311
	 * @return array array of not matching cache ids (string)
312
	 */
312
	 */
313
	public function getIdsSansLesTags($tags = array()) {
313
	public function getIdsSansLesTags($tags = array()) {
314
	   	$ids = $this->executerMethodeStockage('getIdsSansLesTags', array($tags));
314
	   	$ids = $this->executerMethodeStockage('getIdsSansLesTags', array($tags));
315
		$ids = $this->supprimerPrefixe($ids);
315
		$ids = $this->supprimerPrefixe($ids);
316
		return $ids;
316
		return $ids;
317
	}
317
	}
318
 
318
 
319
	/**
319
	/**
320
	 * Return an array of stored cache ids which match any given tags
320
	 * Return an array of stored cache ids which match any given tags
321
	 *
321
	 *
322
	 * In case of multiple tags, a logical OR is made between tags
322
	 * In case of multiple tags, a logical OR is made between tags
323
	 *
323
	 *
324
	 * @param array $tags array of tags
324
	 * @param array $tags array of tags
325
	 * @return array array of matching any cache ids (string)
325
	 * @return array array of matching any cache ids (string)
326
	 */
326
	 */
327
	public function getIdsAvecUnTag($tags = array()) {
327
	public function getIdsAvecUnTag($tags = array()) {
328
		$ids = $this->executerMethodeStockage('getIdsAvecUnTag', array($tags));
328
		$ids = $this->executerMethodeStockage('getIdsAvecUnTag', array($tags));
329
		$ids = $this->supprimerPrefixe($ids);
329
		$ids = $this->supprimerPrefixe($ids);
330
		return $ids;
330
		return $ids;
331
	}
331
	}
332
 
332
 
333
	/**
333
	/**
334
	 * Return the filling percentage of the backend storage
334
	 * Return the filling percentage of the backend storage
335
	 *
335
	 *
336
	 * @return int integer between 0 and 100
336
	 * @return int integer between 0 and 100
337
	 */
337
	 */
338
	public function getPourcentageRemplissage() {
338
	public function getPourcentageRemplissage() {
339
		return $this->executerMethodeStockage('getPourcentageRemplissage');
339
		return $this->executerMethodeStockage('getPourcentageRemplissage');
340
	}
340
	}
341
 
341
 
342
	/**
342
	/**
343
	 * Return an array of metadatas for the given cache id
343
	 * Return an array of metadatas for the given cache id
344
	 *
344
	 *
345
	 * The array will include these keys :
345
	 * The array will include these keys :
346
	 * - expire : the expire timestamp
346
	 * - expire : the expire timestamp
347
	 * - tags : a string array of tags
347
	 * - tags : a string array of tags
348
	 * - mtime : timestamp of last modification time
348
	 * - mtime : timestamp of last modification time
349
	 *
349
	 *
350
	 * @param string $id cache id
350
	 * @param string $id cache id
351
	 * @return array array of metadatas (false if the cache id is not found)
351
	 * @return array array of metadatas (false if the cache id is not found)
352
	 */
352
	 */
353
	public function getMetadonnees($id) {
353
	public function getMetadonnees($id) {
354
		$id = $this->prefixerId($id);
354
		$id = $this->prefixerId($id);
355
		return $this->executerMethodeStockage('getMetadonnees', array($id));
355
		return $this->executerMethodeStockage('getMetadonnees', array($id));
356
	}
356
	}
357
 
357
 
358
	/**
358
	/**
359
	 * Give (if possible) an extra lifetime to the given cache id
359
	 * Give (if possible) an extra lifetime to the given cache id
360
	 *
360
	 *
361
	 * @param string $id cache id
361
	 * @param string $id cache id
362
	 * @param int $extraLifetime
362
	 * @param int $extraLifetime
363
	 * @return boolean true if ok
363
	 * @return boolean true if ok
364
	 */
364
	 */
365
	public function ajouterSupplementDureeDeVie($id, $supplement_duree_de_vie) {
365
	public function ajouterSupplementDureeDeVie($id, $supplement_duree_de_vie) {
366
		$id = $this->prefixerId($id);
366
		$id = $this->prefixerId($id);
367
		return $this->executerMethodeStockage('ajouterSupplementDureeDeVie', array($id, $supplement_duree_de_vie));
367
		return $this->executerMethodeStockage('ajouterSupplementDureeDeVie', array($id, $supplement_duree_de_vie));
368
	}
368
	}
369
	
369
	
370
 
370
 
371
	/**
371
	/**
372
	 * Fabrique et retourne l'identifiant du cache avec son préfixe.
372
	 * Fabrique et retourne l'identifiant du cache avec son préfixe.
373
	 *
373
	 *
374
	 * Vérifie l'option 'cache_id_prefixe' et retourne le nouvel id avec préfixe ou simplement l'id lui même si elle vaut null.
374
	 * Vérifie l'option 'cache_id_prefixe' et retourne le nouvel id avec préfixe ou simplement l'id lui même si elle vaut null.
375
	 *
375
	 *
376
	 * @param  string $id Identifiant du cache.
376
	 * @param  string $id Identifiant du cache.
377
	 * @return string Identifiant du cache avec ou sans préfixe.
377
	 * @return string Identifiant du cache avec ou sans préfixe.
378
	 */
378
	 */
379
	private function prefixerId($id) {
379
	private function prefixerId($id) {
380
		$nouvel_id = $id;
380
		$nouvel_id = $id;
381
		if (($id !== null) && isset($this->options['cache_id_prefixe'])) {
381
		if (($id !== null) && isset($this->options['cache_id_prefixe'])) {
382
			$nouvel_id = $this->options['cache_id_prefixe'].$id;
382
			$nouvel_id = $this->options['cache_id_prefixe'].$id;
383
		}
383
		}
384
		return $nouvel_id;
384
		return $nouvel_id;
385
	}
385
	}
386
	
386
	
387
	private function executerMethodeStockage($methode, $params = null) {
387
	private function executerMethodeStockage($methode, $params = null) {
388
		if (method_exists($this->stockage, $methode)) {
388
		if (method_exists($this->stockage, $methode)) {
389
			if ($params == null) {
389
			if ($params == null) {
390
				$resultat = call_user_func(array($this->stockage, $methode));
390
				$resultat = call_user_func(array($this->stockage, $methode));
391
			} else {
391
			} else {
392
				$resultat = call_user_func_array(array($this->stockage, $methode), $params);
392
				$resultat = call_user_func_array(array($this->stockage, $methode), $params);
393
			}
393
			}
394
		} else {
394
		} else {
395
			$resultat = false;
395
			$resultat = false;
396
			trigger_error("La méthode '$methode' n'existe pas dans la classe '".get_class($this)."'.", E_USER_WARNING);
396
			trigger_error("La méthode '$methode' n'existe pas dans la classe '".get_class($this)."'.", E_USER_WARNING);
397
		}
397
		}
398
		return $resultat;
398
		return $resultat;
399
	}
399
	}
400
	
400
	
401
	private function supprimerPrefixe($ids) {
401
	private function supprimerPrefixe($ids) {
402
		// Il est nécessaire de retirer les cache_id_prefixe des ids (voir #ZF-6178, #ZF-7600)
402
		// Il est nécessaire de retirer les cache_id_prefixe des ids (voir #ZF-6178, #ZF-7600)
403
		if (isset($this->options['cache_id_prefixe']) && $this->options['cache_id_prefixe'] !== '') {
403
		if (isset($this->options['cache_id_prefixe']) && $this->options['cache_id_prefixe'] !== '') {
404
			$prefixe =& $this->options['cache_id_prefixe'];
404
			$prefixe =& $this->options['cache_id_prefixe'];
405
			$prefixe_longueur = strlen($prefixe);
405
			$prefixe_longueur = strlen($prefixe);
406
			foreach ($ids as &$id) {
406
			foreach ($ids as &$id) {
407
				if (strpos($id, $prefixe) === 0) {
407
				if (strpos($id, $prefixe) === 0) {
408
					$id = substr($id, $prefixe_longueur);
408
					$id = substr($id, $prefixe_longueur);
409
				}
409
				}
410
			}
410
			}
411
		}
411
		}
412
		return $ids;
412
		return $ids;
413
	}
413
	}
414
	
414
	
415
	private function controlerEcriture($id, $donnees_avant_ecriture) {
415
	private function controlerEcriture($id, $donnees_avant_ecriture) {
416
		$resultat = true;
416
		$resultat = true;
417
		if ($this->options['controle_ecriture']) {
417
		if ($this->options['controle_ecriture']) {
418
			$donnees_apres_ecriture = $this->executerMethodeStockage('charger', array($id, true));
418
			$donnees_apres_ecriture = $this->executerMethodeStockage('charger', array($id, true));
419
			if ($donnees_avant_ecriture != $donnees_apres_ecriture) {
419
			if ($donnees_avant_ecriture != $donnees_apres_ecriture) {
420
				$this->executerMethodeStockage('supprimer', array($id));
420
				$this->executerMethodeStockage('supprimer', array($id));
421
				$resultat = false;
421
				$resultat = false;
422
			}
422
			}
423
		}
423
		}
424
		return $resultat;
424
		return $resultat;
425
	}
425
	}
426
	
426
	
427
	private function deserialiserAutomatiquement($donnees) {
427
	private function deserialiserAutomatiquement($donnees) {
428
		if ($donnees !== false && $this->options['serialisation_auto']) {
428
		if ($donnees !== false && $this->options['serialisation_auto']) {
429
				// we need to unserialize before sending the result
429
				// we need to unserialize before sending the result
430
				$donnees = unserialize($donnees);
430
				$donnees = unserialize($donnees);
431
		}
431
		}
432
		return $donnees;
432
		return $donnees;
433
	}
433
	}
434
	
434
	
435
	private function serialiserAutomatiquement($donnees) {
435
	private function serialiserAutomatiquement($donnees) {
436
		if ($this->options['serialisation_auto']) {
436
		if ($this->options['serialisation_auto']) {
437
			// we need to serialize datas before storing them
437
			// we need to serialize datas before storing them
438
			$donnees = serialize($donnees);
438
			$donnees = serialize($donnees);
439
		} else {
439
		} else {
440
			if (!is_string($donnees)) {
440
			if (!is_string($donnees)) {
441
				trigger_error("Les données doivent être une chaîne de caractères ou vous devez activez l'option serialisation_auto = true", E_USER_WARNING);
441
				trigger_error("Les données doivent être une chaîne de caractères ou vous devez activez l'option serialisation_auto = true", E_USER_WARNING);
442
			}
442
			}
443
		}
443
		}
444
		return $donnees;
444
		return $donnees;
445
	}
445
	}
446
	
446
	
447
	private function nettoyerAutomatiquement() {
447
	private function nettoyerAutomatiquement() {
448
		if ($this->options['nettoyage_auto'] > 0) {
448
		if ($this->options['nettoyage_auto'] > 0) {
449
			$rand = rand(1, $this->options['nettoyage_auto']);
449
			$rand = rand(1, $this->options['nettoyage_auto']);
450
			if ($rand == 1) {
450
			if ($rand == 1) {
451
				$this->nettoyer(self::NETTOYAGE_MODE_EXPIRATION);
451
				$this->nettoyer(self::NETTOYAGE_MODE_EXPIRATION);
452
			}
452
			}
453
		}
453
		}
454
	}
454
	}
455
	
455
	
456
	/**
456
	/**
457
	 * Valide un identifiant de cache ou un tag (securité, nom de fichiers fiables, préfixes réservés...)
457
	 * Valide un identifiant de cache ou un tag (securité, nom de fichiers fiables, préfixes réservés...)
458
	 *
458
	 *
459
	 * @param  string $chaine Identificant de cache ou tag
459
	 * @param  string $chaine Identificant de cache ou tag
460
	 * @return void
460
	 * @return void
461
	 */
461
	 */
462
	protected static function validerIdOuTag($chaine) {
462
	protected static function validerIdOuTag($chaine) {
463
		if (!is_string($chaine)) {
463
		if (!is_string($chaine)) {
464
			trigger_error('Id ou tag invalide : doit être une chaîne de caractères', E_USER_ERROR);
464
			trigger_error('Id ou tag invalide : doit être une chaîne de caractères', E_USER_ERROR);
465
		}
465
		}
466
		if (substr($chaine, 0, 9) == 'internal-') {
466
		if (substr($chaine, 0, 9) == 'internal-') {
467
			trigger_error('"internal-*" identifiants ou tags sont réservés', E_USER_WARNING);
467
			trigger_error('"internal-*" identifiants ou tags sont réservés', E_USER_WARNING);
468
		}
468
		}
469
		if (!preg_match('~^[a-zA-Z0-9_]+$~D', $chaine)) {
469
		if (!preg_match('~^[a-zA-Z0-9_]+$~D', $chaine)) {
470
			trigger_error("Id ou tag invalide '$chaine' : doit contenir seulement [a-zA-Z0-9_]", E_USER_WARNING);
470
			trigger_error("Id ou tag invalide '$chaine' : doit contenir seulement [a-zA-Z0-9_]", E_USER_WARNING);
471
		}
471
		}
472
	}
472
	}
473
 
473
 
474
	/**
474
	/**
475
	 * Valide un tableau de tags  (securité, nom de fichiers fiables, préfixes réservés...)
475
	 * Valide un tableau de tags  (securité, nom de fichiers fiables, préfixes réservés...)
476
	 *
476
	 *
477
	 * @param  array $tags tableau de tags
477
	 * @param  array $tags tableau de tags
478
	 * @return void
478
	 * @return void
479
	 */
479
	 */
480
	protected static function validerTableauDeTags($tags) {
480
	protected static function validerTableauDeTags($tags) {
481
		if (!is_array($tags)) {
481
		if (!is_array($tags)) {
482
			trigger_error("Tableau de tags invalide : doit être un tableau 'array'", E_USER_WARNING);
482
			trigger_error("Tableau de tags invalide : doit être un tableau 'array'", E_USER_WARNING);
483
		}
483
		}
484
		foreach ($tags as $tag) {
484
		foreach ($tags as $tag) {
485
			self::validerIdOuTag($tag);
485
			self::validerIdOuTag($tag);
486
		}
486
		}
487
		reset($tags);
487
		reset($tags);
488
	}
488
	}
489
	
489
	
490
	/**
490
	/**
491
	 * Calcule et retourne le timestamp d'expiration
491
	 * Calcule et retourne le timestamp d'expiration
492
	 *
492
	 *
493
	 * @return int timestamp d'expiration (unix timestamp)
493
	 * @return int timestamp d'expiration (unix timestamp)
494
	 */
494
	 */
495
	public function getTimestampExpiration($duree_de_vie) {
495
	public function getTimestampExpiration($duree_de_vie) {
496
		if ($duree_de_vie === false) {
496
		if ($duree_de_vie === false) {
497
			if (isset($this->options['duree_de_vie']) && is_int($this->options['duree_de_vie'])) {
497
			if (isset($this->options['duree_de_vie']) && is_int($this->options['duree_de_vie'])) {
498
				$duree_de_vie = (int) $this->options['duree_de_vie'];
498
				$duree_de_vie = (int) $this->options['duree_de_vie'];
499
			} else {
499
			} else {
500
				$duree_de_vie = 3600;
500
				$duree_de_vie = 3600;
501
			}
501
			}
502
		}
502
		}
503
		$timestamp = ($duree_de_vie === null) ? 9999999999 : (time() + $duree_de_vie);
503
		$timestamp = ($duree_de_vie === null) ? 9999999999 : (time() + $duree_de_vie);
504
		return $timestamp;
504
		return $timestamp;
505
	}
505
	}
506
	
506
	
507
}
507
}