[ Index ] |
|
Code source de Symfony 1.0.0 |
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 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Fri Mar 16 22:42:14 2007 | par Balluche grâce à PHPXref 0.7 |