• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • Examples
  • File List

E:/E/GEAMP/www/openbiz/openbiz/others/Zend/Cache/Backend/File.php

00001 <?php
00026 require_once 'Zend/Cache/Backend/ExtendedInterface.php';
00027 
00031 require_once 'Zend/Cache/Backend.php';
00032 
00033 
00040 class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface
00041 {
00090     protected $_options = array(
00091         'cache_dir' => null,
00092         'file_locking' => true,
00093         'read_control' => true,
00094         'read_control_type' => 'crc32',
00095         'hashed_directory_level' => 0,
00096         'hashed_directory_umask' => 0700,
00097         'file_name_prefix' => 'zend_cache',
00098         'cache_file_umask' => 0600,
00099         'metadatas_array_max_size' => 100
00100     );
00101 
00107     protected $_metadatasArray = array();
00108 
00109 
00117     public function __construct(array $options = array())
00118     {
00119         parent::__construct($options);
00120         if ($this->_options['cache_dir'] !== null) { // particular case for this option
00121             $this->setCacheDir($this->_options['cache_dir']);
00122         } else {
00123             $this->setCacheDir(self::getTmpDir() . DIRECTORY_SEPARATOR, false);
00124         }
00125         if (isset($this->_options['file_name_prefix'])) { // particular case for this option
00126             if (!preg_match('~^[\w]+$~', $this->_options['file_name_prefix'])) {
00127                 Zend_Cache::throwException('Invalid file_name_prefix : must use only [a-zA-A0-9_]');
00128             }
00129         }
00130         if ($this->_options['metadatas_array_max_size'] < 10) {
00131             Zend_Cache::throwException('Invalid metadatas_array_max_size, must be > 10');
00132         }
00133         if (isset($options['hashed_directory_umask']) && is_string($options['hashed_directory_umask'])) {
00134             // See #ZF-4422
00135             $this->_options['hashed_directory_umask'] = octdec($this->_options['hashed_directory_umask']);
00136         }
00137         if (isset($options['cache_file_umask']) && is_string($options['cache_file_umask'])) {
00138             // See #ZF-4422
00139             $this->_options['cache_file_umask'] = octdec($this->_options['cache_file_umask']);
00140         }
00141     }
00142 
00151     public function setCacheDir($value, $trailingSeparator = true)
00152     {
00153         if (!is_dir($value)) {
00154             Zend_Cache::throwException('cache_dir must be a directory');
00155         }
00156         if (!is_writable($value)) {
00157             Zend_Cache::throwException('cache_dir is not writable');
00158         }
00159         if ($trailingSeparator) {
00160             // add a trailing DIRECTORY_SEPARATOR if necessary
00161             $value = rtrim(realpath($value), '\\/') . DIRECTORY_SEPARATOR;
00162         }
00163         $this->_options['cache_dir'] = $value;
00164     }
00165 
00173     public function load($id, $doNotTestCacheValidity = false)
00174     {
00175         if (!($this->_test($id, $doNotTestCacheValidity))) {
00176             // The cache is not hit !
00177             return false;
00178         }
00179         $metadatas = $this->_getMetadatas($id);
00180         $file = $this->_file($id);
00181         $data = $this->_fileGetContents($file);
00182         if ($this->_options['read_control']) {
00183             $hashData = $this->_hash($data, $this->_options['read_control_type']);
00184             $hashControl = $metadatas['hash'];
00185             if ($hashData != $hashControl) {
00186                 // Problem detected by the read control !
00187                 $this->_log('Zend_Cache_Backend_File::load() / read_control : stored hash and computed hash do not match');
00188                 $this->remove($id);
00189                 return false;
00190             }
00191         }
00192         return $data;
00193     }
00194 
00201     public function test($id)
00202     {
00203         clearstatcache();
00204         return $this->_test($id, false);
00205     }
00206 
00219     public function save($data, $id, $tags = array(), $specificLifetime = false)
00220     {
00221         clearstatcache();
00222         $file = $this->_file($id);
00223         $path = $this->_path($id);
00224         if ($this->_options['hashed_directory_level'] > 0) {
00225             if (!is_writable($path)) {
00226                 // maybe, we just have to build the directory structure
00227                 $this->_recursiveMkdirAndChmod($id);
00228             }
00229             if (!is_writable($path)) {
00230                 return false;
00231             }
00232         }
00233         if ($this->_options['read_control']) {
00234             $hash = $this->_hash($data, $this->_options['read_control_type']);
00235         } else {
00236             $hash = '';
00237         }
00238         $metadatas = array(
00239             'hash' => $hash,
00240             'mtime' => time(),
00241             'expire' => $this->_expireTime($this->getLifetime($specificLifetime)),
00242             'tags' => $tags
00243         );
00244         $res = $this->_setMetadatas($id, $metadatas);
00245         if (!$res) {
00246             $this->_log('Zend_Cache_Backend_File::save() / error on saving metadata');
00247             return false;
00248         }
00249         $res = $this->_filePutContents($file, $data);
00250         return $res;
00251     }
00252 
00259     public function remove($id)
00260     {
00261         $file = $this->_file($id);
00262         $boolRemove   = $this->_remove($file);
00263         $boolMetadata = $this->_delMetadatas($id);
00264         return $boolMetadata && $boolRemove;
00265     }
00266 
00284     public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
00285     {
00286         // We use this protected method to hide the recursive stuff
00287         clearstatcache();
00288         return $this->_clean($this->_options['cache_dir'], $mode, $tags);
00289     }
00290 
00296     public function getIds()
00297     {
00298         return $this->_get($this->_options['cache_dir'], 'ids', array());
00299     }
00300 
00306     public function getTags()
00307     {
00308         return $this->_get($this->_options['cache_dir'], 'tags', array());
00309     }
00310 
00319     public function getIdsMatchingTags($tags = array())
00320     {
00321         return $this->_get($this->_options['cache_dir'], 'matching', $tags);
00322     }
00323 
00332     public function getIdsNotMatchingTags($tags = array())
00333     {
00334         return $this->_get($this->_options['cache_dir'], 'notMatching', $tags);
00335     }
00336 
00345     public function getIdsMatchingAnyTags($tags = array())
00346     {
00347         return $this->_get($this->_options['cache_dir'], 'matchingAny', $tags);
00348     }
00349 
00356     public function getFillingPercentage()
00357     {
00358         $free = disk_free_space($this->_options['cache_dir']);
00359         $total = disk_total_space($this->_options['cache_dir']);
00360         if ($total == 0) {
00361             Zend_Cache::throwException('can\'t get disk_total_space');
00362         } else {
00363             if ($free >= $total) {
00364                 return 100;
00365             }
00366             return ((int) (100. * ($total - $free) / $total));
00367         }
00368     }
00369 
00381     public function getMetadatas($id)
00382     {
00383         $metadatas = $this->_getMetadatas($id);
00384         if (!$metadatas) {
00385             return false;
00386         }
00387         if (time() > $metadatas['expire']) {
00388             return false;
00389         }
00390         return array(
00391             'expire' => $metadatas['expire'],
00392             'tags' => $metadatas['tags'],
00393             'mtime' => $metadatas['mtime']
00394         );
00395     }
00396 
00404     public function touch($id, $extraLifetime)
00405     {
00406         $metadatas = $this->_getMetadatas($id);
00407         if (!$metadatas) {
00408             return false;
00409         }
00410         if (time() > $metadatas['expire']) {
00411             return false;
00412         }
00413         $newMetadatas = array(
00414             'hash' => $metadatas['hash'],
00415             'mtime' => time(),
00416             'expire' => $metadatas['expire'] + $extraLifetime,
00417             'tags' => $metadatas['tags']
00418         );
00419         $res = $this->_setMetadatas($id, $newMetadatas);
00420         if (!$res) {
00421             return false;
00422         }
00423         return true;
00424     }
00425 
00440     public function getCapabilities()
00441     {
00442         return array(
00443             'automatic_cleaning' => true,
00444             'tags' => true,
00445             'expired_read' => true,
00446             'priority' => false,
00447             'infinite_lifetime' => true,
00448             'get_list' => true
00449         );
00450     }
00451 
00459     public function ___expire($id)
00460     {
00461         $metadatas = $this->_getMetadatas($id);
00462         if ($metadatas) {
00463             $metadatas['expire'] = 1;
00464             $this->_setMetadatas($id, $metadatas);
00465         }
00466     }
00467 
00474     protected function _getMetadatas($id)
00475     {
00476         if (isset($this->_metadatasArray[$id])) {
00477             return $this->_metadatasArray[$id];
00478         } else {
00479             $metadatas = $this->_loadMetadatas($id);
00480             if (!$metadatas) {
00481                 return false;
00482             }
00483             $this->_setMetadatas($id, $metadatas, false);
00484             return $metadatas;
00485         }
00486     }
00487 
00496     protected function _setMetadatas($id, $metadatas, $save = true)
00497     {
00498         if (count($this->_metadatasArray) >= $this->_options['metadatas_array_max_size']) {
00499             $n = (int) ($this->_options['metadatas_array_max_size'] / 10);
00500             $this->_metadatasArray = array_slice($this->_metadatasArray, $n);
00501         }
00502         if ($save) {
00503             $result = $this->_saveMetadatas($id, $metadatas);
00504             if (!$result) {
00505                 return false;
00506             }
00507         }
00508         $this->_metadatasArray[$id] = $metadatas;
00509         return true;
00510     }
00511 
00518     protected function _delMetadatas($id)
00519     {
00520         if (isset($this->_metadatasArray[$id])) {
00521             unset($this->_metadatasArray[$id]);
00522         }
00523         $file = $this->_metadatasFile($id);
00524         return $this->_remove($file);
00525     }
00526 
00532     protected function _cleanMetadatas()
00533     {
00534         $this->_metadatasArray = array();
00535     }
00536 
00543     protected function _loadMetadatas($id)
00544     {
00545         $file = $this->_metadatasFile($id);
00546         $result = $this->_fileGetContents($file);
00547         if (!$result) {
00548             return false;
00549         }
00550         $tmp = @unserialize($result);
00551         return $tmp;
00552     }
00553 
00561     protected function _saveMetadatas($id, $metadatas)
00562     {
00563         $file = $this->_metadatasFile($id);
00564         $result = $this->_filePutContents($file, serialize($metadatas));
00565         if (!$result) {
00566             return false;
00567         }
00568         return true;
00569     }
00570 
00577     protected function _metadatasFile($id)
00578     {
00579         $path = $this->_path($id);
00580         $fileName = $this->_idToFileName('internal-metadatas---' . $id);
00581         return $path . $fileName;
00582     }
00583 
00590     protected function _isMetadatasFile($fileName)
00591     {
00592         $id = $this->_fileNameToId($fileName);
00593         if (substr($id, 0, 21) == 'internal-metadatas---') {
00594             return true;
00595         } else {
00596             return false;
00597         }
00598     }
00599 
00609     protected function _remove($file)
00610     {
00611         if (!is_file($file)) {
00612             return false;
00613         }
00614         if (!@unlink($file)) {
00615             # we can't remove the file (because of locks or any problem)
00616             $this->_log("Zend_Cache_Backend_File::_remove() : we can't remove $file");
00617             return false;
00618         }
00619         return true;
00620     }
00621 
00641     protected function _clean($dir, $mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
00642     {
00643         if (!is_dir($dir)) {
00644             return false;
00645         }
00646         $result = true;
00647         $prefix = $this->_options['file_name_prefix'];
00648         $glob = @glob($dir . $prefix . '--*');
00649         if ($glob === false) {
00650             return true;
00651         }
00652         foreach ($glob as $file)  {
00653             if (is_file($file)) {
00654                 $fileName = basename($file);
00655                 if ($this->_isMetadatasFile($fileName)) {
00656                     // in CLEANING_MODE_ALL, we drop anything, even remainings old metadatas files
00657                     if ($mode != Zend_Cache::CLEANING_MODE_ALL) {
00658                         continue;
00659                     }
00660                 }
00661                 $id = $this->_fileNameToId($fileName);
00662                 $metadatas = $this->_getMetadatas($id);
00663                 if ($metadatas === FALSE) {
00664                     $metadatas = array('expire' => 1, 'tags' => array());
00665                 }
00666                 switch ($mode) {
00667                     case Zend_Cache::CLEANING_MODE_ALL:
00668                         $res = $this->remove($id);
00669                         if (!$res) {
00670                             // in this case only, we accept a problem with the metadatas file drop
00671                             $res = $this->_remove($file);
00672                         }
00673                         $result = $result && $res;
00674                         break;
00675                     case Zend_Cache::CLEANING_MODE_OLD:
00676                         if (time() > $metadatas['expire']) {
00677                             $result = $this->remove($id) && $result;
00678                         }
00679                         break;
00680                     case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
00681                         $matching = true;
00682                         foreach ($tags as $tag) {
00683                             if (!in_array($tag, $metadatas['tags'])) {
00684                                 $matching = false;
00685                                 break;
00686                             }
00687                         }
00688                         if ($matching) {
00689                             $result = $this->remove($id) && $result;
00690                         }
00691                         break;
00692                     case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
00693                         $matching = false;
00694                         foreach ($tags as $tag) {
00695                             if (in_array($tag, $metadatas['tags'])) {
00696                                 $matching = true;
00697                                 break;
00698                             }
00699                         }
00700                         if (!$matching) {
00701                             $result = $this->remove($id) && $result;
00702                         }
00703                         break;
00704                     case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
00705                         $matching = false;
00706                         foreach ($tags as $tag) {
00707                             if (in_array($tag, $metadatas['tags'])) {
00708                                 $matching = true;
00709                                 break;
00710                             }
00711                         }
00712                         if ($matching) {
00713                             $result = $this->remove($id) && $result;
00714                         }
00715                         break;
00716                     default:
00717                         Zend_Cache::throwException('Invalid mode for clean() method');
00718                         break;
00719                 }
00720             }
00721             if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
00722                 // Recursive call
00723                 $result = $this->_clean($file . DIRECTORY_SEPARATOR, $mode, $tags) && $result;
00724                 if ($mode=='all') {
00725                     // if mode=='all', we try to drop the structure too
00726                     @rmdir($file);
00727                 }
00728             }
00729         }
00730         return $result;
00731     }
00732 
00733     protected function _get($dir, $mode, $tags = array())
00734     {
00735         if (!is_dir($dir)) {
00736             return false;
00737         }
00738         $result = array();
00739         $prefix = $this->_options['file_name_prefix'];
00740         $glob = @glob($dir . $prefix . '--*');
00741         if ($glob === false) {
00742             return true;
00743         }
00744         foreach ($glob as $file)  {
00745             if (is_file($file)) {
00746                 $fileName = basename($file);
00747                 $id = $this->_fileNameToId($fileName);
00748                 $metadatas = $this->_getMetadatas($id);
00749                 if ($metadatas === FALSE) {
00750                     continue;
00751                 }
00752                 if (time() > $metadatas['expire']) {
00753                     continue;
00754                 }
00755                 switch ($mode) {
00756                     case 'ids':
00757                         $result[] = $id;
00758                         break;
00759                     case 'tags':
00760                         $result = array_unique(array_merge($result, $metadatas['tags']));
00761                         break;
00762                     case 'matching':
00763                         $matching = true;
00764                         foreach ($tags as $tag) {
00765                             if (!in_array($tag, $metadatas['tags'])) {
00766                                 $matching = false;
00767                                 break;
00768                             }
00769                         }
00770                         if ($matching) {
00771                             $result[] = $id;
00772                         }
00773                         break;
00774                     case 'notMatching':
00775                         $matching = false;
00776                         foreach ($tags as $tag) {
00777                             if (in_array($tag, $metadatas['tags'])) {
00778                                 $matching = true;
00779                                 break;
00780                             }
00781                         }
00782                         if (!$matching) {
00783                             $result[] = $id;
00784                         }
00785                         break;
00786                     case 'matchingAny':
00787                         $matching = false;
00788                         foreach ($tags as $tag) {
00789                             if (in_array($tag, $metadatas['tags'])) {
00790                                 $matching = true;
00791                                 break;
00792                             }
00793                         }
00794                         if ($matching) {
00795                             $result[] = $id;
00796                         }
00797                         break;
00798                     default:
00799                         Zend_Cache::throwException('Invalid mode for _get() method');
00800                         break;
00801                 }
00802             }
00803             if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
00804                 // Recursive call
00805                 $result = array_unique(array_merge($result, $this->_get($file . DIRECTORY_SEPARATOR, $mode, $tags)));
00806             }
00807         }
00808         return array_unique($result);
00809     }
00810 
00816     protected function _expireTime($lifetime)
00817     {
00818         if ($lifetime === null) {
00819             return 9999999999;
00820         }
00821         return time() + $lifetime;
00822     }
00823 
00832     protected function _hash($data, $controlType)
00833     {
00834         switch ($controlType) {
00835         case 'md5':
00836             return md5($data);
00837         case 'crc32':
00838             return crc32($data);
00839         case 'strlen':
00840             return strlen($data);
00841         case 'adler32':
00842             return hash('adler32', $data);
00843         default:
00844             Zend_Cache::throwException("Incorrect hash function : $controlType");
00845         }
00846     }
00847 
00854     protected function _idToFileName($id)
00855     {
00856         $prefix = $this->_options['file_name_prefix'];
00857         $result = $prefix . '---' . $id;
00858         return $result;
00859     }
00860 
00867     protected function _file($id)
00868     {
00869         $path = $this->_path($id);
00870         $fileName = $this->_idToFileName($id);
00871         return $path . $fileName;
00872     }
00873 
00881     protected function _path($id, $parts = false)
00882     {
00883         $partsArray = array();
00884         $root = $this->_options['cache_dir'];
00885         $prefix = $this->_options['file_name_prefix'];
00886         if ($this->_options['hashed_directory_level']>0) {
00887             $hash = hash('adler32', $id);
00888             for ($i=0 ; $i < $this->_options['hashed_directory_level'] ; $i++) {
00889                 $root = $root . $prefix . '--' . substr($hash, 0, $i + 1) . DIRECTORY_SEPARATOR;
00890                 $partsArray[] = $root;
00891             }
00892         }
00893         if ($parts) {
00894             return $partsArray;
00895         } else {
00896             return $root;
00897         }
00898     }
00899 
00906     protected function _recursiveMkdirAndChmod($id)
00907     {
00908         if ($this->_options['hashed_directory_level'] <=0) {
00909             return true;
00910         }
00911         $partsArray = $this->_path($id, true);
00912         foreach ($partsArray as $part) {
00913             if (!is_dir($part)) {
00914                 @mkdir($part, $this->_options['hashed_directory_umask']);
00915                 @chmod($part, $this->_options['hashed_directory_umask']); // see #ZF-320 (this line is required in some configurations)
00916             }
00917         }
00918         return true;
00919     }
00920 
00928     protected function _test($id, $doNotTestCacheValidity)
00929     {
00930         $metadatas = $this->_getMetadatas($id);
00931         if (!$metadatas) {
00932             return false;
00933         }
00934         if ($doNotTestCacheValidity || (time() <= $metadatas['expire'])) {
00935             return $metadatas['mtime'];
00936         }
00937         return false;
00938     }
00939 
00946     protected function _fileGetContents($file)
00947     {
00948         $result = false;
00949         if (!is_file($file)) {
00950             return false;
00951         }
00952         $f = @fopen($file, 'rb');
00953         if ($f) {
00954             if ($this->_options['file_locking']) @flock($f, LOCK_SH);
00955             $result = stream_get_contents($f);
00956             if ($this->_options['file_locking']) @flock($f, LOCK_UN);
00957             @fclose($f);
00958         }
00959         return $result;
00960     }
00961 
00969     protected function _filePutContents($file, $string)
00970     {
00971         $result = false;
00972         $f = @fopen($file, 'ab+');
00973         if ($f) {
00974             if ($this->_options['file_locking']) @flock($f, LOCK_EX);
00975             fseek($f, 0);
00976             ftruncate($f, 0);
00977             $tmp = @fwrite($f, $string);
00978             if (!($tmp === FALSE)) {
00979                 $result = true;
00980             }
00981             @fclose($f);
00982         }
00983         @chmod($file, $this->_options['cache_file_umask']);
00984         return $result;
00985     }
00986 
00993     protected function _fileNameToId($fileName)
00994     {
00995         $prefix = $this->_options['file_name_prefix'];
00996         return preg_replace('~^' . $prefix . '---(.*)$~', '$1', $fileName);
00997     }
00998 
00999 }

Generated on Thu Apr 19 2012 17:01:15 for openbiz by  doxygen 1.7.2