Overview

Packages

  • Framework
  • None
  • PHP
  • Utilitaire

Classes

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