2 // vim: foldmethod=marker tabstop=4 shiftwidth=4 autoindent
4 * Ethna_Plugin_Cachemanager_Localfile.php
6 * @author Masaki Fujimoto <fujimoto@php.net>
7 * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
13 * キャッシュマネージャクラス(ローカルファイルキャッシュ版)
15 * @author Masaki Fujimoto <fujimoto@php.net>
19 class Ethna_Plugin_Cachemanager_Localfile extends Ethna_Plugin_Cachemanager
21 /**#@+ @access private */
28 * キャッシュに値が設定されている場合はキャッシュ値
29 * が戻り値となる。キャッシュに値が無い場合やlifetime
30 * を過ぎている場合、エラーが発生した場合はEthna_Error
34 * @param string $key キャッシュキー
35 * @param int $lifetime キャッシュ有効期間
36 * @param string $namespace キャッシュネームスペース
37 * @return array キャッシュ値
39 function get($key, $lifetime = null, $namespace = null)
41 $namespace = is_null($namespace) ? $this->namespace : $namespace;
42 $cache_file = $this->_getCacheFile($namespace, $key);
46 if (is_readable($cache_file) === false
47 || ($st = stat($cache_file)) === false) {
48 return Ethna::raiseError('fopen failed', E_CACHE_NO_VALUE);
50 if (is_null($lifetime) == false) {
51 if (($st[9]+$lifetime) < time()) {
52 return Ethna::raiseError('fopen failed', E_CACHE_EXPIRED);
56 $fp = fopen($cache_file, "r");
58 return Ethna::raiseError('fopen failed', E_CACHE_NO_VALUE);
62 while ($timeout > 0) {
63 $r = flock($fp, LOCK_EX|LOCK_NB);
72 return Ethna::raiseError('fopen failed', E_CACHE_GENERAL);
78 $st = stat($cache_file);
86 if ($st == false || $n > 5) {
88 return Ethna::raiseError('stat failed', E_CACHE_NO_VALUE);
90 $value = fread($fp, $st[7]);
93 return unserialize($value);
100 * @param string $key キャッシュキー
101 * @param string $namespace キャッシュネームスペース
102 * @return int 最終更新日時(unixtime)
104 function getLastModified($key, $namespace = null)
106 $namespace = is_null($namespace) ? $this->namespace : $namespace;
107 $cache_file = $this->_getCacheFile($namespace, $key);
110 if (is_readable($cache_file) === false
111 || ($st = stat($cache_file)) === false) {
112 return Ethna::raiseError('fopen failed', E_CACHE_NO_VALUE);
118 * 値がキャッシュされているかどうかを取得する
121 * @param string $key キャッシュキー
122 * @param int $lifetime キャッシュ有効期間
123 * @param string $namespace キャッシュネームスペース
125 function isCached($key, $lifetime = null, $namespace = null)
127 $namespace = is_null($namespace) ? $this->namespace : $namespace;
128 $cache_file = $this->_getCacheFile($namespace, $key);
132 if (is_readable($cache_file) === false
133 || ($st = stat($cache_file)) === false) {
136 if (is_null($lifetime) == false) {
137 if (($st[9]+$lifetime) < time()) {
149 * @param string $key キャッシュキー
150 * @param mixed $value キャッシュ値
151 * @param int $timestamp キャッシュ最終更新時刻(unixtime)
152 * @param string $namespace キャッシュネームスペース
154 function set($key, $value, $timestamp = null, $namespace = null)
156 $namespace = is_null($namespace) ? $this->namespace : $namespace;
157 $dir = $this->_getCacheDir($namespace, $key);
160 $r = Ethna_Util::mkdir($dir, 0777);
161 if ($r == false && is_dir($dir) == false) {
162 return Ethna::raiseError('mkdir(%s) failed', E_USER_WARNING, $dir);
165 $cache_file = $this->_getCacheFile($namespace, $key);
166 $fp = fopen($cache_file, "a+");
168 return Ethna::raiseError('fopen failed', E_CACHE_GENERAL);
173 while ($timeout > 0) {
174 $r = flock($fp, LOCK_EX|LOCK_NB);
183 return Ethna::raiseError('fopen failed', E_CACHE_GENERAL);
187 fwrite($fp, serialize($value));
189 Ethna_Util::chmod($cache_file, 0666);
191 if (is_null($timestamp)) {
192 // this could suppress warning
195 touch($cache_file, $timestamp);
205 * @param string $key キャッシュキー
206 * @param string $namespace キャッシュネームスペース
208 function clear($key, $namespace = null)
210 $namespace = is_null($namespace) ? $this->namespace : $namespace;
211 $cache_file = $this->_getCacheFile($namespace, $key);
213 if (file_exists($cache_file)) {
223 function _getCacheDir($namespace, $key)
226 // intentionally avoid using -2 or -4
227 $dir1 = substr($key, $len-4, 2);
228 if ($len-4 < 0 || strlen($dir1) < 2) {
231 $dir2 = substr($key, $len-2, 2);
232 if ($len-2 < 0 || strlen($dir2) < 2) {
236 $map = $this->config->get('cachemanager_localfile');
237 $tmp_key = $namespace . "::" . $key;
241 if (is_array($map)) {
242 foreach ($map as $key => $value) {
243 if (strncmp($key, $tmp_key, strlen($key)) == 0) {
250 return sprintf("%s/cache/%s/cache_%s/%s/%s", $this->backend->getTmpdir(), $dir, $this->_escape($namespace), $this->_escape($dir1), $this->_escape($dir2));
258 function _getCacheFile($namespace, $key)
260 return sprintf("%s/%s", $this->_getCacheDir($namespace, $key), $this->_escape($key));
264 * キーをファイルシステム用にエスケープする
268 function _escape($string)
270 return preg_replace('/([^0-9A-Za-z_])/e', "sprintf('%%%02X', ord('\$1'))", $string);