Development

/branches/1.3/lib/cache/sfFileCache.class.php

You must first sign up to be able to contribute.

root/branches/1.3/lib/cache/sfFileCache.class.php

Revision 23810, 7.8 kB (checked in by Kris.Wallsmith, 4 years ago)

[1.3] set svn:eol-style property to native and svn:keywords property to Id on all .php files

  • Property svn:mime-type set to text/x-php
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
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  * @package    symfony
15  * @subpackage cache
16  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
17  * @version    SVN: $Id$
18  */
19 class sfFileCache extends sfCache
20 {
21   const READ_DATA = 1;
22   const READ_TIMEOUT = 2;
23   const READ_LAST_MODIFIED = 4;
24
25   const EXTENSION = '.cache';
26
27  /**
28   * Initializes this sfCache instance.
29   *
30   * Available options:
31   *
32   * * cache_dir: The directory where to put cache files
33   *
34   * * see sfCache for options available for all drivers
35   *
36   * @see sfCache
37   */
38   public function initialize($options = array())
39   {
40     parent::initialize($options);
41
42     if (!$this->getOption('cache_dir'))
43     {
44       throw new sfInitializationException('You must pass a "cache_dir" option to initialize a sfFileCache object.');
45     }
46
47     $this->setcache_dir($this->getOption('cache_dir'));
48   }
49
50   /**
51    * @see sfCache
52    */
53   public function get($key, $default = null)
54   {
55     $file_path = $this->getFilePath($key);
56     if (!file_exists($file_path))
57     {
58       return $default;
59     }
60
61     $data = $this->read($file_path, self::READ_DATA);
62
63     if ($data[self::READ_DATA] === null)
64     {
65       return $default;
66     }
67
68     return $data[self::READ_DATA];
69   }
70
71   /**
72    * @see sfCache
73    */
74   public function has($key)
75   {
76     $path = $this->getFilePath($key);
77     return file_exists($path) && $this->isValid($path);
78   }
79
80   /**
81    * @see sfCache
82    */
83   public function set($key, $data, $lifetime = null)
84   {
85     if ($this->getOption('automatic_cleaning_factor') > 0 && rand(1, $this->getOption('automatic_cleaning_factor')) == 1)
86     {
87       $this->clean(sfCache::OLD);
88     }
89
90     return $this->write($this->getFilePath($key), $data, time() + $this->getLifetime($lifetime));
91   }
92
93   /**
94    * @see sfCache
95    */
96   public function remove($key)
97   {
98     return @unlink($this->getFilePath($key));
99   }
100
101   /**
102    * @see sfCache
103    */
104   public function removePattern($pattern)
105   {
106     if (false !== strpos($pattern, '**'))
107     {
108       $pattern = str_replace(sfCache::SEPARATOR, DIRECTORY_SEPARATOR, $pattern).self::EXTENSION;
109
110       $regexp = self::patternToRegexp($pattern);
111       $paths = array();
112       foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->getOption('cache_dir'))) as $path)
113       {
114         if (preg_match($regexp, str_replace($this->getOption('cache_dir').DIRECTORY_SEPARATOR, '', $path)))
115         {
116           $paths[] = $path;
117         }
118       }
119     }
120     else
121     {
122       $paths = glob($this->getOption('cache_dir').DIRECTORY_SEPARATOR.str_replace(sfCache::SEPARATOR, DIRECTORY_SEPARATOR, $pattern).self::EXTENSION);
123     }
124
125     foreach ($paths as $path)
126     {
127       if (is_dir($path))
128       {
129         sfToolkit::clearDirectory($path);
130       }
131       else
132       {
133         @unlink($path);
134       }
135     }
136   }
137
138   /**
139    * @see sfCache
140    */
141   public function clean($mode = sfCache::ALL)
142   {
143     if (!is_dir($this->getOption('cache_dir')))
144     {
145       return true;
146     }
147
148     $result = true;
149     foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->getOption('cache_dir'))) as $file)
150     {
151       if (sfCache::ALL == $mode || !$this->isValid($file))
152       {
153         $result = @unlink($file) && $result;
154       }
155     }
156
157     return $result;
158   }
159
160   /**
161    * @see sfCache
162    */
163   public function getTimeout($key)
164   {
165     $path = $this->getFilePath($key);
166
167     if (!file_exists($path))
168     {
169       return 0;
170     }
171
172     $data = $this->read($path, self::READ_TIMEOUT);
173
174     return $data[self::READ_TIMEOUT] < time() ? 0 : $data[self::READ_TIMEOUT];
175   }
176
177   /**
178    * @see sfCache
179    */
180   public function getLastModified($key)
181   {
182     $path = $this->getFilePath($key);
183
184     if (!file_exists($path))
185     {
186       return 0;
187     }
188     
189     $data = $this->read($path, self::READ_TIMEOUT | self::READ_LAST_MODIFIED);
190
191     if ($data[self::READ_TIMEOUT] < time())
192     {
193       return 0;
194     }
195     return $data[self::READ_LAST_MODIFIED];
196   }
197
198   protected function isValid($path)
199   {
200     $data = $this->read($path, self::READ_TIMEOUT);
201     return time() < $data[self::READ_TIMEOUT];
202   }
203
204  /**
205   * Converts a cache key to a full path.
206   *
207   * @param string $key The cache key
208   *
209   * @return string The full path to the cache file
210   */
211   protected function getFilePath($key)
212   {
213     return $this->getOption('cache_dir').DIRECTORY_SEPARATOR.str_replace(sfCache::SEPARATOR, DIRECTORY_SEPARATOR, $key).self::EXTENSION;
214   }
215
216  /**
217   * Reads the cache file and returns the content.
218   *
219   * @param string $path The file path
220   * @param mixed  $type The type of data you want to be returned
221   *                     sfFileCache::READ_DATA: The cache content
222   *                     sfFileCache::READ_TIMEOUT: The timeout
223   *                     sfFileCache::READ_LAST_MODIFIED: The last modification timestamp
224   *
225   * @return array the (meta)data of the cache file. E.g. $data[sfFileCache::READ_DATA]
226   *
227   * @throws sfCacheException
228   */
229   protected function read($path, $type = self::READ_DATA)
230   {
231     if (!$fp = @fopen($path, 'rb'))
232     {
233       throw new sfCacheException(sprintf('Unable to read cache file "%s".', $path));
234     }
235
236     @flock($fp, LOCK_SH);
237     $data[self::READ_TIMEOUT] = intval(@stream_get_contents($fp, 12, 0));
238     if ($type != self::READ_TIMEOUT && time() < $data[self::READ_TIMEOUT])
239     {
240       if ($type & self::READ_LAST_MODIFIED)
241       {
242         $data[self::READ_LAST_MODIFIED] = intval(@stream_get_contents($fp, 12, 12));
243       }
244       if ($type & self::READ_DATA)
245       {
246         fseek($fp, 0, SEEK_END);
247         $length = ftell($fp) - 24;
248         fseek($fp, 24);
249         $data[self::READ_DATA] = @fread($fp, $length);
250       }
251     }
252     else
253     {
254       $data[self::READ_LAST_MODIFIED] = null;
255       $data[self::READ_DATA] = null;
256     }
257     @flock($fp, LOCK_UN);
258     @fclose($fp);
259
260     return $data;
261   }
262
263  /**
264   * Writes the given data in the cache file.
265   *
266   * @param string  $path    The file path
267   * @param string  $data    The data to put in cache
268   * @param integer $timeout The timeout timestamp
269   *
270   * @return boolean true if ok, otherwise false
271   *
272   * @throws sfCacheException
273   */
274   protected function write($path, $data, $timeout)
275   {
276     $current_umask = umask();
277     umask(0000);
278
279     if (!is_dir(dirname($path)))
280     {
281       // create directory structure if needed
282       mkdir(dirname($path), 0777, true);
283     }
284
285     $tmpFile = tempnam(dirname($path), basename($path));
286
287     if (!$fp = @fopen($tmpFile, 'wb'))
288     {
289        throw new sfCacheException(sprintf('Unable to write cache file "%s".', $tmpFile));
290     }
291
292     @fwrite($fp, str_pad($timeout, 12, 0, STR_PAD_LEFT));
293     @fwrite($fp, str_pad(time(), 12, 0, STR_PAD_LEFT));
294     @fwrite($fp, $data);
295     @fclose($fp);
296
297     // Hack from Agavi (http://trac.agavi.org/changeset/3979)
298     // With php < 5.2.6 on win32, renaming to an already existing file doesn't work, but copy does,
299     // so we simply assume that when rename() fails that we are on win32 and try to use copy()
300     if (!@rename($tmpFile, $path))
301     {
302       if (copy($tmpFile, $path))
303       {
304         unlink($tmpFile);
305       }
306     }
307
308     chmod($path, 0666);
309     umask($current_umask);
310
311     return true;
312   }
313
314   /**
315    * Sets the cache root directory.
316    *
317    * @param string $cache_dir The directory where to put the cache files
318    */
319   protected function setcache_dir($cache_dir)
320   {
321     // remove last DIRECTORY_SEPARATOR
322     if (DIRECTORY_SEPARATOR == substr($cache_dir, -1))
323     {
324       $cache_dir = substr($cache_dir, 0, -1);
325     }
326
327     // create cache dir if needed
328     if (!is_dir($cache_dir))
329     {
330       $current_umask = umask(0000);
331       @mkdir($cache_dir, 0777, true);
332       umask($current_umask);
333     }
334   }
335 }
336
Note: See TracBrowser for help on using the browser.