[ Index ]
 

Code source de Symfony 1.0.0

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/lib/cache/ -> sfFileCache.class.php (source)

   1  <?php
   2  
   3  /*
   4   * This file is part of the symfony package.
   5   * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
   6   * 
   7   * For the full copyright and license information, please view the LICENSE
   8   * file that was distributed with this source code.
   9   */
  10  
  11  /**
  12   * Cache class that stores content in files.
  13   *
  14   * This class is based on the PEAR_Cache_Lite class.
  15   * All cache files are stored in files in the [sf_root_dir].'/cache/'.[sf_app].'/template' directory.
  16   * To disable all caching, you can set to false [sf_cache] setting.
  17   *
  18   * @package    symfony
  19   * @subpackage cache
  20   * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
  21   * @author     Fabien Marty <fab@php.net>
  22   * @version    SVN: $Id: sfFileCache.class.php 3198 2007-01-08 20:36:20Z fabien $
  23   */
  24  class sfFileCache extends sfCache
  25  {
  26    const DEFAULT_NAMESPACE = '';
  27  
  28   /**
  29    * Directory where to put the cache files
  30    */
  31    protected $cacheDir = '';
  32  
  33   /**
  34    * Enable / disable fileLocking (can avoid cache corruption under bad circumstances)
  35    * @var boolean $fileLocking
  36    */
  37    protected $fileLocking = true;
  38  
  39   /**
  40    * Enable / disable write control (the cache is read just after writing to detect corrupt entries)
  41    *
  42    * Enable write control will lightly slow the cache writing but not the cache reading
  43    * Write control can detect some corrupt cache files but maybe it's not a perfect control
  44    */
  45    protected $writeControl = false;
  46  
  47   /**
  48    * Enable / disable read control
  49    *
  50    * If enabled, a control key is embeded in cache file and this key is compared with the one calculated after the reading.
  51    */
  52    protected $readControl = false;
  53  
  54   /**
  55    * File Name protection
  56    *
  57    * if set to true, you can use any cache id or namespace name
  58    * if set to false, it can be faster but cache ids and namespace names
  59    * will be used directly in cache file names so be carefull with
  60    * special characters...
  61    */
  62    protected $fileNameProtection = false;
  63  
  64   /**
  65    * Disable / Tune the automatic cleaning process
  66    *
  67    * The automatic cleaning process destroy too old (for the given life time)
  68    * cache files when a new cache file is written.
  69    * 0               => no automatic cache cleaning
  70    * 1               => systematic cache cleaning
  71    * x (integer) > 1 => automatic cleaning randomly 1 times on x cache write
  72    */
  73    protected $automaticCleaningFactor = 500;
  74    
  75   /**
  76    * Nested directory level
  77    */
  78    protected $hashedDirectoryLevel = 0;
  79  
  80   /**
  81    * Cache suffix
  82    */
  83    protected
  84      $suffix = '.cache';
  85  
  86   /**
  87    * Constructor.
  88    *
  89    * @param string The cache root directory
  90    */
  91    public function __construct($cacheDir = null)
  92    {
  93      $this->setCacheDir($cacheDir);
  94    }
  95  
  96    /**
  97     * Initializes the cache.
  98     *
  99     * @param array An array of options
 100     * Available options:
 101     *  - cacheDir:                cache root directory
 102     *  - fileLocking:             enable / disable file locking (boolean)
 103     *  - writeControl:            enable / disable write control (boolean)
 104     *  - readControl:             enable / disable read control (boolean)
 105     *  - fileNameProtection:      enable / disable automatic file name protection (boolean)
 106     *  - automaticCleaningFactor: disable / tune automatic cleaning process (int)
 107     *  - hashedDirectoryLevel:    level of the hashed directory system (int)
 108     *  - lifeTime:                default life time
 109     *
 110     */
 111    public function initialize($options = array())
 112    {
 113      if (isset($options['cacheDir']))
 114      {
 115        $this->setCacheDir($options['cacheDir']);
 116        unset($options['cacheDir']);
 117      }
 118  
 119      $availableOptions = array('fileLocking', 'writeControl', 'readControl', 'fileNameProtection', 'automaticCleaningFactor', 'hashedDirectoryLevel', 'lifeTime');
 120      foreach ($options as $key => $value)
 121      {
 122        if (!in_array($key, $availableOptions))
 123        {
 124          sfLogger::getInstance()->error(sprintf('sfFileCache cannot take "%s" as an option', $key));
 125        }
 126  
 127        $this->$key = $value;
 128      }
 129    }
 130  
 131    /**
 132     * Sets the suffix for cache files.
 133     *
 134     * @param string The suffix name (with the leading .)
 135     */
 136    public function setSuffix($suffix)
 137    {
 138      $this->suffix = $suffix;
 139    }
 140  
 141   /**
 142    * Enables / disables write control.
 143    *
 144    * @param boolean
 145    */
 146    public function setWriteControl($boolean)
 147    {
 148      $this->writeControl = $boolean;
 149    }
 150  
 151    /**
 152     * Gets the value of the writeControl option.
 153     *
 154     * @return boolean
 155     */
 156    public function getWriteControl()
 157    {
 158      return $this->writeControl;
 159    }
 160  
 161   /**
 162    * Enables / disables file locking.
 163    *
 164    * @param boolean
 165    */
 166    public function setFileLocking($boolean)
 167    {
 168      $this->fileLocking = $boolean;
 169    }
 170  
 171    /**
 172     * Gets the value of the fileLocking option.
 173     *
 174     * @return boolean
 175     */
 176    public function getFileLocking()
 177    {
 178      return $this->fileLocking;
 179    }
 180  
 181    /**
 182     * Sets the cache root directory.
 183     *
 184     * @param string The directory where to put the cache files
 185     */
 186    public function setCacheDir($cacheDir)
 187    {
 188      // remove last DIRECTORY_SEPARATOR
 189      if (DIRECTORY_SEPARATOR == substr($cacheDir, -1))
 190      {
 191        $cacheDir = substr($cacheDir, 0, -1);
 192      }
 193  
 194      // create cache dir if needed
 195      if (!is_dir($cacheDir))
 196      {
 197        $current_umask = umask(0000);
 198        @mkdir($cacheDir, 0777, true);
 199        umask($current_umask);
 200      }
 201  
 202       $this->cacheDir = $cacheDir;
 203     }
 204  
 205      public function getCacheDir()
 206      {
 207        return $this->cacheDir;
 208      }
 209  
 210   /**
 211    * Tests if a cache is available and (if yes) returns it.
 212    *
 213    * @param  string  The cache id
 214    * @param  string  The name of the cache namespace
 215    * @param  boolean If set to true, the cache validity won't be tested
 216    *
 217    * @return string  Data of the cache (or null if no cache available)
 218    *
 219    * @see sfCache
 220    */
 221    public function get($id, $namespace = self::DEFAULT_NAMESPACE, $doNotTestCacheValidity = false)
 222    {
 223      $data = null;
 224  
 225      list($path, $file) = $this->getFileName($id, $namespace);
 226  
 227      if ($doNotTestCacheValidity)
 228      {
 229        if (file_exists($path.$file))
 230        {
 231          $data = $this->read($path, $file);
 232        }
 233      }
 234      else
 235      {
 236        if ((file_exists($path.$file)) && (@filemtime($path.$file) > $this->refreshTime))
 237        {
 238          $data = $this->read($path, $file);
 239        }
 240      }
 241  
 242      return $data ? $data : null;
 243    }
 244  
 245    /**
 246     * Returns true if there is a cache for the given id and namespace.
 247     *
 248     * @param  string  The cache id
 249     * @param  string  The name of the cache namespace
 250     * @param  boolean If set to true, the cache validity won't be tested
 251     *
 252     * @return boolean true if the cache exists, false otherwise
 253     *
 254     * @see sfCache
 255     */
 256    public function has($id, $namespace = self::DEFAULT_NAMESPACE, $doNotTestCacheValidity = false)
 257    {
 258      list($path, $file) = $this->getFileName($id, $namespace);
 259  
 260      if ($doNotTestCacheValidity)
 261      {
 262        if (file_exists($path.$file))
 263        {
 264          return true;
 265        }
 266      }
 267      else
 268      {
 269        if ((file_exists($path.$file)) && (@filemtime($path.$file) > $this->refreshTime))
 270        {
 271          return true;
 272        }
 273      }
 274  
 275      return false;
 276    }
 277    
 278   /**
 279    * Saves some data in a cache file.
 280    *
 281    * @param string The cache id
 282    * @param string The name of the cache namespace
 283    * @param string The data to put in cache
 284    *
 285    * @return boolean true if no problem
 286    *
 287    * @see sfCache
 288    */
 289    public function set($id, $namespace = self::DEFAULT_NAMESPACE, $data)
 290    {
 291      list($path, $file) = $this->getFileName($id, $namespace);
 292  
 293      if ($this->automaticCleaningFactor > 0)
 294      {
 295        $rand = rand(1, $this->automaticCleaningFactor);
 296        if ($rand == 1)
 297        {
 298          $this->clean(false, 'old');
 299        }
 300      }
 301  
 302      if ($this->writeControl)
 303      {
 304        return $this->writeAndControl($path, $file, $data);
 305      }
 306      else
 307      {
 308        return $this->write($path, $file, $data);
 309      }
 310    }
 311  
 312   /**
 313    * Removes a cache file.
 314    *
 315    * @param string The cache id
 316    * @param string The name of the cache namespace
 317    *
 318    * @return boolean true if no problem
 319    */
 320    public function remove($id, $namespace = self::DEFAULT_NAMESPACE)
 321    {
 322      list($path, $file) = $this->getFileName($id, $namespace);
 323  
 324      return $this->unlink($path.$file);
 325    }
 326  
 327   /**
 328    * Cleans the cache.
 329    *
 330    * If no namespace is specified all cache files will be destroyed
 331    * else only cache files of the specified namespace will be destroyed.
 332    *
 333    * @param string The name of the cache namespace
 334    *
 335    * @return boolean true if no problem
 336    */
 337    public function clean($namespace = null, $mode = 'all')
 338    {
 339      $namespace = str_replace('/', DIRECTORY_SEPARATOR, $namespace);
 340  
 341      return $this->cleanDir($this->cacheDir.DIRECTORY_SEPARATOR.$namespace, $mode);
 342    }
 343  
 344    /**
 345     * Returns the cache last modification time.
 346     *
 347     * @return int The last modification time
 348     */
 349    public function lastModified($id, $namespace = self::DEFAULT_NAMESPACE)
 350    {
 351      list($path, $file) = $this->getFileName($id, $namespace);
 352  
 353      return (file_exists($path.$file) ? filemtime($path.$file) : 0);
 354    }
 355  
 356   /**
 357    * Makes a file name (with path).
 358    *
 359    * @param string The cache id
 360    * @param string The name of the namespace
 361    *
 362    * @return array An array containing the path and the file name
 363    */
 364    protected function getFileName($id, $namespace)
 365    {
 366      $file = ($this->fileNameProtection) ? md5($id).$this->suffix : $id.$this->suffix;
 367  
 368      if ($namespace)
 369      {
 370        $namespace = str_replace('/', DIRECTORY_SEPARATOR, $namespace);
 371        $path = $this->cacheDir.DIRECTORY_SEPARATOR.$namespace.DIRECTORY_SEPARATOR;
 372      }
 373      else
 374      {
 375        $path = $this->cacheDir.DIRECTORY_SEPARATOR;
 376      }
 377      if ($this->hashedDirectoryLevel > 0)
 378      {
 379        $hash = md5($file);
 380        for ($i = 0; $i < $this->hashedDirectoryLevel; $i++)
 381        {
 382          $path = $path.substr($hash, 0, $i + 1).DIRECTORY_SEPARATOR;
 383        }
 384      }
 385  
 386      return array($path, $file);
 387    }
 388  
 389   /**
 390    * Removes a file.
 391    *
 392    * @param string The complete file path and name
 393    *
 394    * @return boolean true if no problem
 395    */
 396    protected function unlink($file)
 397    {
 398      return @unlink($file) ? true : false;
 399    }
 400  
 401   /**
 402    * Recursive function for cleaning cache file in the given directory.
 403    *
 404    * @param  string  The directory complete path
 405    * @param  string  The name of the cache namespace
 406    * @param  string  The flush cache mode : 'old', 'all'
 407    *
 408    * @return boolean true if no problem
 409    *
 410    * @throws sfCacheException
 411    */
 412    protected function cleanDir($dir, $mode)
 413    {
 414      if (!($dh = opendir($dir)))
 415      {
 416        throw new sfCacheException('Unable to open cache directory "'.$dir.'"');
 417      }
 418  
 419      $result = true;
 420      while ($file = readdir($dh))
 421      {
 422        if (($file != '.') && ($file != '..'))
 423        {
 424          $file2 = $dir.DIRECTORY_SEPARATOR.$file;
 425          if (is_file($file2))
 426          {
 427            $unlink = 1;
 428            if ($mode == 'old')
 429            {
 430              // files older than lifeTime get deleted from cache
 431              if ((time() - filemtime($file2)) < $this->lifeTime)
 432              {
 433                $unlink = 0;
 434              }
 435            }
 436  
 437            if ($unlink)
 438            {
 439              $result = ($result and ($this->unlink($file2)));
 440            }
 441          }
 442          else if (is_dir($file2))
 443          {
 444            $result = ($result and ($this->cleanDir($file2.DIRECTORY_SEPARATOR, $mode)));
 445          }
 446        }
 447      }
 448  
 449      return $result;
 450    }
 451  
 452   /**
 453    * Reads the cache file and returns the content.
 454    *
 455    * @param string The file path
 456    * @param string The file name
 457    *
 458    * @return string The content of the cache file.
 459    *
 460    * @throws sfCacheException
 461    */
 462    protected function read($path, $file)
 463    {
 464      $fp = @fopen($path.$file, "rb");
 465      if ($this->fileLocking)
 466      {
 467        @flock($fp, LOCK_SH);
 468      }
 469  
 470      if ($fp)
 471      {
 472        clearstatcache(); // because the filesize can be cached by PHP itself...
 473        $length = @filesize($path.$file);
 474        $mqr = get_magic_quotes_runtime();
 475        set_magic_quotes_runtime(0);
 476        if ($this->readControl)
 477        {
 478          $hashControl = @fread($fp, 32);
 479          $length = $length - 32;
 480        } 
 481        $data = ($length) ? @fread($fp, $length) : '';
 482        set_magic_quotes_runtime($mqr);
 483        if ($this->fileLocking)
 484        {
 485          @flock($fp, LOCK_UN);
 486        }
 487        @fclose($fp);
 488        if ($this->readControl)
 489        {
 490          $hashData = $this->hash($data);
 491          if ($hashData != $hashControl)
 492          {
 493            @touch($path.$file, time() - 2 * abs($this->lifeTime));
 494            return false;
 495          }
 496        }
 497  
 498        return $data;
 499      }
 500  
 501      throw new sfCacheException('Unable to read cache file "'.$path.$file.'"');
 502    }
 503  
 504   /**
 505    * Writes the given data in the cache file.
 506    *
 507    * @param string The file path
 508    * @param string The file name
 509    * @param string The data to put in cache
 510    *
 511    * @return boolean true if ok
 512    *
 513    * @throws sfCacheException
 514    */
 515    protected function write($path, $file, $data)
 516    {
 517      $try = 1;
 518      while ($try <= 2)
 519      {
 520        $fp = @fopen($path.$file, 'wb');
 521        if ($fp)
 522        {
 523          if ($this->fileLocking)
 524          {
 525            @flock($fp, LOCK_EX);
 526          }
 527          if ($this->readControl)
 528          {
 529            @fwrite($fp, $this->hash($data), 32);
 530          }
 531          @fwrite($fp, $data);
 532          if ($this->fileLocking)
 533          {
 534            @flock($fp, LOCK_UN);
 535          }
 536          @fclose($fp);
 537  
 538          // change file mode
 539          $current_umask = umask();
 540          umask(0000);
 541          chmod($path.$file, 0666);
 542          umask($current_umask);
 543  
 544          return true;
 545        }
 546        else
 547        {
 548          if ($try == 1 && !is_dir($path))
 549          {
 550            // create directory structure if needed
 551            $current_umask = umask(0000);
 552            mkdir($path, 0777, true);
 553            umask($current_umask);
 554  
 555            $try = 2;
 556          }
 557          else
 558          {
 559            $try = 999;
 560          }
 561        }
 562      }
 563  
 564      throw new sfCacheException('Unable to write cache file "'.$path.$file.'"');
 565    }
 566    
 567   /**
 568    * Writes the given data in the cache file and controls it just after to avoid corrupted cache entries.
 569    *
 570    * @param string The file path
 571    * @param string The file name
 572    * @param string The data to put in cache
 573    *
 574    * @return boolean true if the test is ok
 575    */
 576    protected function writeAndControl($path, $file, $data)
 577    {
 578      $this->write($path, $file, $data);
 579      $dataRead = $this->read($path, $file);
 580  
 581      return ($dataRead == $data);
 582    }
 583    
 584   /**
 585    * Makes a control key with the string containing datas.
 586    *
 587    * @param string $data data
 588    *
 589    * @return string control key
 590    */
 591    protected function hash($data)
 592    {
 593      return sprintf('% 32d', crc32($data));
 594    }
 595  }


Généré le : Fri Mar 16 22:42:14 2007 par Balluche grâce à PHPXref 0.7