Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 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: sfFileCache.class.php 23810 2009-11-12 11:07:44Z Kris.Wallsmith $
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
}