Source for file FileStorage.php
Documentation is available at FileStorage.php
6: * Copyright (c) 2004, 2009 David Grudl (http://davidgrudl.com)
8: * This source file is subject to the "Nette license" that is bundled
9: * with this package in the file license.txt.
11: * For more information please see https://nette.org
13: * @copyright Copyright (c) 2004, 2009 David Grudl
14: * @license https://nette.org/license Nette license
15: * @link https://nette.org
17: * @package Nette\Caching
23: require_once dirname(__FILE__) .
'/../Object.php';
25: require_once dirname(__FILE__) .
'/../Caching/ICacheStorage.php';
30: * Cache file storage.
32: * @author David Grudl
33: * @copyright Copyright (c) 2004, 2009 David Grudl
34: * @package Nette\Caching
39: * Atomic thread safe logic:
41: * 1) reading: open(r+b), lock(SH), read
42: * - delete?: lock(EX), truncate*, unlink*, close
43: * 2) deleting: open(r+b), lock(EX), truncate*, unlink*, close
44: * 3) writing: open(r+b || wb), lock(EX), truncate*, write data, write meta, close
46: * *unlink fails in windows
49: /**#@+ internal cache file structure */
50: const META_HEADER_LEN =
28; // 22b signature + 6b meta-struct size + serialized meta-struct + data
51: // meta structure: array of
57: const META_FILES =
'df'; // array of dependent files (file => timestamp)
58: const META_ITEMS =
'di'; // array of dependent items (file => timestamp)
59: const META_TAGS =
'tags'; // array of tags (tag => [foo])
60: const META_CONSTS =
'consts'; // array of constants (const => [value])
63: /**#@+ additional cache structure */
69: /** @var float probability that the clean() routine is started */
70: public static $gcProbability =
0.001;
101: if ($meta &&
$this->verify($meta)) {
112: * Verifies dependencies.
116: private function verify($meta)
119: /*if (!empty($meta[self::META_DELTA]) || !empty($meta[self::META_FILES])) {
123: if (!empty($meta[self::META_DELTA])) {
124: // meta[file] was added by readMeta()
128: } elseif (!empty($meta[self::META_EXPIRE]) &&
$meta[self::META_EXPIRE] <
time()) {
132: if (!empty($meta[self::META_CONSTS])) {
133: foreach ($meta[self::META_CONSTS] as $const =>
$value) {
138: if (!empty($meta[self::META_FILES])) {
139: foreach ($meta[self::META_FILES] as $depFile =>
$time) {
140: if (@filemtime($depFile) <>
$time) break 2; // intentionally @
144: if (!empty($meta[self::META_ITEMS])) {
145: foreach ($meta[self::META_ITEMS] as $depFile =>
$time) {
147: if ($m[self::META_TIME] !==
$time) break 2;
148: if ($m &&
!$this->verify($m)) break 2;
155: // meta[handle] was added by readMeta()
158: @unlink($meta[self::FILE]); // intentionally @; meta[file] was added by readMeta()
166: * Writes item into the cache.
169: * @param array dependencies
170: * @return bool TRUE if no problem
172: public function write($key, $data, array $dp)
175: self::META_TIME =>
microtime(),
178: if (!is_string($data)) {
179: $data =
serialize($data);
184: $meta[self::META_PRIORITY] = (int)
$dp[Cache::PRIORITY];
193: $meta[self::META_EXPIRE] =
$expire; // absolute time
195: $meta[self::META_DELTA] =
$expire -
time(); // sliding time
207: $meta[self::META_ITEMS][$depFile] =
$m[self::META_TIME];
214: foreach ((array)
$dp[Cache::FILES] as $depFile) {
215: $meta[self::META_FILES][$depFile] =
@filemtime($depFile); // intentionally @
220: foreach ((array)
$dp[Cache::CONSTS] as $const) {
226: $handle =
@fopen($cacheFile, 'r+b'); // intentionally @
228: $handle =
@fopen($cacheFile, 'wb'); // intentionally @
239: $head =
'<?php //netteCache[01]' .
str_pad((string)
strlen($head), 6, '0', STR_PAD_LEFT) .
$head;
244: if (fwrite($handle, $data, $dataLen) ===
$dataLen) {
246: if (fwrite($handle, $head, $headLen) ===
$headLen) {
262: * Removes item from the cache.
264: * @return bool TRUE if no problem
270: if (!$meta) return TRUE;
281: * Removes items from the cache by conditions & garbage collector.
282: * @param array conditions
283: * @return bool TRUE if no problem
287: $tags =
isset($conds[Cache::TAGS]) ?
array_flip($conds[Cache::TAGS]) :
array();
289: $priority =
isset($conds[Cache::PRIORITY]) ?
$conds[Cache::PRIORITY] : -
1;
291: $all =
!empty($conds[Cache::ALL]);
295: foreach (glob($this->base .
'*') as $cacheFile)
301: if (!$meta ||
$all) continue 2;
303: if (!empty($meta[self::META_EXPIRE]) &&
$meta[self::META_EXPIRE] <
$now) {
307: if (!empty($meta[self::META_PRIORITY]) &&
$meta[self::META_PRIORITY] <=
$priority) {
331: * Reads cache data from disk.
332: * @param string file path
333: * @param int lock mode
334: * @return array|NULL
338: $handle =
@fopen($file, 'r+b'); // intentionally @
339: if (!$handle) return NULL;
344: if ($head &&
strlen($head) ===
self::META_HEADER_LEN) {
349: fseek($handle, $size +
self::META_HEADER_LEN); // needed by PHP < 5.2.6
350: $meta[self::FILE] =
$file;
351: $meta[self::HANDLE] =
$handle;
363: * Reads cache data from disk and closes cache file handle.
372: if (empty($meta[self::META_SERIALIZED])) {
382: * Returns file name.