Subversion Repositories Applications.framework

Rev

Rev 269 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 269 Rev 282
1
<?php
1
<?php
2
class CacheFichier {
2
class CacheFichier {
3
	/**
3
	/**
4
	 * Available options
4
	 * Options disponibles
-
 
5
	 * 
-
 
6
	 * ====> (string) stockage_chemin :
-
 
7
	 * Chemin vers  le dossier devant contenir l'arborescence du cache.
-
 
8
	 * 
-
 
9
	 * =====> (boolean) fichier_verrou :
-
 
10
	 * - Active / Désactive le verrouillage des fichiers
-
 
11
	 * - Peut éviter la corruption du cache dans de mauvaises circonstances, mais cela ne fonctionne pas sur des serveur 
-
 
12
	 * multithread et sur les systèmes de fichiers NFS par exemple.
-
 
13
	 *
-
 
14
	 * =====> (boolean) controle_lecture :
-
 
15
	 * - Activer / désactiver le contrôle de lecture
-
 
16
	 * - S'il est activé, une clé de contrôle est ajoutée dans le fichier de cache et cette clé est comparée avec celle calculée
-
 
17
	 * après la lecture.
-
 
18
	 *
-
 
19
	 * =====> (string) controle_lecture_type :
-
 
20
	 * Type de contrôle de lecture (seulement si le contrôle de lecture est activé).
-
 
21
	 * Les valeurs disponibles sont:
-
 
22
	 * - «md5» pour un contrôle md5 (le meilleur mais le plus lent)
-
 
23
	 * - «crc32» pour un contrôle de hachage crc32 (un peu moins sécurisé, mais plus rapide, un meilleur choix)
-
 
24
	 * - «adler32» pour un contrôle de hachage adler32  (excellent choix aussi, plus rapide que crc32)
-
 
25
	 * - «strlen» pour un test de longueur uniquement (le plus rapide)
-
 
26
	 *
-
 
27
	 * =====> (int) dossier_niveau :
-
 
28
	 * - Permet de réglez le nombre de niveau de sous-dossier que contiendra l'arborescence des dossiers du cache.
-
 
29
	 * 0 signifie "pas de sous-dossier pour le cache", 
-
 
30
	 * 1 signifie "un niveau de sous-dossier", 
-
 
31
	 * 2 signifie "deux niveaux" ...
-
 
32
	 * Cette option peut accélérer le cache seulement lorsque vous avez plusieurs centaines de fichiers de cache. 
-
 
33
	 * Seuls des tests spécifiques peuvent vous aider à choisir la meilleure valeur possible pour vous.
-
 
34
	 * 1 ou 2 peut être est un bon début.
-
 
35
	 *
-
 
36
	 * =====> (int) dossier_umask :
-
 
37
	 * - Umask pour les sous-dossiers de l'arborescence du cache.
-
 
38
	 *
-
 
39
	 * =====> (string) fichier_prefixe :
-
 
40
	 * - préfixe pour les fichiers du cache
-
 
41
	 * - ATTENTION : faite vraiment attention avec cette option, car une valeur trop générique dans le dossier cache du système
-
 
42
	 * (comme /tmp) peut provoquer des catastrophes lors du nettoyage du cache.
5
	 *
43
	 *
6
	 * =====> (string) cache_dir :
44
	 * =====> (int) fichier_umask :
7
	 * - Directory where to put the cache files
45
	 * - Umask pour les fichiers de cache
8
	 *
46
	 *
9
	 * =====> (boolean) file_locking :
-
 
10
	 * - Enable / disable file_locking
-
 
11
	 * - Can avoid cache corruption under bad circumstances but it doesn't work on multithread
-
 
12
	 * webservers and on NFS filesystems for example
-
 
13
	 *
-
 
14
	 * =====> (boolean) read_control :
-
 
15
	 * - Enable / disable read control
-
 
16
	 * - If enabled, a control key is embeded in cache file and this key is compared with the one
-
 
17
	 * calculated after the reading.
-
 
18
	 *
-
 
19
	 * =====> (string) read_control_type :
-
 
20
	 * - Type of read control (only if read control is enabled). Available values are :
-
 
21
	 *   'md5' for a md5 hash control (best but slowest)
-
 
22
	 *   'crc32' for a crc32 hash control (lightly less safe but faster, better choice)
-
 
23
	 *   'adler32' for an adler32 hash control (excellent choice too, faster than crc32)
-
 
24
	 *   'strlen' for a length only test (fastest)
-
 
25
	 *
-
 
26
	 * =====> (int) hashed_directory_level :
-
 
27
	 * - Hashed directory level
-
 
28
	 * - Set the hashed directory structure level. 0 means "no hashed directory
-
 
29
	 * structure", 1 means "one level of directory", 2 means "two levels"...
-
 
30
	 * This option can speed up the cache only when you have many thousands of
-
 
31
	 * cache file. Only specific benchs can help you to choose the perfect value
-
 
32
	 * for you. Maybe, 1 or 2 is a good start.
-
 
33
	 *
-
 
34
	 * =====> (int) hashed_directory_umask :
-
 
35
	 * - Umask for hashed directory structure
-
 
36
	 *
-
 
37
	 * =====> (string) file_name_prefix :
-
 
38
	 * - prefix for cache files
-
 
39
	 * - be really carefull with this option because a too generic value in a system cache dir
-
 
40
	 *   (like /tmp) can cause disasters when cleaning the cache
-
 
41
	 *
-
 
42
	 * =====> (int) cache_file_umask :
-
 
43
	 * - Umask for cache files
-
 
44
	 *
-
 
45
	 * =====> (int) metatadatas_array_max_size :
47
	 * =====> (int) metadonnees_max_taille :
46
	 * - max size for the metadatas array (don't change this value unless you
48
	 * - taille maximum pour le tableau de métadonnées du cache (ne changer pas cette valeur sauf si vous savez ce que vous faite)
47
	 *   know what you are doing)
-
 
48
	 *
49
	 *
49
	 * @var array available options
50
	 * @var array options disponibles
50
	 */
51
	 */
51
	protected $options = array(
52
	protected $options = array(
52
		'stockage_chemin' => null,
53
		'stockage_chemin' => null,
53
		'fichier_verrou' => true,
54
		'fichier_verrou' => true,
54
		'controle_lecture' => true,
55
		'controle_lecture' => true,
55
		'controle_lecture_type' => 'crc32',
56
		'controle_lecture_type' => 'crc32',
56
		'dossier_niveau' => 0,
57
		'dossier_niveau' => 0,
57
		'dossier_umask' => 0700,
58
		'dossier_umask' => 0700,
58
		'fichier_prefixe' => 'tbf',
59
		'fichier_prefixe' => 'tbf',
59
		'fichier_umask' => 0600,
60
		'fichier_umask' => 0600,
60
		'metadonnees_max_taille' => 100
61
		'metadonnees_max_taille' => 100
61
	);
62
	);
62
 
63
 
63
	/**
64
	/**
64
	 * Array of metadatas (each item is an associative array)
65
	 * Array of metadatas (each item is an associative array)
65
	 *
66
	 *
66
	 * @var array
67
	 * @var array
67
	 */
68
	 */
68
	protected $metadonnees = array();
69
	protected $metadonnees = array();
69
 
70
 
70
	private $Cache = null;
71
	private $Cache = null;
71
	
72
	
72
	/**
73
	/**
73
	 * Constructor
74
	 * Constructor
74
	 *
75
	 *
75
	 * @param  array $options associative array of options
76
	 * @param  array $options associative array of options
76
	 * @throws Zend_Cache_Exception
77
	 * @throws Zend_Cache_Exception
77
	 * @return void
78
	 * @return void
78
	 */
79
	 */
79
	public function __construct(array $options = array(), Cache $cache) {
80
	public function __construct(array $options = array(), Cache $cache) {
80
		$this->Cache = $cache;
81
		$this->Cache = $cache;
-
 
82
		$this->initialiserOptionsParConfig();
81
		$this->setOptions($options);
83
		$this->setOptions($options);
82
 
84
 
83
		if (isset($this->options['prefixe_fichier'])) {
85
		if (isset($this->options['prefixe_fichier'])) {
84
			if (!preg_match('~^[a-zA-Z0-9_]+$~D', $this->options['prefixe_fichier'])) {
86
			if (!preg_match('~^[a-zA-Z0-9_]+$~D', $this->options['prefixe_fichier'])) {
85
				trigger_error("Préfixe de nom de fichier invalide : doit contenir seulement [a-zA-Z0-9_]", E_USER_WARNING);
87
				trigger_error("Préfixe de nom de fichier invalide : doit contenir seulement [a-zA-Z0-9_]", E_USER_WARNING);
86
			}
88
			}
87
		}
89
		}
88
		if ($this->options['metadonnees_max_taille'] < 10) {
90
		if ($this->options['metadonnees_max_taille'] < 10) {
89
			trigger_error("Taille du tableau des méta-données invalide, elle doit être > 10", E_USER_WARNING);
91
			trigger_error("Taille du tableau des méta-données invalide, elle doit être > 10", E_USER_WARNING);
90
		}
92
		}
91
		if (isset($options['dossier_umask']) && is_string($options['dossier_umask'])) {
93
		if (isset($options['dossier_umask']) && is_string($options['dossier_umask'])) {
92
			// See #ZF-4422
94
			// See #ZF-4422
93
			$this->options['dossier_umask'] = octdec($this->options['dossier_umask']);
95
			$this->options['dossier_umask'] = octdec($this->options['dossier_umask']);
94
		}
96
		}
95
		if (isset($options['fichier_umask']) && is_string($options['fichier_umask'])) {
97
		if (isset($options['fichier_umask']) && is_string($options['fichier_umask'])) {
96
			// See #ZF-4422
98
			// See #ZF-4422
97
			$this->options['fichier_umask'] = octdec($this->options['fichier_umask']);
99
			$this->options['fichier_umask'] = octdec($this->options['fichier_umask']);
98
		}
100
		}
-
 
101
	}
-
 
102
	
-
 
103
	private function initialiserOptionsParConfig() {
-
 
104
		while (list($nom, $valeur) = each($this->options)) {
-
 
105
			if (Config::existe($nom)) {
-
 
106
				$this->options[$nom] = Config::get($nom);
-
 
107
			}
-
 
108
		}
99
	}
109
	}
100
	
110
	
101
	private function setOptions($options) {
111
	private function setOptions($options) {
102
		while (list($nom, $valeur) = each($options)) {
112
		while (list($nom, $valeur) = each($options)) {
103
			if (!is_string($nom)) {
113
			if (!is_string($nom)) {
104
				trigger_error("Nom d'option incorecte : $nom", E_USER_WARNING);
114
				trigger_error("Nom d'option incorecte : $nom", E_USER_WARNING);
105
			}
115
			}
106
			$nom = strtolower($nom);
116
			$nom = strtolower($nom);
107
			if (array_key_exists($nom, $this->options)) {
117
			if (array_key_exists($nom, $this->options)) {
108
				$this->options[$nom] = $valeur;
118
				$this->options[$nom] = $valeur;
109
			}
119
			}
110
		}
120
		}
111
	}
121
	}
112
 
122
 
113
   	public function setEmplacement($emplacement) {
123
   	public function setEmplacement($emplacement) {
114
		if (!is_dir($emplacement)) {
124
		if (!is_dir($emplacement)) {
115
			trigger_error("L'emplacement doit être un dossier.", E_USER_WARNING);
125
			trigger_error("L'emplacement doit être un dossier.", E_USER_WARNING);
116
		}
126
		}
117
		if (!is_writable($emplacement)) {
127
		if (!is_writable($emplacement)) {
118
			trigger_error("Le dossier de stockage du cache n'est pas accessible en écriture", E_USER_WARNING);
128
			trigger_error("Le dossier de stockage du cache n'est pas accessible en écriture", E_USER_WARNING);
119
		}
129
		}
120
		$emplacement = rtrim(realpath($emplacement), '\\/').DS;
130
		$emplacement = rtrim(realpath($emplacement), '\\/').DS;
121
		$this->options['stockage_chemin'] = $emplacement;
131
		$this->options['stockage_chemin'] = $emplacement;
122
	}
132
	}
123
 
133
 
124
	/**
134
	/**
125
	 * Test if a cache is available for the given id and (if yes) return it (false else)
135
	 * Test if a cache is available for the given id and (if yes) return it (false else)
126
	 *
136
	 *
127
	 * @param string $id cache id
137
	 * @param string $id cache id
128
	 * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
138
	 * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
129
	 * @return string|false cached datas
139
	 * @return string|false cached datas
130
	 */
140
	 */
131
	public function charger($id, $ne_pas_tester_validiter_du_cache = false) {
141
	public function charger($id, $ne_pas_tester_validiter_du_cache = false) {
132
		$donnees = false;
142
		$donnees = false;
133
		if ($this->tester($id, $ne_pas_tester_validiter_du_cache)) {
143
		if ($this->tester($id, $ne_pas_tester_validiter_du_cache)) {
134
			$metadonnees = $this->getMetadonneesFichier($id);
144
			$metadonnees = $this->getMetadonneesFichier($id);
135
			$fichier = $this->getFichierNom($id);
145
			$fichier = $this->getFichierNom($id);
136
			$donnees = $this->getContenuFichier($fichier);
146
			$donnees = $this->getContenuFichier($fichier);
137
			if ($this->options['controle_lecture']) {
147
			if ($this->options['controle_lecture']) {
138
				$cle_secu_donnees = $this->genererCleSecu($donnees, $this->options['controle_lecture_type']);
148
				$cle_secu_donnees = $this->genererCleSecu($donnees, $this->options['controle_lecture_type']);
139
				$cle_secu_controle = $metadonnees['hash'];
149
				$cle_secu_controle = $metadonnees['hash'];
140
				if ($cle_secu_donnees != $cle_secu_controle) {
150
				if ($cle_secu_donnees != $cle_secu_controle) {
141
					// Probléme détecté par le contrôle de lecture !
151
					// Probléme détecté par le contrôle de lecture !
142
					// TODO : loguer le pb de sécu
152
					// TODO : loguer le pb de sécu
143
					$this->supprimer($id);
153
					$this->supprimer($id);
144
					$donnees = false;
154
					$donnees = false;
145
				}
155
				}
146
			}
156
			}
147
		}
157
		}
148
		return $donnees;
158
		return $donnees;
149
	}
159
	}
150
 
160
 
151
	/**
161
	/**
152
	 * Teste si un enregistrement en cache est disponible ou pas (pour l'id passé en paramètre).
162
	 * Teste si un enregistrement en cache est disponible ou pas (pour l'id passé en paramètre).
153
	 *
163
	 *
154
	 * @param string $id identifiant de cache.
164
	 * @param string $id identifiant de cache.
155
	 * @return mixed false (le cache n'est pas disponible) ou timestamp (int) "de dernière modification" de l'enregistrement en cache
165
	 * @return mixed false (le cache n'est pas disponible) ou timestamp (int) "de dernière modification" de l'enregistrement en cache
156
	 */
166
	 */
157
	public function tester($id) {
167
	public function tester($id) {
158
		clearstatcache();
168
		clearstatcache();
159
		return $this->testerExistenceCache($id, false);
169
		return $this->testerExistenceCache($id, false);
160
	}
170
	}
161
 
171
 
162
	/**
172
	/**
163
	 * Save some string datas into a cache record
173
	 * Save some string datas into a cache record
164
	 *
174
	 *
165
	 * Note : $data is always "string" (serialization is done by the
175
	 * Note : $data is always "string" (serialization is done by the
166
	 * core not by the backend)
176
	 * core not by the backend)
167
	 *
177
	 *
168
	 * @param  string $data			 Datas to cache
178
	 * @param  string $data			 Datas to cache
169
	 * @param  string $id			   Cache id
179
	 * @param  string $id			   Cache id
170
	 * @param  array  $tags			 Array of strings, the cache record will be tagged by each string entry
180
	 * @param  array  $tags			 Array of strings, the cache record will be tagged by each string entry
171
	 * @param  int	$specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
181
	 * @param  int	$specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
172
	 * @return boolean true if no problem
182
	 * @return boolean true if no problem
173
	 */
183
	 */
174
	public function sauver($donnees, $id, $tags = array(), $duree_vie_specifique = false) {
184
	public function sauver($donnees, $id, $tags = array(), $duree_vie_specifique = false) {
175
		clearstatcache();
185
		clearstatcache();
176
		$fichier = $this->getFichierNom($id);
186
		$fichier = $this->getFichierNom($id);
177
		$chemin = $this->getChemin($id);
187
		$chemin = $this->getChemin($id);
178
		
188
		
179
		$resultat = true;
189
		$resultat = true;
180
		if ($this->options['dossier_niveau'] > 0) {
190
		if ($this->options['dossier_niveau'] > 0) {
181
			if (!is_writable($chemin)) {
191
			if (!is_writable($chemin)) {
182
				// maybe, we just have to build the directory structure
192
				// maybe, we just have to build the directory structure
183
				$this->lancerMkdirEtChmodRecursif($id);
193
				$this->lancerMkdirEtChmodRecursif($id);
184
			}
194
			}
185
			if (!is_writable($chemin)) {
195
			if (!is_writable($chemin)) {
186
				$resultat = false;
196
				$resultat = false;
187
			}
197
			}
188
		}
198
		}
189
		
199
		
190
		if ($resultat === true) {
200
		if ($resultat === true) {
191
			if ($this->options['controle_lecture']) {
201
			if ($this->options['controle_lecture']) {
192
				$cle_secu = $this->genererCleSecu($donnees, $this->options['controle_lecture_type']);
202
				$cle_secu = $this->genererCleSecu($donnees, $this->options['controle_lecture_type']);
193
			} else {
203
			} else {
194
				$cle_secu = '';
204
				$cle_secu = '';
195
			}
205
			}
196
			
206
			
197
			$metadonnees = array(
207
			$metadonnees = array(
198
				'hash' => $cle_secu,
208
				'hash' => $cle_secu,
199
				'mtime' => time(),
209
				'mtime' => time(),
200
				'expiration' => $this->Cache->getTimestampExpiration($duree_vie_specifique),
210
				'expiration' => $this->Cache->getTimestampExpiration($duree_vie_specifique),
201
				'tags' => $tags
211
				'tags' => $tags
202
			);
212
			);
203
 
213
 
204
			if (! $resultat = $this->setMetadonnees($id, $metadonnees)) {
214
			if (! $resultat = $this->setMetadonnees($id, $metadonnees)) {
205
				// TODO : ajouter un log
215
				// TODO : ajouter un log
206
			} else {
216
			} else {
207
				$resultat = $this->setContenuFichier($fichier, $donnees);
217
				$resultat = $this->setContenuFichier($fichier, $donnees);
208
			}
218
			}
209
		}
219
		}
210
		return $resultat;
220
		return $resultat;
211
	}
221
	}
212
 
222
 
213
	/**
223
	/**
214
	 * Remove a cache record
224
	 * Remove a cache record
215
	 *
225
	 *
216
	 * @param  string $id cache id
226
	 * @param  string $id cache id
217
	 * @return boolean true if no problem
227
	 * @return boolean true if no problem
218
	 */
228
	 */
219
	public function supprimer($id) {
229
	public function supprimer($id) {
220
		$fichier = $this->getFichierNom($id);
230
		$fichier = $this->getFichierNom($id);
221
		$suppression_fichier = $this->supprimerFichier($fichier);
231
		$suppression_fichier = $this->supprimerFichier($fichier);
222
		$suppression_metadonnees = $this->supprimerMetadonnees($id);
232
		$suppression_metadonnees = $this->supprimerMetadonnees($id);
223
		return $suppression_metadonnees && $suppression_fichier;
233
		return $suppression_metadonnees && $suppression_fichier;
224
	}
234
	}
225
 
235
 
226
	/**
236
	/**
227
	 * Clean some cache records
237
	 * Clean some cache records
228
	 *
238
	 *
229
	 * Available modes are :
239
	 * Available modes are :
230
	 * 'all' (default)  => remove all cache entries ($tags is not used)
240
	 * 'all' (default)  => remove all cache entries ($tags is not used)
231
	 * 'old'			=> remove too old cache entries ($tags is not used)
241
	 * 'old'			=> remove too old cache entries ($tags is not used)
232
	 * 'matchingTag'	=> remove cache entries matching all given tags
242
	 * 'matchingTag'	=> remove cache entries matching all given tags
233
	 *					 ($tags can be an array of strings or a single string)
243
	 *					 ($tags can be an array of strings or a single string)
234
	 * 'notMatchingTag' => remove cache entries not matching one of the given tags
244
	 * 'notMatchingTag' => remove cache entries not matching one of the given tags
235
	 *					 ($tags can be an array of strings or a single string)
245
	 *					 ($tags can be an array of strings or a single string)
236
	 * 'matchingAnyTag' => remove cache entries matching any given tags
246
	 * 'matchingAnyTag' => remove cache entries matching any given tags
237
	 *					 ($tags can be an array of strings or a single string)
247
	 *					 ($tags can be an array of strings or a single string)
238
	 *
248
	 *
239
	 * @param string $mode clean mode
249
	 * @param string $mode clean mode
240
	 * @param tags array $tags array of tags
250
	 * @param tags array $tags array of tags
241
	 * @return boolean true if no problem
251
	 * @return boolean true if no problem
242
	 */
252
	 */
243
	public function nettoyer($mode = Cache::NETTOYAGE_MODE_TOUS, $tags = array()) {
253
	public function nettoyer($mode = Cache::NETTOYAGE_MODE_TOUS, $tags = array()) {
244
		// We use this protected method to hide the recursive stuff
254
		// We use this protected method to hide the recursive stuff
245
		clearstatcache();
255
		clearstatcache();
246
		return $this->nettoyerFichiers($this->options['stockage_chemin'], $mode, $tags);
256
		return $this->nettoyerFichiers($this->options['stockage_chemin'], $mode, $tags);
247
	}
257
	}
248
 
258
 
249
	/**
259
	/**
250
	 * Return an array of stored cache ids
260
	 * Return an array of stored cache ids
251
	 *
261
	 *
252
	 * @return array array of stored cache ids (string)
262
	 * @return array array of stored cache ids (string)
253
	 */
263
	 */
254
	public function getIds() {
264
	public function getIds() {
255
		return $this->analyserCache($this->options['stockage_chemin'], 'ids', array());
265
		return $this->analyserCache($this->options['stockage_chemin'], 'ids', array());
256
	}
266
	}
257
 
267
 
258
	/**
268
	/**
259
	 * Return an array of stored tags
269
	 * Return an array of stored tags
260
	 *
270
	 *
261
	 * @return array array of stored tags (string)
271
	 * @return array array of stored tags (string)
262
	 */
272
	 */
263
	public function getTags() {
273
	public function getTags() {
264
		return $this->analyserCache($this->options['stockage_chemin'], 'tags', array());
274
		return $this->analyserCache($this->options['stockage_chemin'], 'tags', array());
265
	}
275
	}
266
 
276
 
267
	/**
277
	/**
268
	 * Return an array of stored cache ids which match given tags
278
	 * Return an array of stored cache ids which match given tags
269
	 *
279
	 *
270
	 * In case of multiple tags, a logical AND is made between tags
280
	 * In case of multiple tags, a logical AND is made between tags
271
	 *
281
	 *
272
	 * @param array $tags array of tags
282
	 * @param array $tags array of tags
273
	 * @return array array of matching cache ids (string)
283
	 * @return array array of matching cache ids (string)
274
	 */
284
	 */
275
	public function getIdsAvecLesTags($tags = array()) {
285
	public function getIdsAvecLesTags($tags = array()) {
276
		return $this->analyserCache($this->options['stockage_chemin'], 'matching', $tags);
286
		return $this->analyserCache($this->options['stockage_chemin'], 'matching', $tags);
277
	}
287
	}
278
 
288
 
279
	/**
289
	/**
280
	 * Return an array of stored cache ids which don't match given tags
290
	 * Return an array of stored cache ids which don't match given tags
281
	 *
291
	 *
282
	 * In case of multiple tags, a logical OR is made between tags
292
	 * In case of multiple tags, a logical OR is made between tags
283
	 *
293
	 *
284
	 * @param array $tags array of tags
294
	 * @param array $tags array of tags
285
	 * @return array array of not matching cache ids (string)
295
	 * @return array array of not matching cache ids (string)
286
	 */
296
	 */
287
	public function getIdsSansLesTags($tags = array()) {
297
	public function getIdsSansLesTags($tags = array()) {
288
		return $this->analyserCache($this->options['stockage_chemin'], 'notMatching', $tags);
298
		return $this->analyserCache($this->options['stockage_chemin'], 'notMatching', $tags);
289
	}
299
	}
290
 
300
 
291
	/**
301
	/**
292
	 * Return an array of stored cache ids which match any given tags
302
	 * Return an array of stored cache ids which match any given tags
293
	 *
303
	 *
294
	 * In case of multiple tags, a logical AND is made between tags
304
	 * In case of multiple tags, a logical AND is made between tags
295
	 *
305
	 *
296
	 * @param array $tags array of tags
306
	 * @param array $tags array of tags
297
	 * @return array array of any matching cache ids (string)
307
	 * @return array array of any matching cache ids (string)
298
	 */
308
	 */
299
	public function getIdsAvecUnTag($tags = array()) {
309
	public function getIdsAvecUnTag($tags = array()) {
300
		return $this->analyserCache($this->options['stockage_chemin'], 'matchingAny', $tags);
310
		return $this->analyserCache($this->options['stockage_chemin'], 'matchingAny', $tags);
301
	}
311
	}
302
 
312
 
303
	/**
313
	/**
304
	 * Return the filling percentage of the backend storage
314
	 * Return the filling percentage of the backend storage
305
	 *
315
	 *
306
	 * @throws Zend_Cache_Exception
316
	 * @throws Zend_Cache_Exception
307
	 * @return int integer between 0 and 100
317
	 * @return int integer between 0 and 100
308
	 */
318
	 */
309
	public function getPourcentageRemplissage() {
319
	public function getPourcentageRemplissage() {
310
		$libre = disk_free_space($this->options['stockage_chemin']);
320
		$libre = disk_free_space($this->options['stockage_chemin']);
311
		$total = disk_total_space($this->options['stockage_chemin']);
321
		$total = disk_total_space($this->options['stockage_chemin']);
312
		
322
		
313
		$pourcentage = 0;
323
		$pourcentage = 0;
314
		if ($total == 0) {
324
		if ($total == 0) {
315
			trigger_error("Impossible d'utiliser la fonction disk_total_space", E_USER_WARNING);
325
			trigger_error("Impossible d'utiliser la fonction disk_total_space", E_USER_WARNING);
316
		} else {
326
		} else {
317
			$pourcentage = ($libre >= $total) ? 100 : ((int) (100. * ($total - $libre) / $total));
327
			$pourcentage = ($libre >= $total) ? 100 : ((int) (100. * ($total - $libre) / $total));
318
		}
328
		}
319
		return $pourcentage;
329
		return $pourcentage;
320
	}
330
	}
321
 
331
 
322
	/**
332
	/**
323
	 * Return an array of metadatas for the given cache id
333
	 * Return an array of metadatas for the given cache id
324
	 *
334
	 *
325
	 * The array must include these keys :
335
	 * The array must include these keys :
326
	 * - expire : the expire timestamp
336
	 * - expire : the expire timestamp
327
	 * - tags : a string array of tags
337
	 * - tags : a string array of tags
328
	 * - mtime : timestamp of last modification time
338
	 * - mtime : timestamp of last modification time
329
	 *
339
	 *
330
	 * @param string $id cache id
340
	 * @param string $id cache id
331
	 * @return array array of metadatas (false if the cache id is not found)
341
	 * @return array array of metadatas (false if the cache id is not found)
332
	 */
342
	 */
333
	public function getMetadonnees($id) {
343
	public function getMetadonnees($id) {
334
		if ($metadonnees = $this->getMetadonneesFichier($id)) {
344
		if ($metadonnees = $this->getMetadonneesFichier($id)) {
335
			if (time() > $metadonnees['expiration']) {
345
			if (time() > $metadonnees['expiration']) {
336
				$metadonnees = false;
346
				$metadonnees = false;
337
			} else {
347
			} else {
338
				$metadonnees = array(
348
				$metadonnees = array(
339
					'expiration' => $metadonnees['expiration'],
349
					'expiration' => $metadonnees['expiration'],
340
					'tags' => $metadonnees['tags'],
350
					'tags' => $metadonnees['tags'],
341
					'mtime' => $metadonnees['mtime']
351
					'mtime' => $metadonnees['mtime']
342
				);
352
				);
343
			}
353
			}
344
		}
354
		}
345
		
355
		
346
		return $metadonnees;
356
		return $metadonnees;
347
	}
357
	}
348
 
358
 
349
	/**
359
	/**
350
	 * Give (if possible) an extra lifetime to the given cache id
360
	 * Give (if possible) an extra lifetime to the given cache id
351
	 *
361
	 *
352
	 * @param string $id cache id
362
	 * @param string $id cache id
353
	 * @param int $extraLifetime
363
	 * @param int $extraLifetime
354
	 * @return boolean true if ok
364
	 * @return boolean true if ok
355
	 */
365
	 */
356
	public function ajouterSupplementDureeDeVie($id, $supplement_duree_de_vie) {
366
	public function ajouterSupplementDureeDeVie($id, $supplement_duree_de_vie) {
357
		$augmentation = true;
367
		$augmentation = true;
358
		if ($metadonnees = $this->getMetadonneesFichier($id)) {
368
		if ($metadonnees = $this->getMetadonneesFichier($id)) {
359
			if (time() > $metadonnees['expiration']) {
369
			if (time() > $metadonnees['expiration']) {
360
				$augmentation = false;
370
				$augmentation = false;
361
			} else {
371
			} else {
362
				$metadonnees_nouvelle = array(
372
				$metadonnees_nouvelle = array(
363
					'hash' => $metadonnees['hash'],
373
					'hash' => $metadonnees['hash'],
364
					'mtime' => time(),
374
					'mtime' => time(),
365
					'expiration' => $metadonnees['expiration'] + $supplement_duree_de_vie,
375
					'expiration' => $metadonnees['expiration'] + $supplement_duree_de_vie,
366
					'tags' => $metadonnees['tags']
376
					'tags' => $metadonnees['tags']
367
				);
377
				);
368
				$augmentation = $this->setMetadonnees($id, $metadonnees_nouvelle);
378
				$augmentation = $this->setMetadonnees($id, $metadonnees_nouvelle);
369
			}
379
			}
370
		}
380
		}
371
		return $augmentation;
381
		return $augmentation;
372
	}
382
	}
373
 
383
 
374
	/**
384
	/**
375
	 * Get a metadatas record
385
	 * Get a metadatas record
376
	 *
386
	 *
377
	 * @param  string $id  Cache id
387
	 * @param  string $id  Cache id
378
	 * @return array|false Associative array of metadatas
388
	 * @return array|false Associative array of metadatas
379
	 */
389
	 */
380
	protected function getMetadonneesFichier($id) {
390
	protected function getMetadonneesFichier($id) {
381
		$metadonnees = false;
391
		$metadonnees = false;
382
		if (isset($this->metadonnees[$id])) {
392
		if (isset($this->metadonnees[$id])) {
383
			$metadonnees = $this->metadonnees[$id];
393
			$metadonnees = $this->metadonnees[$id];
384
		} else {
394
		} else {
385
			if ($metadonnees = $this->chargerMetadonnees($id)) {
395
			if ($metadonnees = $this->chargerMetadonnees($id)) {
386
				$this->setMetadonnees($id, $metadonnees, false);
396
				$this->setMetadonnees($id, $metadonnees, false);
387
			}
397
			}
388
		}
398
		}
389
		return $metadonnees;
399
		return $metadonnees;
390
	}
400
	}
391
 
401
 
392
	/**
402
	/**
393
	 * Set a metadatas record
403
	 * Set a metadatas record
394
	 *
404
	 *
395
	 * @param  string $id		Cache id
405
	 * @param  string $id		Cache id
396
	 * @param  array  $metadatas Associative array of metadatas
406
	 * @param  array  $metadatas Associative array of metadatas
397
	 * @param  boolean $save	 optional pass false to disable saving to file
407
	 * @param  boolean $save	 optional pass false to disable saving to file
398
	 * @return boolean True if no problem
408
	 * @return boolean True if no problem
399
	 */
409
	 */
400
	protected function setMetadonnees($id, $metadonnees, $sauvegarde = true) {
410
	protected function setMetadonnees($id, $metadonnees, $sauvegarde = true) {
401
		if (count($this->metadonnees) >= $this->options['metadonnees_max_taille']) {
411
		if (count($this->metadonnees) >= $this->options['metadonnees_max_taille']) {
402
			$n = (int) ($this->options['metadonnees_max_taille'] / 10);
412
			$n = (int) ($this->options['metadonnees_max_taille'] / 10);
403
			$this->metadonnees = array_slice($this->metadonnees, $n);
413
			$this->metadonnees = array_slice($this->metadonnees, $n);
404
		}
414
		}
405
		
415
		
406
		$resultat = true;
416
		$resultat = true;
407
		if ($sauvegarde) {
417
		if ($sauvegarde) {
408
			$resultat = $this->sauverMetadonnees($id, $metadonnees);
418
			$resultat = $this->sauverMetadonnees($id, $metadonnees);
409
		}
419
		}
410
		if ($resultat == true) {
420
		if ($resultat == true) {
411
			$this->metadonnees[$id] = $metadonnees;
421
			$this->metadonnees[$id] = $metadonnees;
412
		}
422
		}
413
		return $resultat;
423
		return $resultat;
414
	}
424
	}
415
 
425
 
416
	/**
426
	/**
417
	 * Drop a metadata record
427
	 * Drop a metadata record
418
	 *
428
	 *
419
	 * @param  string $id Cache id
429
	 * @param  string $id Cache id
420
	 * @return boolean True if no problem
430
	 * @return boolean True if no problem
421
	 */
431
	 */
422
	protected function supprimerMetadonnees($id) {
432
	protected function supprimerMetadonnees($id) {
423
		if (isset($this->metadonnees[$id])) {
433
		if (isset($this->metadonnees[$id])) {
424
			unset($this->metadonnees[$id]);
434
			unset($this->metadonnees[$id]);
425
		}
435
		}
426
		$fichier_meta = $this->getNomFichierMeta($id);
436
		$fichier_meta = $this->getNomFichierMeta($id);
427
		return $this->supprimerFichier($fichier_meta);
437
		return $this->supprimerFichier($fichier_meta);
428
	}
438
	}
429
 
439
 
430
	/**
440
	/**
431
	 * Clear the metadatas array
441
	 * Clear the metadatas array
432
	 *
442
	 *
433
	 * @return void
443
	 * @return void
434
	 */
444
	 */
435
	protected function nettoyerMetadonnees() {
445
	protected function nettoyerMetadonnees() {
436
		$this->metadonnees = array();
446
		$this->metadonnees = array();
437
	}
447
	}
438
 
448
 
439
	/**
449
	/**
440
	 * Load metadatas from disk
450
	 * Load metadatas from disk
441
	 *
451
	 *
442
	 * @param  string $id Cache id
452
	 * @param  string $id Cache id
443
	 * @return array|false Metadatas associative array
453
	 * @return array|false Metadatas associative array
444
	 */
454
	 */
445
	protected function chargerMetadonnees($id) {
455
	protected function chargerMetadonnees($id) {
446
		$fichier = $this->getNomFichierMeta($id);
456
		$fichier = $this->getNomFichierMeta($id);
447
		if ($resultat = $this->getContenuFichier($fichier)) {
457
		if ($resultat = $this->getContenuFichier($fichier)) {
448
			$resultat = @unserialize($resultat);
458
			$resultat = @unserialize($resultat);
449
		}
459
		}
450
		return $resultat;
460
		return $resultat;
451
	}
461
	}
452
 
462
 
453
	/**
463
	/**
454
	 * Save metadatas to disk
464
	 * Save metadatas to disk
455
	 *
465
	 *
456
	 * @param  string $id		Cache id
466
	 * @param  string $id		Cache id
457
	 * @param  array  $metadatas Associative array
467
	 * @param  array  $metadatas Associative array
458
	 * @return boolean True if no problem
468
	 * @return boolean True if no problem
459
	 */
469
	 */
460
	protected function sauverMetadonnees($id, $metadonnees) {
470
	protected function sauverMetadonnees($id, $metadonnees) {
461
		$fichier = $this->getNomFichierMeta($id);
471
		$fichier = $this->getNomFichierMeta($id);
462
		$resultat = $this->setContenuFichier($fichier, serialize($metadonnees));
472
		$resultat = $this->setContenuFichier($fichier, serialize($metadonnees));
463
		return $resultat;
473
		return $resultat;
464
	}
474
	}
465
 
475
 
466
	/**
476
	/**
467
	 * Make and return a file name (with path) for metadatas
477
	 * Make and return a file name (with path) for metadatas
468
	 *
478
	 *
469
	 * @param  string $id Cache id
479
	 * @param  string $id Cache id
470
	 * @return string Metadatas file name (with path)
480
	 * @return string Metadatas file name (with path)
471
	 */
481
	 */
472
	protected function getNomFichierMeta($id) {
482
	protected function getNomFichierMeta($id) {
473
		$chemin = $this->getChemin($id);
483
		$chemin = $this->getChemin($id);
474
		$fichier_nom = $this->transformaterIdEnNomFichier('interne-meta---'.$id);
484
		$fichier_nom = $this->transformaterIdEnNomFichier('interne-meta---'.$id);
475
		return $chemin.$fichier_nom;
485
		return $chemin.$fichier_nom;
476
	}
486
	}
477
 
487
 
478
	/**
488
	/**
479
	 * Check if the given filename is a metadatas one
489
	 * Check if the given filename is a metadatas one
480
	 *
490
	 *
481
	 * @param  string $fileName File name
491
	 * @param  string $fileName File name
482
	 * @return boolean True if it's a metadatas one
492
	 * @return boolean True if it's a metadatas one
483
	 */
493
	 */
484
	protected function etreFichierMeta($fichier_nom) {
494
	protected function etreFichierMeta($fichier_nom) {
485
		$id = $this->transformerNomFichierEnId($fichier_nom);
495
		$id = $this->transformerNomFichierEnId($fichier_nom);
486
		return (substr($id, 0, 21) == 'interne-meta---') ? true : false;
496
		return (substr($id, 0, 21) == 'interne-meta---') ? true : false;
487
	}
497
	}
488
 
498
 
489
	/**
499
	/**
490
	 * Remove a file
500
	 * Remove a file
491
	 *
501
	 *
492
	 * If we can't remove the file (because of locks or any problem), we will touch
502
	 * If we can't remove the file (because of locks or any problem), we will touch
493
	 * the file to invalidate it
503
	 * the file to invalidate it
494
	 *
504
	 *
495
	 * @param  string $file Complete file path
505
	 * @param  string $file Complete file path
496
	 * @return boolean True if ok
506
	 * @return boolean True if ok
497
	 */
507
	 */
498
	protected function supprimerFichier($fichier) {
508
	protected function supprimerFichier($fichier) {
499
		$resultat = false;
509
		$resultat = false;
500
		if (is_file($fichier)) {
510
		if (is_file($fichier)) {
501
			if ($resultat = @unlink($fichier)) {
511
			if ($resultat = @unlink($fichier)) {
502
				// TODO : ajouter un log
512
				// TODO : ajouter un log
503
			}
513
			}
504
		}
514
		}
505
		return $resultat;
515
		return $resultat;
506
	}
516
	}
507
 
517
 
508
	/**
518
	/**
509
	 * Clean some cache records (protected method used for recursive stuff)
519
	 * Clean some cache records (protected method used for recursive stuff)
510
	 *
520
	 *
511
	 * Available modes are :
521
	 * Available modes are :
512
	 * Zend_Cache::CLEANING_MODE_ALL (default)	=> remove all cache entries ($tags is not used)
522
	 * Zend_Cache::CLEANING_MODE_ALL (default)	=> remove all cache entries ($tags is not used)
513
	 * Zend_Cache::CLEANING_MODE_OLD			  => remove too old cache entries ($tags is not used)
523
	 * Zend_Cache::CLEANING_MODE_OLD			  => remove too old cache entries ($tags is not used)
514
	 * Zend_Cache::CLEANING_MODE_MATCHING_TAG	 => remove cache entries matching all given tags
524
	 * Zend_Cache::CLEANING_MODE_MATCHING_TAG	 => remove cache entries matching all given tags
515
	 *											   ($tags can be an array of strings or a single string)
525
	 *											   ($tags can be an array of strings or a single string)
516
	 * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
526
	 * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
517
	 *											   ($tags can be an array of strings or a single string)
527
	 *											   ($tags can be an array of strings or a single string)
518
	 * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
528
	 * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
519
	 *											   ($tags can be an array of strings or a single string)
529
	 *											   ($tags can be an array of strings or a single string)
520
	 *
530
	 *
521
	 * @param  string $dir  Directory to clean
531
	 * @param  string $dir  Directory to clean
522
	 * @param  string $mode Clean mode
532
	 * @param  string $mode Clean mode
523
	 * @param  array  $tags Array of tags
533
	 * @param  array  $tags Array of tags
524
	 * @throws Zend_Cache_Exception
534
	 * @throws Zend_Cache_Exception
525
	 * @return boolean True if no problem
535
	 * @return boolean True if no problem
526
	 */
536
	 */
527
	protected function nettoyerFichiers($dossier, $mode = Cache::NETTOYAGE_MODE_TOUS, $tags = array()) {
537
	protected function nettoyerFichiers($dossier, $mode = Cache::NETTOYAGE_MODE_TOUS, $tags = array()) {
528
		if (!is_dir($dossier)) {
538
		if (!is_dir($dossier)) {
529
			return false;
539
			return false;
530
		}
540
		}
531
		$resultat = true;
541
		$resultat = true;
532
		$prefixe = $this->options['fichier_prefixe'];
542
		$prefixe = $this->options['fichier_prefixe'];
533
		$glob = @glob($dossier.$prefixe.'--*');
543
		$glob = @glob($dossier.$prefixe.'--*');
534
		if ($glob === false) {
544
		if ($glob === false) {
535
			// On some systems it is impossible to distinguish between empty match and an error.
545
			// On some systems it is impossible to distinguish between empty match and an error.
536
			return true;
546
			return true;
537
		}
547
		}
538
		foreach ($glob as $fichier)  {
548
		foreach ($glob as $fichier)  {
539
			if (is_file($fichier)) {
549
			if (is_file($fichier)) {
540
				$fichier_nom = basename($fichier);
550
				$fichier_nom = basename($fichier);
541
				if ($this->etreFichierMeta($fichier_nom)) {
551
				if ($this->etreFichierMeta($fichier_nom)) {
542
					// Pour le mode Cache::NETTOYAGE_MODE_TOUS, nous essayons de tous supprimer même les vieux fichiers méta
552
					// Pour le mode Cache::NETTOYAGE_MODE_TOUS, nous essayons de tous supprimer même les vieux fichiers méta
543
					if ($mode != Cache::NETTOYAGE_MODE_TOUS) {
553
					if ($mode != Cache::NETTOYAGE_MODE_TOUS) {
544
						continue;
554
						continue;
545
					}
555
					}
546
				}
556
				}
547
				$id = $this->transformerNomFichierEnId($fichier_nom);
557
				$id = $this->transformerNomFichierEnId($fichier_nom);
548
				$metadonnees = $this->getMetadonneesFichier($id);
558
				$metadonnees = $this->getMetadonneesFichier($id);
549
				if ($metadonnees === FALSE) {
559
				if ($metadonnees === FALSE) {
550
					$metadonnees = array('expiration' => 1, 'tags' => array());
560
					$metadonnees = array('expiration' => 1, 'tags' => array());
551
				}
561
				}
552
				switch ($mode) {
562
				switch ($mode) {
553
					case Cache::NETTOYAGE_MODE_TOUS :
563
					case Cache::NETTOYAGE_MODE_TOUS :
554
						if ($resultat_suppression = $this->supprimer($id)) {
564
						if ($resultat_suppression = $this->supprimer($id)) {
555
							// Dans ce cas seulement, nous acception qu'il y ait un problème avec la suppresssion du fichier meta
565
							// Dans ce cas seulement, nous acception qu'il y ait un problème avec la suppresssion du fichier meta
556
							$resultat_suppression = $this->supprimerFichier($fichier);
566
							$resultat_suppression = $this->supprimerFichier($fichier);
557
						}
567
						}
558
						$resultat = $resultat && $resultat_suppression;
568
						$resultat = $resultat && $resultat_suppression;
559
						break;
569
						break;
560
					case Cache::NETTOYAGE_MODE_EXPIRATION :
570
					case Cache::NETTOYAGE_MODE_EXPIRATION :
561
						if (time() > $metadonnees['expiration']) {
571
						if (time() > $metadonnees['expiration']) {
562
							$resultat = $this->supprimer($id) && $resultat;
572
							$resultat = $this->supprimer($id) && $resultat;
563
						}
573
						}
564
						break;
574
						break;
565
					case Cache::NETTOYAGE_MODE_AVEC_LES_TAGS :
575
					case Cache::NETTOYAGE_MODE_AVEC_LES_TAGS :
566
						$correspondance = true;
576
						$correspondance = true;
567
						foreach ($tags as $tag) {
577
						foreach ($tags as $tag) {
568
							if (!in_array($tag, $metadonnees['tags'])) {
578
							if (!in_array($tag, $metadonnees['tags'])) {
569
								$correspondance = false;
579
								$correspondance = false;
570
								break;
580
								break;
571
							}
581
							}
572
						}
582
						}
573
						if ($correspondance) {
583
						if ($correspondance) {
574
							$resultat = $this->supprimer($id) && $resultat;
584
							$resultat = $this->supprimer($id) && $resultat;
575
						}
585
						}
576
						break;
586
						break;
577
					case Cache::NETTOYAGE_MODE_SANS_LES_TAGS :
587
					case Cache::NETTOYAGE_MODE_SANS_LES_TAGS :
578
						$correspondance = false;
588
						$correspondance = false;
579
						foreach ($tags as $tag) {
589
						foreach ($tags as $tag) {
580
							if (in_array($tag, $metadonnees['tags'])) {
590
							if (in_array($tag, $metadonnees['tags'])) {
581
								$correspondance = true;
591
								$correspondance = true;
582
								break;
592
								break;
583
							}
593
							}
584
						}
594
						}
585
						if (!$correspondance) {
595
						if (!$correspondance) {
586
							$resultat = $this->supprimer($id) && $resultat;
596
							$resultat = $this->supprimer($id) && $resultat;
587
						}
597
						}
588
						break;
598
						break;
589
					case Cache::NETTOYAGE_MODE_AVEC_UN_TAG :
599
					case Cache::NETTOYAGE_MODE_AVEC_UN_TAG :
590
						$correspondance = false;
600
						$correspondance = false;
591
						foreach ($tags as $tag) {
601
						foreach ($tags as $tag) {
592
							if (in_array($tag, $metadonnees['tags'])) {
602
							if (in_array($tag, $metadonnees['tags'])) {
593
								$correspondance = true;
603
								$correspondance = true;
594
								break;
604
								break;
595
							}
605
							}
596
						}
606
						}
597
						if ($correspondance) {
607
						if ($correspondance) {
598
							$resultat = $this->supprimer($id) && $resultat;
608
							$resultat = $this->supprimer($id) && $resultat;
599
						}
609
						}
600
						break;
610
						break;
601
					default:
611
					default:
602
						trigger_error("Mode de nettoyage invalide pour la méthode nettoyer()", E_USER_WARNING);
612
						trigger_error("Mode de nettoyage invalide pour la méthode nettoyer()", E_USER_WARNING);
603
						break;
613
						break;
604
				}
614
				}
605
			}
615
			}
606
			if ((is_dir($fichier)) and ($this->options['dossier_niveau'] > 0)) {
616
			if ((is_dir($fichier)) and ($this->options['dossier_niveau'] > 0)) {
607
				// Appel récursif
617
				// Appel récursif
608
				$resultat = $this->nettoyerFichiers($fichier.DS, $mode, $tags) && $resultat;
618
				$resultat = $this->nettoyerFichiers($fichier.DS, $mode, $tags) && $resultat;
609
				if ($mode == Cache::NETTOYAGE_MODE_TOUS) {
619
				if ($mode == Cache::NETTOYAGE_MODE_TOUS) {
610
					// Si mode == Cache::NETTOYAGE_MODE_TOUS, nous essayons de supprimer la structure aussi
620
					// Si mode == Cache::NETTOYAGE_MODE_TOUS, nous essayons de supprimer la structure aussi
611
					@rmdir($fichier);
621
					@rmdir($fichier);
612
				}
622
				}
613
			}
623
			}
614
		}
624
		}
615
		return $resultat;
625
		return $resultat;
616
	}
626
	}
617
 
627
 
618
	protected function analyserCache($dossier, $mode, $tags = array()) {
628
	protected function analyserCache($dossier, $mode, $tags = array()) {
619
		if (!is_dir($dossier)) {
629
		if (!is_dir($dossier)) {
620
			return false;
630
			return false;
621
		}
631
		}
622
		$resultat = array();
632
		$resultat = array();
623
		$prefixe = $this->options['fichier_prefixe'];
633
		$prefixe = $this->options['fichier_prefixe'];
624
		$glob = @glob($dossier.$prefixe.'--*');
634
		$glob = @glob($dossier.$prefixe.'--*');
625
		if ($glob === false) {
635
		if ($glob === false) {
626
			// On some systems it is impossible to distinguish between empty match and an error.
636
			// On some systems it is impossible to distinguish between empty match and an error.
627
			return array();
637
			return array();
628
		}
638
		}
629
		foreach ($glob as $fichier)  {
639
		foreach ($glob as $fichier)  {
630
			if (is_file($fichier)) {
640
			if (is_file($fichier)) {
631
				$nom_fichier = basename($fichier);
641
				$nom_fichier = basename($fichier);
632
				$id = $this->transformerNomFichierEnId($nom_fichier);
642
				$id = $this->transformerNomFichierEnId($nom_fichier);
633
				$metadonnees = $this->getMetadonneesFichier($id);
643
				$metadonnees = $this->getMetadonneesFichier($id);
634
				if ($metadonnees === FALSE) {
644
				if ($metadonnees === FALSE) {
635
					continue;
645
					continue;
636
				}
646
				}
637
				if (time() > $metadonnees['expiration']) {
647
				if (time() > $metadonnees['expiration']) {
638
					continue;
648
					continue;
639
				}
649
				}
640
				switch ($mode) {
650
				switch ($mode) {
641
					case 'ids':
651
					case 'ids':
642
						$resultat[] = $id;
652
						$resultat[] = $id;
643
						break;
653
						break;
644
					case 'tags':
654
					case 'tags':
645
						$resultat = array_unique(array_merge($resultat, $metadonnees['tags']));
655
						$resultat = array_unique(array_merge($resultat, $metadonnees['tags']));
646
						break;
656
						break;
647
					case 'matching':
657
					case 'matching':
648
						$correspondance = true;
658
						$correspondance = true;
649
						foreach ($tags as $tag) {
659
						foreach ($tags as $tag) {
650
							if (!in_array($tag, $metadonnees['tags'])) {
660
							if (!in_array($tag, $metadonnees['tags'])) {
651
								$correspondance = false;
661
								$correspondance = false;
652
								break;
662
								break;
653
							}
663
							}
654
						}
664
						}
655
						if ($correspondance) {
665
						if ($correspondance) {
656
							$resultat[] = $id;
666
							$resultat[] = $id;
657
						}
667
						}
658
						break;
668
						break;
659
					case 'notMatching':
669
					case 'notMatching':
660
						$correspondance = false;
670
						$correspondance = false;
661
						foreach ($tags as $tag) {
671
						foreach ($tags as $tag) {
662
							if (in_array($tag, $metadonnees['tags'])) {
672
							if (in_array($tag, $metadonnees['tags'])) {
663
								$correspondance = true;
673
								$correspondance = true;
664
								break;
674
								break;
665
							}
675
							}
666
						}
676
						}
667
						if (!$correspondance) {
677
						if (!$correspondance) {
668
							$resultat[] = $id;
678
							$resultat[] = $id;
669
						}
679
						}
670
						break;
680
						break;
671
					case 'matchingAny':
681
					case 'matchingAny':
672
						$correspondance = false;
682
						$correspondance = false;
673
						foreach ($tags as $tag) {
683
						foreach ($tags as $tag) {
674
							if (in_array($tag, $metadonnees['tags'])) {
684
							if (in_array($tag, $metadonnees['tags'])) {
675
								$correspondance = true;
685
								$correspondance = true;
676
								break;
686
								break;
677
							}
687
							}
678
						}
688
						}
679
						if ($correspondance) {
689
						if ($correspondance) {
680
							$resultat[] = $id;
690
							$resultat[] = $id;
681
						}
691
						}
682
						break;
692
						break;
683
					default:
693
					default:
684
						trigger_error("Mode invalide pour la méthode analyserCache()", E_USER_WARNING);
694
						trigger_error("Mode invalide pour la méthode analyserCache()", E_USER_WARNING);
685
						break;
695
						break;
686
				}
696
				}
687
			}
697
			}
688
			if ((is_dir($fichier)) and ($this->options['dossier_niveau'] > 0)) {
698
			if ((is_dir($fichier)) and ($this->options['dossier_niveau'] > 0)) {
689
				// Appel récursif
699
				// Appel récursif
690
				$resultat_analyse_recursive = $this->analyserCache($fichier.DS, $mode, $tags);
700
				$resultat_analyse_recursive = $this->analyserCache($fichier.DS, $mode, $tags);
691
				if ($resultat_analyse_recursive === false) {
701
				if ($resultat_analyse_recursive === false) {
692
					// TODO : ajoute un log
702
					// TODO : ajoute un log
693
				} else {
703
				} else {
694
					$resultat = array_unique(array_merge($resultat, $resultat_analyse_recursive));
704
					$resultat = array_unique(array_merge($resultat, $resultat_analyse_recursive));
695
				}
705
				}
696
			}
706
			}
697
		}
707
		}
698
		return array_unique($resultat);
708
		return array_unique($resultat);
699
	}
709
	}
700
 
710
 
701
	/**
711
	/**
702
	 * Make a control key with the string containing datas
712
	 * Make a control key with the string containing datas
703
	 *
713
	 *
704
	 * @param  string $data		Data
714
	 * @param  string $data		Data
705
	 * @param  string $controlType Type of control 'md5', 'crc32' or 'strlen'
715
	 * @param  string $controlType Type of control 'md5', 'crc32' or 'strlen'
706
	 * @throws Zend_Cache_Exception
716
	 * @throws Zend_Cache_Exception
707
	 * @return string Control key
717
	 * @return string Control key
708
	 */
718
	 */
709
	protected function genererCleSecu($donnees, $type_de_controle) {
719
	protected function genererCleSecu($donnees, $type_de_controle) {
710
		switch ($type_de_controle) {
720
		switch ($type_de_controle) {
711
		case 'md5':
721
		case 'md5':
712
			return md5($donnees);
722
			return md5($donnees);
713
		case 'crc32':
723
		case 'crc32':
714
			return crc32($donnees);
724
			return crc32($donnees);
715
		case 'strlen':
725
		case 'strlen':
716
			return strlen($donnees);
726
			return strlen($donnees);
717
		case 'adler32':
727
		case 'adler32':
718
			return hash('adler32', $donnees);
728
			return hash('adler32', $donnees);
719
		default:
729
		default:
720
			trigger_error("Fonction de génération de clé de sécurité introuvable : $type_de_controle", E_USER_WARNING);
730
			trigger_error("Fonction de génération de clé de sécurité introuvable : $type_de_controle", E_USER_WARNING);
721
		}
731
		}
722
	}
732
	}
723
 
733
 
724
	/**
734
	/**
725
	 * Transform a cache id into a file name and return it
735
	 * Transform a cache id into a file name and return it
726
	 *
736
	 *
727
	 * @param  string $id Cache id
737
	 * @param  string $id Cache id
728
	 * @return string File name
738
	 * @return string File name
729
	 */
739
	 */
730
	protected function transformaterIdEnNomFichier($id) {
740
	protected function transformaterIdEnNomFichier($id) {
731
		$prefixe = $this->options['fichier_prefixe'];
741
		$prefixe = $this->options['fichier_prefixe'];
732
		$resultat = $prefixe.'---'.$id;
742
		$resultat = $prefixe.'---'.$id;
733
		return $resultat;
743
		return $resultat;
734
	}
744
	}
735
 
745
 
736
	/**
746
	/**
737
	 * Make and return a file name (with path)
747
	 * Make and return a file name (with path)
738
	 *
748
	 *
739
	 * @param  string $id Cache id
749
	 * @param  string $id Cache id
740
	 * @return string File name (with path)
750
	 * @return string File name (with path)
741
	 */
751
	 */
742
	protected function getFichierNom($id) {
752
	protected function getFichierNom($id) {
743
		$path = $this->getChemin($id);
753
		$path = $this->getChemin($id);
744
		$fileName = $this->transformaterIdEnNomFichier($id);
754
		$fileName = $this->transformaterIdEnNomFichier($id);
745
		return $path . $fileName;
755
		return $path . $fileName;
746
	}
756
	}
747
 
757
 
748
	/**
758
	/**
749
	 * Return the complete directory path of a filename (including hashedDirectoryStructure)
759
	 * Return the complete directory path of a filename (including hashedDirectoryStructure)
750
	 *
760
	 *
751
	 * @param  string $id Cache id
761
	 * @param  string $id Cache id
752
	 * @param  boolean $decoupage if true, returns array of directory parts instead of single string
762
	 * @param  boolean $decoupage if true, returns array of directory parts instead of single string
753
	 * @return string Complete directory path
763
	 * @return string Complete directory path
754
	 */
764
	 */
755
	protected function getChemin($id, $decoupage = false) {
765
	protected function getChemin($id, $decoupage = false) {
756
		$morceaux = array();
766
		$morceaux = array();
757
		$chemin = $this->options['stockage_chemin'];
767
		$chemin = $this->options['stockage_chemin'];
758
		$prefixe = $this->options['fichier_prefixe'];
768
		$prefixe = $this->options['fichier_prefixe'];
759
		if ($this->options['dossier_niveau'] > 0) {
769
		if ($this->options['dossier_niveau'] > 0) {
760
			$hash = hash('adler32', $id);
770
			$hash = hash('adler32', $id);
761
			for ($i = 0 ; $i < $this->options['dossier_niveau'] ; $i++) {
771
			for ($i = 0 ; $i < $this->options['dossier_niveau'] ; $i++) {
762
				$chemin .= $prefixe.'--'.substr($hash, 0, $i + 1).DS;
772
				$chemin .= $prefixe.'--'.substr($hash, 0, $i + 1).DS;
763
				$morceaux[] = $chemin;
773
				$morceaux[] = $chemin;
764
			}
774
			}
765
		}
775
		}
766
		return ($decoupage) ? 	$morceaux : $chemin;
776
		return ($decoupage) ? 	$morceaux : $chemin;
767
	}
777
	}
768
 
778
 
769
	/**
779
	/**
770
	 * Make the directory strucuture for the given id
780
	 * Make the directory strucuture for the given id
771
	 *
781
	 *
772
	 * @param string $id cache id
782
	 * @param string $id cache id
773
	 * @return boolean true
783
	 * @return boolean true
774
	 */
784
	 */
775
	protected function lancerMkdirEtChmodRecursif($id) {
785
	protected function lancerMkdirEtChmodRecursif($id) {
776
		$resultat = true;
786
		$resultat = true;
777
		if ($this->options['dossier_niveau'] > 0) {
787
		if ($this->options['dossier_niveau'] > 0) {
778
			$chemins = $this->getChemin($id, true);
788
			$chemins = $this->getChemin($id, true);
779
			foreach ($chemins as $chemin) {
789
			foreach ($chemins as $chemin) {
780
				if (!is_dir($chemin)) {
790
				if (!is_dir($chemin)) {
781
					@mkdir($chemin, $this->options['dossier_umask']);
791
					@mkdir($chemin, $this->options['dossier_umask']);
782
					@chmod($chemin, $this->options['dossier_umask']); // see #ZF-320 (this line is required in some configurations)
792
					@chmod($chemin, $this->options['dossier_umask']); // see #ZF-320 (this line is required in some configurations)
783
				}
793
				}
784
			}
794
			}
785
		}
795
		}
786
		return $resultat;
796
		return $resultat;
787
	}
797
	}
788
 
798
 
789
	/**
799
	/**
790
	 * Test if the given cache id is available (and still valid as a cache record)
800
	 * Test if the given cache id is available (and still valid as a cache record)
791
	 *
801
	 *
792
	 * @param  string  $id					 Cache id
802
	 * @param  string  $id					 Cache id
793
	 * @param  boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
803
	 * @param  boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
794
	 * @return boolean|mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
804
	 * @return boolean|mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
795
	 */
805
	 */
796
	protected function testerExistenceCache($id, $ne_pas_tester_validiter_du_cache) {
806
	protected function testerExistenceCache($id, $ne_pas_tester_validiter_du_cache) {
797
		$resultat = false;
807
		$resultat = false;
798
		if ($metadonnees = $this->getMetadonnees($id)) {
808
		if ($metadonnees = $this->getMetadonnees($id)) {
799
			if ($ne_pas_tester_validiter_du_cache || (time() <= $metadonnees['expiration'])) {
809
			if ($ne_pas_tester_validiter_du_cache || (time() <= $metadonnees['expiration'])) {
800
				$resultat =  $metadonnees['mtime'];
810
				$resultat =  $metadonnees['mtime'];
801
			}
811
			}
802
		}
812
		}
803
		return $resultat;
813
		return $resultat;
804
	}
814
	}
805
 
815
 
806
	/**
816
	/**
807
	 * Return the file content of the given file
817
	 * Return the file content of the given file
808
	 *
818
	 *
809
	 * @param  string $file File complete path
819
	 * @param  string $file File complete path
810
	 * @return string File content (or false if problem)
820
	 * @return string File content (or false if problem)
811
	 */
821
	 */
812
	protected function getContenuFichier($fichier) {
822
	protected function getContenuFichier($fichier) {
813
		$resultat = false;
823
		$resultat = false;
814
		if (is_file($fichier)) {
824
		if (is_file($fichier)) {
815
			$f = @fopen($fichier, 'rb');
825
			$f = @fopen($fichier, 'rb');
816
			if ($f) {
826
			if ($f) {
817
				if ($this->options['fichier_verrou']) @flock($f, LOCK_SH);
827
				if ($this->options['fichier_verrou']) @flock($f, LOCK_SH);
818
				$resultat = stream_get_contents($f);
828
				$resultat = stream_get_contents($f);
819
				if ($this->options['fichier_verrou']) @flock($f, LOCK_UN);
829
				if ($this->options['fichier_verrou']) @flock($f, LOCK_UN);
820
				@fclose($f);
830
				@fclose($f);
821
			}
831
			}
822
		}
832
		}
823
		return $resultat;
833
		return $resultat;
824
	}
834
	}
825
 
835
 
826
	/**
836
	/**
827
	 * Put the given string into the given file
837
	 * Put the given string into the given file
828
	 *
838
	 *
829
	 * @param  string $file   File complete path
839
	 * @param  string $file   File complete path
830
	 * @param  string $string String to put in file
840
	 * @param  string $string String to put in file
831
	 * @return boolean true if no problem
841
	 * @return boolean true if no problem
832
	 */
842
	 */
833
	protected function setContenuFichier($fichier, $chaine) {
843
	protected function setContenuFichier($fichier, $chaine) {
834
		$resultat = false;
844
		$resultat = false;
835
		$f = @fopen($fichier, 'ab+');
845
		$f = @fopen($fichier, 'ab+');
836
		if ($f) {
846
		if ($f) {
837
			if ($this->options['fichier_verrou']) @flock($f, LOCK_EX);
847
			if ($this->options['fichier_verrou']) @flock($f, LOCK_EX);
838
			fseek($f, 0);
848
			fseek($f, 0);
839
			ftruncate($f, 0);
849
			ftruncate($f, 0);
840
			$tmp = @fwrite($f, $chaine);
850
			$tmp = @fwrite($f, $chaine);
841
			if (!($tmp === FALSE)) {
851
			if (!($tmp === FALSE)) {
842
				$resultat = true;
852
				$resultat = true;
843
			}
853
			}
844
			@fclose($f);
854
			@fclose($f);
845
		}
855
		}
846
		@chmod($fichier, $this->options['fichier_umask']);
856
		@chmod($fichier, $this->options['fichier_umask']);
847
		return $resultat;
857
		return $resultat;
848
	}
858
	}
849
 
859
 
850
	/**
860
	/**
851
	 * Transform a file name into cache id and return it
861
	 * Transform a file name into cache id and return it
852
	 *
862
	 *
853
	 * @param  string $fileName File name
863
	 * @param  string $fileName File name
854
	 * @return string Cache id
864
	 * @return string Cache id
855
	 */
865
	 */
856
	protected function transformerNomFichierEnId($nom_de_fichier) {
866
	protected function transformerNomFichierEnId($nom_de_fichier) {
857
		$prefixe = $this->options['fichier_prefixe'];
867
		$prefixe = $this->options['fichier_prefixe'];
858
		return preg_replace('~^' . $prefixe . '---(.*)$~', '$1', $nom_de_fichier);
868
		return preg_replace('~^' . $prefixe . '---(.*)$~', '$1', $nom_de_fichier);
859
	}
869
	}
860
}
870
}
861
?>
871
?>