Subversion Repositories Applications.framework

Rev

Rev 250 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

<?php
class CacheFichier {
        /**
         * Available options
         *
         * =====> (string) cache_dir :
         * - Directory where to put the cache files
         *
         * =====> (boolean) file_locking :
         * - Enable / disable file_locking
         * - Can avoid cache corruption under bad circumstances but it doesn't work on multithread
         * webservers and on NFS filesystems for example
         *
         * =====> (boolean) read_control :
         * - Enable / disable read control
         * - If enabled, a control key is embeded in cache file and this key is compared with the one
         * calculated after the reading.
         *
         * =====> (string) read_control_type :
         * - Type of read control (only if read control is enabled). Available values are :
         *   'md5' for a md5 hash control (best but slowest)
         *   'crc32' for a crc32 hash control (lightly less safe but faster, better choice)
         *   'adler32' for an adler32 hash control (excellent choice too, faster than crc32)
         *   'strlen' for a length only test (fastest)
         *
         * =====> (int) hashed_directory_level :
         * - Hashed directory level
         * - Set the hashed directory structure level. 0 means "no hashed directory
         * structure", 1 means "one level of directory", 2 means "two levels"...
         * This option can speed up the cache only when you have many thousands of
         * cache file. Only specific benchs can help you to choose the perfect value
         * for you. Maybe, 1 or 2 is a good start.
         *
         * =====> (int) hashed_directory_umask :
         * - Umask for hashed directory structure
         *
         * =====> (string) file_name_prefix :
         * - prefix for cache files
         * - be really carefull with this option because a too generic value in a system cache dir
         *   (like /tmp) can cause disasters when cleaning the cache
         *
         * =====> (int) cache_file_umask :
         * - Umask for cache files
         *
         * =====> (int) metatadatas_array_max_size :
         * - max size for the metadatas array (don't change this value unless you
         *   know what you are doing)
         *
         * @var array available options
         */
        protected $options = array(
                'stockage_chemin' => null,
                'fichier_verrou' => true,// file_locking
                'controle_lecture' => true,// controle de lecture
                'controle_lecture_type' => 'crc32',
                'dossier_niveau' => 0,
                'dossier_umask' => 0700,
                'fichier_prefixe' => 'tbf',
                'fichier_umask' => 0600,
                'metadonnees_max_taille' => 100
        );

        /**
         * Array of metadatas (each item is an associative array)
         *
         * @var array
         */
        protected $metadonnees = array(); // metadatasArray


        /**
         * Constructor
         *
         * @param  array $options associative array of options
         * @throws Zend_Cache_Exception
         * @return void
         */
        public function __construct(array $options = array()) {
                if (isset($this->options['prefixe_fichier'])) {
                        if (!preg_match('~^[a-zA-Z0-9_]+$~D', $this->options['prefixe_fichier'])) {
                                trigger_error("Préfixe de nom de fichier invalide : doit contenir seulement [a-zA-Z0-9_]", E_USER_WARNING);
                        }
                }
                if ($this->_options['metadonnees_max_taille'] < 10) {
                        trigger_error("Taille du tableau des méta-données invalide, elle doit être > 10", E_USER_WARNING);
                }
                if (isset($options['dossier_umask']) && is_string($options['dossier_umask'])) {
                        // See #ZF-4422
                        $this->options['dossier_umask'] = octdec($this->options['dossier_umask']);
                }
                if (isset($options['fichier_umask']) && is_string($options['fichier_umask'])) {
                        // See #ZF-4422
                        $this->options['fichier_umask'] = octdec($this->options['fichier_umask']);
                }
        }

        private function setEmplacement($emplacement) {
                if (!is_dir($emplacement)) {
                        trigger_error("L'emplacement doit être un dossier.", E_USER_WARNING);
                }
                if (!is_writable($emplacement)) {
                        trigger_error("Le dossier de stockage du cache n'est pas accessible en écriture", E_USER_WARNING);
                }
                $emplacement = rtrim(realpath($emplacement), '\\/').DS;
                $this->options['stockage_chemin'] = $emplacement;
        }

        /**
         * Test if a cache is available for the given id and (if yes) return it (false else)
         *
         * @param string $id cache id
         * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
         * @return string|false cached datas
         */
        public function charger($id, $ne_pas_tester_validiter_du_cache = false) {
                $donnees = false;
                if ($this->tester($id, $ne_pas_tester_validiter_du_cache)) {
                        $metadonnees = $this->getMetadonneesFichier($id);
                        $fichier = $this->getFichierNom($id);
                        $donnees = $this->getContenuFichier($fichier);
                        if ($this->options['controle_lecture']) {
                                $cle_secu_donnees = $this->genererCleSecu($donnees, $this->options['controle_lecture_type']);
                                $cle_secu_controle = $metadonnees['hash'];
                                if ($cle_secu_donnees != $cle_secu_controle) {
                                        // Probléme détecté par le contrôle de lecture !
                                        // TODO : loguer le pb de sécu
                                        $this->supprimer($id);
                                        $donnees = false;
                                }
                        }
                }
                return $donnees;
        }

        /**
         * Teste si un enregistrement en cache est disponible ou pas (pour l'id passé en paramètre).
         *
         * @param string $id identifiant de cache.
         * @return mixed false (le cache n'est pas disponible) ou timestamp (int) "de dernière modification" de l'enregistrement en cache
         */
        public function tester($id) {
                clearstatcache();
                return $this->testerExistenceCache($id, false);
        }

        /**
         * Save some string datas into a cache record
         *
         * Note : $data is always "string" (serialization is done by the
         * core not by the backend)
         *
         * @param  string $data                  Datas to cache
         * @param  string $id                      Cache id
         * @param  array  $tags                  Array of strings, the cache record will be tagged by each string entry
         * @param  int  $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
         * @return boolean true if no problem
         */
        public function save($data, $id, $tags = array(), $specificLifetime = false) {
                clearstatcache();
                $file = $this->getFichierNom($id);
                $path = $this->getChemin($id);
                if ($this->_options['hashed_directory_level'] > 0) {
                        if (!is_writable($path)) {
                                // maybe, we just have to build the directory structure
                                $this->lancerMkdirEtChmodRecursif($id);
                        }
                        if (!is_writable($path)) {
                                return false;
                        }
                }
                if ($this->_options['read_control']) {
                        $hash = $this->genererCleSecu($data, $this->_options['read_control_type']);
                } else {
                        $hash = '';
                }
                $metadatas = array(
                        'hash' => $hash,
                        'mtime' => time(),
                        'expire' => $this->_expireTime($this->getLifetime($specificLifetime)),
                        'tags' => $tags
                );
                $res = $this->_setMetadatas($id, $metadatas);
                if (!$res) {
                        $this->_log('Zend_Cache_Backend_File::save() / error on saving metadata');
                        return false;
                }
                $res = $this->setContenuFichier($file, $data);
                return $res;
        }

        /**
         * Remove a cache record
         *
         * @param  string $id cache id
         * @return boolean true if no problem
         */
        public function supprimer($id) {
                $fichier = $this->getFichierNom($id);
                $suppression_fichier = $this->supprimerFichier($fichier);
                $suppression_metadonnees = $this->supprimerMetadonnees($id);
                return $suppression_metadonnees && $suppression_fichier;
        }

        /**
         * Clean some cache records
         *
         * Available modes are :
         * 'all' (default)  => remove all cache entries ($tags is not used)
         * 'old'                        => remove too old cache entries ($tags is not used)
         * 'matchingTag'        => remove cache entries matching all given tags
         *                                       ($tags can be an array of strings or a single string)
         * 'notMatchingTag' => remove cache entries not matching one of the given tags
         *                                       ($tags can be an array of strings or a single string)
         * 'matchingAnyTag' => remove cache entries matching any given tags
         *                                       ($tags can be an array of strings or a single string)
         *
         * @param string $mode clean mode
         * @param tags array $tags array of tags
         * @return boolean true if no problem
         */
        public function nettoyer($mode = Cache::NETTOYAGE_MODE_TOUS, $tags = array()) {
                // We use this protected method to hide the recursive stuff
                clearstatcache();
                return $this->nettoyerFichiers($this->options['stockage_dossier'], $mode, $tags);
        }

        /**
         * Return an array of stored cache ids
         *
         * @return array array of stored cache ids (string)
         */
        public function getIds()
        {
                return $this->_get($this->_options['cache_dir'], 'ids', array());
        }

        /**
         * Return an array of stored tags
         *
         * @return array array of stored tags (string)
         */
        public function getTags()
        {
                return $this->_get($this->_options['cache_dir'], 'tags', array());
        }

        /**
         * Return an array of stored cache ids which match given tags
         *
         * In case of multiple tags, a logical AND is made between tags
         *
         * @param array $tags array of tags
         * @return array array of matching cache ids (string)
         */
        public function getIdsMatchingTags($tags = array())
        {
                return $this->_get($this->_options['cache_dir'], 'matching', $tags);
        }

        /**
         * Return an array of stored cache ids which don't match given tags
         *
         * In case of multiple tags, a logical OR is made between tags
         *
         * @param array $tags array of tags
         * @return array array of not matching cache ids (string)
         */
        public function getIdsNotMatchingTags($tags = array())
        {
                return $this->_get($this->_options['cache_dir'], 'notMatching', $tags);
        }

        /**
         * Return an array of stored cache ids which match any given tags
         *
         * In case of multiple tags, a logical AND is made between tags
         *
         * @param array $tags array of tags
         * @return array array of any matching cache ids (string)
         */
        public function getIdsMatchingAnyTags($tags = array())
        {
                return $this->_get($this->_options['cache_dir'], 'matchingAny', $tags);
        }

        /**
         * Return the filling percentage of the backend storage
         *
         * @throws Zend_Cache_Exception
         * @return int integer between 0 and 100
         */
        public function getFillingPercentage()
        {
                $free = disk_free_space($this->_options['cache_dir']);
                $total = disk_total_space($this->_options['cache_dir']);
                if ($total == 0) {
                        Zend_Cache::throwException('can\'t get disk_total_space');
                } else {
                        if ($free >= $total) {
                                return 100;
                        }
                        return ((int) (100. * ($total - $free) / $total));
                }
        }

        /**
         * Return an array of metadatas for the given cache id
         *
         * The array must include these keys :
         * - expire : the expire timestamp
         * - tags : a string array of tags
         * - mtime : timestamp of last modification time
         *
         * @param string $id cache id
         * @return array array of metadatas (false if the cache id is not found)
         */
        public function getMetadatas($id)
        {
                $metadatas = $this->getMetadonneesFichier($id);
                if (!$metadatas) {
                        return false;
                }
                if (time() > $metadatas['expire']) {
                        return false;
                }
                return array(
                        'expire' => $metadatas['expire'],
                        'tags' => $metadatas['tags'],
                        'mtime' => $metadatas['mtime']
                );
        }

        /**
         * Give (if possible) an extra lifetime to the given cache id
         *
         * @param string $id cache id
         * @param int $extraLifetime
         * @return boolean true if ok
         */
        public function touch($id, $extraLifetime)
        {
                $metadatas = $this->getMetadonneesFichier($id);
                if (!$metadatas) {
                        return false;
                }
                if (time() > $metadatas['expire']) {
                        return false;
                }
                $newMetadatas = array(
                        'hash' => $metadatas['hash'],
                        'mtime' => time(),
                        'expire' => $metadatas['expire'] + $extraLifetime,
                        'tags' => $metadatas['tags']
                );
                $res = $this->_setMetadatas($id, $newMetadatas);
                if (!$res) {
                        return false;
                }
                return true;
        }

        /**
         * Get a metadatas record
         *
         * @param  string $id  Cache id
         * @return array|false Associative array of metadatas
         */
        protected function getMetadonneesFichier($id) {
                $metadonnees = false;
                if (isset($this->metadonnees[$id])) {
                        $metadonnees = $this->metadonnees[$id];
                } else {
                        if ($metadonnees = $this->chargerMetadonnees($id)) {
                                $this->setMetadonnees($id, $metadonnees, false);
                        }
                }
                return $metadonnees;
        }

        /**
         * Set a metadatas record
         *
         * @param  string $id           Cache id
         * @param  array  $metadatas Associative array of metadatas
         * @param  boolean $save         optional pass false to disable saving to file
         * @return boolean True if no problem
         */
        protected function setMetadonnees($id, $metadonnees, $sauvegarde = true) {
                if (count($this->metadonnees) >= $this->options['metadonnees_max_taille']) {
                        $n = (int) ($this->options['metadonnees_max_taille'] / 10);
                        $this->metadonnees = array_slice($this->metadonnees, $n);
                }
                
                $resultat = true;
                if ($sauvegarde) {
                        $resultat = $this->sauverMetadonnees($id, $metadonnees);
                }
                if ($resultat == true) {
                        $this->metadonnees[$id] = $metadonnees;
                }
                return $resultat;
        }

        /**
         * Drop a metadata record
         *
         * @param  string $id Cache id
         * @return boolean True if no problem
         */
        protected function supprimerMetadonnees($id) {
                if (isset($this->metadonnees[$id])) {
                        unset($this->metadonnees[$id]);
                }
                $fichier_meta = $this->getNomFichierMeta($id);
                return $this->supprimerFichier($fichier_meta);
        }

        /**
         * Clear the metadatas array
         *
         * @return void
         */
        protected function nettoyerMetadonnees() {
                $this->metadonnees = array();
        }

        /**
         * Load metadatas from disk
         *
         * @param  string $id Cache id
         * @return array|false Metadatas associative array
         */
        protected function chargerMetadonnees($id) {
                $fichier = $this->getNomFichierMeta($id);
                if ($resultat = $this->getContenuFichier($fichier)) {
                        $resultat = @unserialize($resultat);
                }
                return $resultat;
        }

        /**
         * Save metadatas to disk
         *
         * @param  string $id           Cache id
         * @param  array  $metadatas Associative array
         * @return boolean True if no problem
         */
        protected function sauverMetadonnees($id, $metadonnees) {
                $fichier = $this->getNomFichierMeta($id);
                $resultat = $this->setContenuFichier($fichier, serialize($metadonnees));
                return $resultat;
        }

        /**
         * Make and return a file name (with path) for metadatas
         *
         * @param  string $id Cache id
         * @return string Metadatas file name (with path)
         */
        protected function getNomFichierMeta($id) {
                $chemin = $this->getChemin($id);
                $fichier_nom = $this->transformaterIdEnNomFichier('internal-metadatas---'.$id);
                return $chemin.$fichier_nom;
        }

        /**
         * Check if the given filename is a metadatas one
         *
         * @param  string $fileName File name
         * @return boolean True if it's a metadatas one
         */
        protected function etreFichierMeta($fichier_nom) {
                $id = $this->transformerNomFichierEnId($fichier_nom);
                return (substr($id, 0, 21) == 'internal-metadatas---') ? true : false;
        }

        /**
         * Remove a file
         *
         * If we can't remove the file (because of locks or any problem), we will touch
         * the file to invalidate it
         *
         * @param  string $file Complete file path
         * @return boolean True if ok
         */
        protected function supprimerFichier($fichier) {
                $resultat = false;
                if (is_file($fichier)) {
                        if ($resultat = @unlink($fichier)) {
                                // TODO : ajouter un log
                        }
                }
                return $resultat;
        }

        /**
         * Clean some cache records (protected method used for recursive stuff)
         *
         * Available modes are :
         * Zend_Cache::CLEANING_MODE_ALL (default)      => remove all cache entries ($tags is not used)
         * Zend_Cache::CLEANING_MODE_OLD                          => remove too old cache entries ($tags is not used)
         * Zend_Cache::CLEANING_MODE_MATCHING_TAG        => remove cache entries matching all given tags
         *                                                                                         ($tags can be an array of strings or a single string)
         * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
         *                                                                                         ($tags can be an array of strings or a single string)
         * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
         *                                                                                         ($tags can be an array of strings or a single string)
         *
         * @param  string $dir  Directory to clean
         * @param  string $mode Clean mode
         * @param  array  $tags Array of tags
         * @throws Zend_Cache_Exception
         * @return boolean True if no problem
         */
        protected function nettoyerFichiers($dossier, $mode = Cache::NETTOYAGE_MODE_TOUS, $tags = array()) {
                if (!is_dir($dossier)) {
                        return false;
                }
                $resultat = true;
                $prefixe = $this->options['fichier_prefixe'];
                $glob = @glob($dossier.$prefixe.'--*');
                if ($glob === false) {
                        // On some systems it is impossible to distinguish between empty match and an error.
                        return true;
                }
                foreach ($glob as $fichier)  {
                        if (is_file($fichier)) {
                                $fichier_nom = basename($fichier);
                                if ($this->etreFichierMeta($fichier_nom)) {
                                        // in CLEANING_MODE_ALL, we drop anything, even remainings old metadatas files
                                        if ($mode != Cache::NETTOYAGE_MODE_TOUS) {
                                                continue;
                                        }
                                }
                                $id = $this->transformerNomFichierEnId($fichier_nom);
                                $metadatas = $this->getMetadonneesFichier($id);
                                if ($metadatas === FALSE) {
                                        $metadatas = array('expire' => 1, 'tags' => array());
                                }
                                switch ($mode) {
                                        case Zend_Cache::CLEANING_MODE_ALL:
                                                $res = $this->remove($id);
                                                if (!$res) {
                                                        // in this case only, we accept a problem with the metadatas file drop
                                                        $res = $this->supprimerFichier($file);
                                                }
                                                $resultat = $resultat && $res;
                                                break;
                                        case Zend_Cache::CLEANING_MODE_OLD:
                                                if (time() > $metadatas['expire']) {
                                                        $resultat = $this->remove($id) && $resultat;
                                                }
                                                break;
                                        case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
                                                $matching = true;
                                                foreach ($tags as $tag) {
                                                        if (!in_array($tag, $metadatas['tags'])) {
                                                                $matching = false;
                                                                break;
                                                        }
                                                }
                                                if ($matching) {
                                                        $resultat = $this->remove($id) && $resultat;
                                                }
                                                break;
                                        case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
                                                $matching = false;
                                                foreach ($tags as $tag) {
                                                        if (in_array($tag, $metadatas['tags'])) {
                                                                $matching = true;
                                                                break;
                                                        }
                                                }
                                                if (!$matching) {
                                                        $resultat = $this->remove($id) && $resultat;
                                                }
                                                break;
                                        case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
                                                $matching = false;
                                                foreach ($tags as $tag) {
                                                        if (in_array($tag, $metadatas['tags'])) {
                                                                $matching = true;
                                                                break;
                                                        }
                                                }
                                                if ($matching) {
                                                        $resultat = $this->remove($id) && $resultat;
                                                }
                                                break;
                                        default:
                                                Zend_Cache::throwException('Invalid mode for clean() method');
                                                break;
                                }
                        }
                        if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
                                // Recursive call
                                $resultat = $this->nettoyerFichiers($file . DIRECTORY_SEPARATOR, $mode, $tags) && $resultat;
                                if ($mode=='all') {
                                        // if mode=='all', we try to drop the structure too
                                        @rmdir($file);
                                }
                        }
                }
                return $resultat;
        }

        protected function _get($dir, $mode, $tags = array()) {
                if (!is_dir($dir)) {
                        return false;
                }
                $result = array();
                $prefix = $this->_options['file_name_prefix'];
                $glob = @glob($dir . $prefix . '--*');
                if ($glob === false) {
                        // On some systems it is impossible to distinguish between empty match and an error.
                        return array();
                }
                foreach ($glob as $file)  {
                        if (is_file($file)) {
                                $fileName = basename($file);
                                $id = $this->transformerNomFichierEnId($fileName);
                                $metadatas = $this->getMetadonneesFichier($id);
                                if ($metadatas === FALSE) {
                                        continue;
                                }
                                if (time() > $metadatas['expire']) {
                                        continue;
                                }
                                switch ($mode) {
                                        case 'ids':
                                                $result[] = $id;
                                                break;
                                        case 'tags':
                                                $result = array_unique(array_merge($result, $metadatas['tags']));
                                                break;
                                        case 'matching':
                                                $matching = true;
                                                foreach ($tags as $tag) {
                                                        if (!in_array($tag, $metadatas['tags'])) {
                                                                $matching = false;
                                                                break;
                                                        }
                                                }
                                                if ($matching) {
                                                        $result[] = $id;
                                                }
                                                break;
                                        case 'notMatching':
                                                $matching = false;
                                                foreach ($tags as $tag) {
                                                        if (in_array($tag, $metadatas['tags'])) {
                                                                $matching = true;
                                                                break;
                                                        }
                                                }
                                                if (!$matching) {
                                                        $result[] = $id;
                                                }
                                                break;
                                        case 'matchingAny':
                                                $matching = false;
                                                foreach ($tags as $tag) {
                                                        if (in_array($tag, $metadatas['tags'])) {
                                                                $matching = true;
                                                                break;
                                                        }
                                                }
                                                if ($matching) {
                                                        $result[] = $id;
                                                }
                                                break;
                                        default:
                                                Zend_Cache::throwException('Invalid mode for _get() method');
                                                break;
                                }
                        }
                        if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
                                // Recursive call
                                $recursiveRs =  $this->_get($file . DIRECTORY_SEPARATOR, $mode, $tags);
                                if ($recursiveRs === false) {
                                        $this->_log('Zend_Cache_Backend_File::_get() / recursive call : can\'t list entries of "'.$file.'"');
                                } else {
                                        $result = array_unique(array_merge($result, $recursiveRs));
                                }
                        }
                }
                return array_unique($result);
        }

        /**
         * Compute & return the expire time
         *
         * @return int expire time (unix timestamp)
         */
        protected function _expireTime($lifetime) {
                if ($lifetime === null) {
                        return 9999999999;
                }
                return time() + $lifetime;
        }

        /**
         * Make a control key with the string containing datas
         *
         * @param  string $data         Data
         * @param  string $controlType Type of control 'md5', 'crc32' or 'strlen'
         * @throws Zend_Cache_Exception
         * @return string Control key
         */
        protected function genererCleSecu($donnees, $type_de_controle) {
                switch ($type_de_controle) {
                case 'md5':
                        return md5($donnees);
                case 'crc32':
                        return crc32($donnees);
                case 'strlen':
                        return strlen($donnees);
                case 'adler32':
                        return hash('adler32', $donnees);
                default:
                        trigger_error("Fonction de génération de clé de sécurité introuvable : $type_de_controle", E_USER_WARNING);
                }
        }

        /**
         * Transform a cache id into a file name and return it
         *
         * @param  string $id Cache id
         * @return string File name
         */
        protected function transformaterIdEnNomFichier($id) {
                $prefixe = $this->options['fichier_prefixe'];
                $resulta = $prefixe.'---'.$id;
                return $resultat;
        }

        /**
         * Make and return a file name (with path)
         *
         * @param  string $id Cache id
         * @return string File name (with path)
         */
        protected function getFichierNom($id) {
                $path = $this->getChemin($id);
                $fileName = $this->transformaterIdEnNomFichier($id);
                return $path . $fileName;
        }

        /**
         * Return the complete directory path of a filename (including hashedDirectoryStructure)
         *
         * @param  string $id Cache id
         * @param  boolean $decoupage if true, returns array of directory parts instead of single string
         * @return string Complete directory path
         */
        protected function getChemin($id, $decoupage = false) {
                $morceaux = array();
                $chemin = $this->options['stockage_chemin'];
                $prefixe = $this->options['fichier_prefixe'];
                if ($this->options['dossier_niveau'] > 0) {
                        $hash = hash('adler32', $id);
                        for ($i = 0 ; $i < $this->options['dossier_niveau'] ; $i++) {
                                $chemin .= $prefix.'--'.substr($hash, 0, $i + 1).DS;
                                $morceaux[] = $chemin;
                        }
                }
                return ($decoupage) ?   $morceaux : $chemin;
        }

        /**
         * Make the directory strucuture for the given id
         *
         * @param string $id cache id
         * @return boolean true
         */
        protected function lancerMkdirEtChmodRecursif($id) {
                $resultat = true;
                if ($this->options['dossier_niveau'] > 0) {
                        $chemins = $this->getChemin($id, true);
                        foreach ($chemins as $chemin) {
                                if (!is_dir($chemin)) {
                                        @mkdir($chemin, $this->options['dossier_umask']);
                                        @chmod($chemin, $this->options['dossier_umask']); // see #ZF-320 (this line is required in some configurations)
                                }
                        }
                }
                return $resultat;
        }

        /**
         * Test if the given cache id is available (and still valid as a cache record)
         *
         * @param  string  $id                                   Cache id
         * @param  boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
         * @return boolean|mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
         */
        protected function testerExistenceCache($id, $ne_pas_tester_validiter_du_cache) {
                $resultat = false;
                if ($metadonnees = $this->getMetadonnees($id)) {
                        if ($ne_pas_tester_validiter_du_cache || (time() <= $metadonnees['expiration'])) {
                                $resultat =  $metadonnees['mtime'];
                        }
                }
                return $resultat;
        }

        /**
         * Return the file content of the given file
         *
         * @param  string $file File complete path
         * @return string File content (or false if problem)
         */
        protected function getContenuFichier($fichier) {
                $resultat = false;
                if (is_file($fichier)) {
                        $f = @fopen($fichier, 'rb');
                        if ($f) {
                                if ($this->options['fichier_verrou']) @flock($f, LOCK_SH);
                                $resultat = stream_get_contents($f);
                                if ($this->options['fichier_verrou']) @flock($f, LOCK_UN);
                                @fclose($f);
                        }
                }
                return $resultat;
        }

        /**
         * Put the given string into the given file
         *
         * @param  string $file   File complete path
         * @param  string $string String to put in file
         * @return boolean true if no problem
         */
        protected function setContenuFichier($fichier, $chaine) {
                $resultat = false;
                $f = @fopen($fichier, 'ab+');
                if ($f) {
                        if ($this->options['fichier_verrou']) @flock($f, LOCK_EX);
                        fseek($f, 0);
                        ftruncate($f, 0);
                        $tmp = @fwrite($f, $chaine);
                        if (!($tmp === FALSE)) {
                                $resultat = true;
                        }
                        @fclose($f);
                }
                @chmod($fichier, $this->options['fichier_umask']);
                return $resultat;
        }

        /**
         * Transform a file name into cache id and return it
         *
         * @param  string $fileName File name
         * @return string Cache id
         */
        protected function transformerNomFichierEnId($nom_de_fichier) {
                $prefixe = $this->options['fichier_prefixe'];
                return preg_replace('~^' . $prefixe . '---(.*)$~', '$1', $nom_de_fichier);
        }
}
?>