[ Index ]
 

Code source de PHP PEAR 1.4.5

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

title

Body

[fermer]

/Cache/Container/ -> file.php (source)

   1  <?php
   2  // +----------------------------------------------------------------------+
   3  // | PEAR :: Cache                                                        |
   4  // +----------------------------------------------------------------------+
   5  // | Copyright (c) 1997-2003 The PHP Group                                |
   6  // +----------------------------------------------------------------------+
   7  // | This source file is subject to version 2.0 of the PHP license,       |
   8  // | that is bundled with this package in the file LICENSE, and is        |
   9  // | available at through the world-wide-web at                           |
  10  // | http://www.php.net/license/2_02.txt.                                 |
  11  // | If you did not receive a copy of the PHP license and are unable to   |
  12  // | obtain it through the world-wide-web, please send a note to          |
  13  // | license@php.net so we can mail you a copy immediately.               |
  14  // +----------------------------------------------------------------------+
  15  // | Authors: Ulf Wendel <ulf.wendel@phpdoc.de>                           |
  16  // |          Sebastian Bergmann <sb@sebastian-bergmann.de>               |
  17  // +----------------------------------------------------------------------+
  18  //
  19  // $Id: file.php,v 1.13 2003/03/27 10:48:42 chregu Exp $
  20  
  21  require_once  'Cache/Container.php';
  22  
  23  /**
  24  * Stores cache contents in a file.
  25  *
  26  * @author   Ulf Wendel  <ulf.wendel@phpdoc.de>
  27  * @version  $Id: file.php,v 1.13 2003/03/27 10:48:42 chregu Exp $
  28  */
  29  class Cache_Container_file extends Cache_Container {
  30  
  31      /**
  32      * File locking
  33      *
  34      * With file container, it's possible, that you get corrupted
  35      * data-entries under bad circumstances. The file locking must
  36      * improve this problem but it's experimental stuff. So the
  37      * default value is false. But it seems to give good results
  38      *
  39      * @var boolean
  40      */
  41      var $fileLocking = false;
  42  
  43      /**
  44      * Directory where to put the cache files.
  45      *
  46      * @var  string  Make sure to add a trailing slash
  47      */
  48      var $cache_dir = '';
  49  
  50      /**
  51      * Filename prefix for cache files.
  52      *
  53      * You can use the filename prefix to implement a "domain" based cache or just
  54      * to give the files a more descriptive name. The word "domain" is borroed from
  55      * a user authentification system. One user id (cached dataset with the ID x)
  56      * may exists in different domains (different filename prefix). You might want
  57      * to use this to have different cache values for a production, development and
  58      * quality assurance system. If you want the production cache not to be influenced
  59      * by the quality assurance activities, use different filename prefixes for them.
  60      *
  61      * I personally don't think that you'll never need this, but 640kb happend to be
  62      * not enough, so... you know what I mean. If you find a useful application of the
  63      * feature please update this inline doc.
  64      *
  65      * @var  string
  66      */
  67      var $filename_prefix = '';
  68      
  69      
  70      /**
  71      * List of cache entries, used within a gc run
  72      * 
  73      * @var array
  74      */
  75      var $entries;
  76      
  77      /**
  78      * Total number of bytes required by all cache entries, used within a gc run.
  79      * 
  80      * @var  int
  81      */
  82      var $total_size = 0;
  83  
  84  
  85      /**
  86      * Max Line Length of userdata
  87      *
  88      * If set to 0, it will take the default 
  89      * ( 1024 in php 4.2, unlimited in php 4.3)
  90      * see http://ch.php.net/manual/en/function.fgets.php
  91      * for details
  92      *
  93      * @var int
  94      */
  95      var $max_userdata_linelength = 257;
  96  
  97      /**
  98      * Creates the cache directory if neccessary
  99      *
 100      * @param    array   Config options: ["cache_dir" => ..., "filename_prefix" => ...]
 101      */
 102       function Cache_Container_file($options = '') {
 103          if (is_array($options))
 104              $this->setOptions($options, array_merge($this->allowed_options, array('cache_dir', 'filename_prefix', 'max_userdata_linelength')));
 105          
 106          clearstatcache();
 107          if ($this->cache_dir)
 108          {
 109              // make relative paths absolute for use in deconstructor.
 110              // it looks like the deconstructor has problems with relative paths
 111              if (OS_UNIX && '/' != $this->cache_dir{0}  )
 112                  $this->cache_dir = realpath( getcwd() . '/' . $this->cache_dir) . '/';
 113  
 114              // check if a trailing slash is in cache_dir
 115              if ($this->cache_dir{strlen($this->cache_dir)-1} != DIRECTORY_SEPARATOR)
 116                   $this->cache_dir .= '/';
 117  
 118              if  (!file_exists($this->cache_dir) || !is_dir($this->cache_dir))
 119                  mkdir($this->cache_dir, 0755);
 120          }
 121          $this->entries = array();
 122          $this->group_dirs = array();
 123                      
 124      } // end func contructor
 125  
 126      function fetch($id, $group) {
 127          $file = $this->getFilename($id, $group);
 128          if (!file_exists($file))
 129              return array(NULL, NULL, NULL);
 130  
 131          // retrive the content
 132          if (!($fh = @fopen($file, 'rb')))
 133              return new Cache_Error("Can't access cache file '$file'. Check access rights and path.", __FILE__, __LINE__);
 134  
 135          // File locking (shared lock)
 136          if ($this->fileLocking)
 137              flock($fh, LOCK_SH);
 138  
 139          // file format:
 140          // 1st line: expiration date
 141          // 2nd line: user data
 142          // 3rd+ lines: cache data
 143          $expire = trim(fgets($fh, 12));
 144          if ($this->max_userdata_linelength == 0 ) {
 145              $userdata = trim(fgets($fh));
 146          } else {
 147              $userdata = trim(fgets($fh, $this->max_userdata_linelength));
 148          }
 149          $cachedata = $this->decode(fread($fh, filesize($file)));
 150  
 151          // Unlocking
 152          if ($this->fileLocking)
 153              flock($fh, LOCK_UN);
 154  
 155          fclose($fh);
 156  
 157          // last usage date used by the gc - maxlifetime
 158          // touch without second param produced stupid entries...
 159          touch($file,time());
 160          clearstatcache();
 161  
 162          return array($expire, $cachedata, $userdata);
 163      } // end func fetch
 164  
 165      /**
 166      * Stores a dataset.
 167      *
 168      * WARNING: If you supply userdata it must not contain any linebreaks,
 169      * otherwise it will break the filestructure.
 170      */
 171      function save($id, $cachedata, $expires, $group, $userdata) {
 172          $this->flushPreload($id, $group);
 173  
 174          $file = $this->getFilename($id, $group);
 175          if (!($fh = @fopen($file, 'wb')))
 176              return new Cache_Error("Can't access '$file' to store cache data. Check access rights and path.", __FILE__, __LINE__);
 177  
 178          // File locking (exclusive lock)
 179          if ($this->fileLocking)
 180              flock($fh, LOCK_EX);
 181  
 182          // file format:
 183          // 1st line: expiration date
 184          // 2nd line: user data
 185          // 3rd+ lines: cache data
 186          $expires = $this->getExpiresAbsolute($expires);
 187          fwrite($fh, $expires . "\n");
 188          fwrite($fh, $userdata . "\n");
 189          fwrite($fh, $this->encode($cachedata));
 190  
 191          // File unlocking
 192          if ($this->fileLocking)
 193              flock($fh, LOCK_UN);
 194  
 195          fclose($fh);
 196  
 197          // I'm not sure if we need this
 198      // i don't think we need this (chregu)
 199          // touch($file);
 200  
 201          return true;
 202      } // end func save
 203  
 204      function remove($id, $group) {
 205          $this->flushPreload($id, $group);
 206  
 207          $file = $this->getFilename($id, $group);
 208          if (file_exists($file)) {
 209  
 210              $ok = unlink($file);
 211              clearstatcache();
 212  
 213              return $ok;
 214          }
 215  
 216          return false;
 217      } // end func remove
 218  
 219      function flush($group) {
 220          $this->flushPreload();
 221          $dir = ($group) ? $this->cache_dir . $group . '/' : $this->cache_dir;
 222  
 223          $num_removed = $this->deleteDir($dir);
 224          unset($this->group_dirs[$group]);
 225          clearstatcache();
 226  
 227          return $num_removed;
 228      } // end func flush
 229  
 230      function idExists($id, $group) {
 231  
 232          return file_exists($this->getFilename($id, $group));
 233      } // end func idExists
 234  
 235      /**
 236      * Deletes all expired files.
 237      *
 238      * Garbage collection for files is a rather "expensive", "long time"
 239      * operation. All files in the cache directory have to be examined which
 240      * means that they must be opened for reading, the expiration date has to be
 241      * read from them and if neccessary they have to be unlinked (removed).
 242      * If you have a user comment for a good default gc probability please add it to
 243      * to the inline docs.
 244      *
 245      * @param    integer Maximum lifetime in seconds of an no longer used/touched entry
 246      * @throws   Cache_Error
 247      */
 248      function garbageCollection($maxlifetime) {
 249  
 250          $this->flushPreload();
 251          clearstatcache();
 252  
 253          $ok = $this->doGarbageCollection($maxlifetime, $this->cache_dir);
 254  
 255          // check the space used by the cache entries        
 256          if ($this->total_size > $this->highwater) {
 257          
 258              krsort($this->entries);
 259              reset($this->entries);
 260              
 261              while ($this->total_size > $this->lowwater && list($lastmod, $entry) = each($this->entries)) {
 262                  if (@unlink($entry['file']))
 263                      $this->total_size -= $entry['size'];
 264                  else
 265                      new CacheError("Can't delete {$entry["file"]}. Check the permissions.");
 266              }
 267              
 268          }
 269          
 270          $this->entries = array();
 271          $this->total_size = 0;
 272          
 273          return $ok;
 274      } // end func garbageCollection
 275      
 276      /**
 277      * Does the recursive gc procedure, protected.
 278      *
 279      * @param    integer Maximum lifetime in seconds of an no longer used/touched entry
 280      * @param    string  directory to examine - don't sets this parameter, it's used for a
 281      *                   recursive function call!
 282      * @throws   Cache_Error
 283      */
 284      function doGarbageCollection($maxlifetime, $dir) {
 285             
 286          if (!($dh = opendir($dir)))
 287              return new Cache_Error("Can't access cache directory '$dir'. Check permissions and path.", __FILE__, __LINE__);
 288  
 289          while ($file = readdir($dh)) {
 290              if ('.' == $file || '..' == $file)
 291                  continue;
 292  
 293              $file = $dir . $file;
 294              if (is_dir($file)) {
 295                  $this->doGarbageCollection($maxlifetime,$file . '/');
 296                  continue;
 297              }
 298  
 299              // skip trouble makers but inform the user
 300              if (!($fh = @fopen($file, 'rb'))) {
 301                  new Cache_Error("Can't access cache file '$file', skipping it. Check permissions and path.", __FILE__, __LINE__);
 302                  continue;
 303              }
 304  
 305              $expire = fgets($fh, 11);
 306              fclose($fh);
 307              $lastused = filemtime($file);
 308              
 309              $this->entries[$lastused] = array('file' => $file, 'size' => filesize($file));
 310              $this->total_size += filesize($file);
 311              
 312              // remove if expired
 313              if (( ($expire && $expire <= time()) || ($lastused <= (time() - $maxlifetime)) ) && !unlink($file))
 314                  new Cache_Error("Can't unlink cache file '$file', skipping. Check permissions and path.", __FILE__, __LINE__);
 315          }
 316  
 317          closedir($dh);
 318  
 319          // flush the disk state cache
 320          clearstatcache();
 321  
 322      } // end func doGarbageCollection
 323  
 324      /**
 325      * Returns the filename for the specified id.
 326      *
 327      * @param    string  dataset ID
 328      * @param    string  cache group
 329      * @return   string  full filename with the path
 330      * @access   public
 331      */
 332      function getFilename($id, $group) {
 333  
 334          if (isset($this->group_dirs[$group]))
 335              return $this->group_dirs[$group] . $this->filename_prefix . $id;
 336  
 337          $dir = $this->cache_dir . $group . '/';
 338          if (!file_exists($dir)) {
 339              mkdir($dir, 0755);
 340              clearstatcache();
 341          }
 342  
 343          $this->group_dirs[$group] = $dir;
 344  
 345          return $dir . $this->filename_prefix . $id;
 346      } // end func getFilename
 347  
 348      /**
 349      * Deletes a directory and all files in it.
 350      *
 351      * @param    string  directory
 352      * @return   integer number of removed files
 353      * @throws   Cache_Error
 354      */
 355      function deleteDir($dir) {
 356          if (!($dh = opendir($dir)))
 357              return new Cache_Error("Can't remove directory '$dir'. Check permissions and path.", __FILE__, __LINE__);
 358  
 359          $num_removed = 0;
 360  
 361          while (false !== $file = readdir($dh)) {
 362              if ('.' == $file || '..' == $file)
 363                  continue;
 364  
 365              $file = $dir . $file;
 366              if (is_dir($file)) {
 367                  $file .= '/';
 368                  $num = $this->deleteDir($file . '/');
 369                  if (is_int($num))
 370                      $num_removed += $num;
 371              } else {
 372                  if (unlink($file))
 373                      $num_removed++;
 374              }
 375          }
 376          // according to php-manual the following is needed for windows installations.
 377          closedir($dh);
 378          unset( $dh);
 379          if ($dir != $this->cache_dir) {  //delete the sub-dir entries  itself also, but not the cache-dir.
 380              rmDir($dir);
 381              $num_removed++;
 382          }
 383  
 384          return $num_removed;
 385      } // end func deleteDir
 386      
 387  } // end class file
 388  ?>


Généré le : Sun Feb 25 14:08:00 2007 par Balluche grâce à PHPXref 0.7