php支持apc和文件缓存的缓存类
PHP #文件缓存 #类 #apc2012-10-30 13:35
刚发现一个PHP缓存实现,实现了apc和文件缓存,继承Cache_Abstract即可实现调用第三方的缓存工具。参考shindig的缓存类和apc。
类代码如下:
001 | <?php |
002 | class CacheException extends Exception { |
003 | } |
004 |
005 | /** |
006 | * 缓存抽象类 |
007 | */ |
008 | abstract class Cache_Abstract { |
009 | /** |
010 | * 读缓存变量 |
011 | * |
012 | * @param string $key 缓存下标 |
013 | * @return mixed |
014 | */ |
015 | abstract public function fetch( $key ); |
016 |
017 | /** |
018 | * 缓存变量 |
019 | * |
020 | * @param string $key 缓存变量下标 |
021 | * @param string $value 缓存变量的值 |
022 | * @return bool |
023 | */ |
024 | abstract public function store( $key , $value ); |
025 |
026 | /** |
027 | * 删除缓存变量 |
028 | * |
029 | * @param string $key 缓存下标 |
030 | * @return Cache_Abstract |
031 | */ |
032 | abstract public function delete ( $key ); |
033 |
034 | /** |
035 | * 清(删)除所有缓存 |
036 | * |
037 | * @return Cache_Abstract |
038 | */ |
039 | abstract public function clear(); |
040 |
041 | /** |
042 | * 锁定缓存变量 |
043 | * |
044 | * @param string $key 缓存下标 |
045 | * @return Cache_Abstract |
046 | */ |
047 | abstract public function lock( $key ); |
048 |
049 | /** |
050 | * 缓存变量解锁 |
051 | * |
052 | * @param string $key 缓存下标 |
053 | * @return Cache_Abstract |
054 | */ |
055 | abstract public function unlock( $key ); |
056 |
057 | /** |
058 | * 取得缓存变量是否被锁定 |
059 | * |
060 | * @param string $key 缓存下标 |
061 | * @return bool |
062 | */ |
063 | abstract public function isLocked( $key ); |
064 |
065 | /** |
066 | * 确保不是锁定状态 |
067 | * 最多做$tries次睡眠等待解锁,超时则跳过并解锁 |
068 | * |
069 | * @param string $key 缓存下标 |
070 | */ |
071 | public function checkLock( $key ) { |
072 | if (! $this -> isLocked( $key )) { |
073 | return $this ; |
074 | } |
075 |
076 | $tries = 10; |
077 | $count = 0; |
078 | do { |
079 | usleep(200); |
080 | $count ++; |
081 | } while ( $count <= $tries && $this ->isLocked( $key )); // 最多做十次睡眠等待解锁,超时则跳过并解锁 |
082 |
083 | $this -> isLocked( $key ) && $this -> unlock( $key ); |
084 |
085 | return $this ; |
086 | } |
087 |
088 | } |
089 |
090 | /** |
091 | * APC扩展缓存实现 |
092 | * |
093 | * |
094 | * @category Mjie |
095 | * @package Cache |
096 | * @author 流水孟春 |
097 | * @copyright Copyright (c) 2008- <cmpan(at)qq.com> |
098 | * @license New BSD License |
099 | * @version $Id: Cache/Apc.php 版本号 2010-04-18 23:02 cmpan $ |
100 | */ |
101 | class Cache_Apc extends Cache_Abstract { |
102 |
103 | protected $_prefix = 'cache.mjie.net' ; |
104 |
105 | public function __construct() { |
106 | if (!function_exists( 'apc_cache_info' )) { |
107 | throw new CacheException( 'apc extension didn' t installed'); |
108 | } |
109 | } |
110 |
111 | /** |
112 | * 保存缓存变量 |
113 | * |
114 | * @param string $key |
115 | * @param mixed $value |
116 | * @return bool |
117 | */ |
118 | public function store( $key , $value ) { |
119 | return apc_store( $this -> _storageKey( $key ), $value ); |
120 | } |
121 |
122 | /** |
123 | * 读取缓存 |
124 | * |
125 | * @param string $key |
126 | * @return mixed |
127 | */ |
128 | public function fetch( $key ) { |
129 | return apc_fetch( $this -> _storageKey( $key )); |
130 | } |
131 |
132 | /** |
133 | * 清除缓存 |
134 | * |
135 | * @return Cache_Apc |
136 | */ |
137 | public function clear() { |
138 | apc_clear_cache(); |
139 | return $this ; |
140 | } |
141 |
142 | /** |
143 | * 删除缓存单元 |
144 | * |
145 | * @return Cache_Apc |
146 | */ |
147 | public function delete ( $key ) { |
148 | apc_delete( $this -> _storageKey( $key )); |
149 | return $this ; |
150 | } |
151 |
152 | /** |
153 | * 缓存单元是否被锁定 |
154 | * |
155 | * @param string $key |
156 | * @return bool |
157 | */ |
158 | public function isLocked( $key ) { |
159 | if ((apc_fetch( $this -> _storageKey( $key ) . '.lock' )) === false) { |
160 | return false; |
161 | } |
162 |
163 | return true; |
164 | } |
165 |
166 | /** |
167 | * 锁定缓存单元 |
168 | * |
169 | * @param string $key |
170 | * @return Cache_Apc |
171 | */ |
172 | public function lock( $key ) { |
173 | apc_store( $this -> _storageKey( $key ) . '.lock' , '' , 5); |
174 | return $this ; |
175 | } |
176 |
177 | /** |
178 | * 缓存单元解锁 |
179 | * |
180 | * @param string $key |
181 | * @return Cache_Apc |
182 | */ |
183 | public function unlock( $key ) { |
184 | apc_delete( $this -> _storageKey( $key ) . '.lock' ); |
185 | return $this ; |
186 | } |
187 |
188 | /** |
189 | * 完整缓存名 |
190 | * |
191 | * @param string $key |
192 | * @return string |
193 | */ |
194 | private function _storageKey( $key ) { |
195 | return $this -> _prefix . '_' . $key ; |
196 | } |
197 |
198 | } |
199 |
200 | /** |
201 | * 文件缓存实现 |
202 | * |
203 | * |
204 | * @category Mjie |
205 | * @package Cache |
206 | * @author 流水孟春 |
207 | * @copyright Copyright (c) 2008- <cmpan(at)qq.com> |
208 | * @license New BSD License |
209 | * @version $Id: Cache/File.php 版本号 2010-04-18 16:46 cmpan $ |
210 | */ |
211 | class Cache_File extends Cache_Abstract { |
212 | public $useSubdir = false; |
213 |
214 | protected $_cachesDir = 'cache' ; |
215 |
216 | public function __construct() { |
217 | if (defined( 'DATA_DIR' )) { |
218 | $this -> _setCacheDir(DATA_DIR . '/cache' ); |
219 | } |
220 | } |
221 |
222 | /** |
223 | * 获取缓存文件 |
224 | * |
225 | * @param string $key |
226 | * @return string |
227 | */ |
228 | protected function _getCacheFile( $key ) { |
229 | $subdir = $this -> useSubdir ? substr ( $key , 0, 2) . '/' : '' ; |
230 | return $this -> _cachesDir . '/' . $subdir . $key . '.php' ; |
231 | } |
232 |
233 | /** |
234 | * 读取缓存变量 |
235 | * 为防止信息泄露,缓存文件格式为php文件,并以"<?php exit;?>"开头 |
236 | * |
237 | * @param string $key 缓存下标 |
238 | * @return mixed |
239 | */ |
240 | public function fetch( $key ) { |
241 | $cacheFile = self::_getCacheFile( $key ); |
242 | if ( file_exists ( $cacheFile ) && is_readable ( $cacheFile )) { |
243 | // include 方式 |
244 | //return include $cacheFile; |
245 | // 系列化方式 |
246 |
247 | return unserialize(@ file_get_contents ( $cacheFile , false, NULL, 13)); |
248 | } |
249 |
250 | return false; |
251 | } |
252 |
253 | /** |
254 | * 缓存变量 |
255 | * 为防止信息泄露,缓存文件格式为php文件,并以"<?php exit;?>"开头 |
256 | * |
257 | * @param string $key 缓存变量下标 |
258 | * @param string $value 缓存变量的值 |
259 | * @return bool |
260 | */ |
261 | public function store( $key , $value ) { |
262 | $cacheFile = self::_getCacheFile( $key ); |
263 | $cacheDir = dirname( $cacheFile ); |
264 |
265 | if (! is_dir ( $cacheDir )) { |
266 | if (!@ mkdir ( $cacheDir , 0755, true)) { |
267 | throw new CacheException( "Could not make cache directory" ); |
268 | } |
269 | } |
270 | // 用include方式 |
271 | //return @file_put_contents($cacheFile, '<?php return ' . var_export($value, true). ';'); |
272 |
273 | return @ file_put_contents ( $cacheFile , '<?php exit;?>' . serialize( $value )); |
274 | } |
275 |
276 | /** |
277 | * 删除缓存变量 |
278 | * |
279 | * @param string $key 缓存下标 |
280 | * @return Cache_File |
281 | */ |
282 | public function delete ( $key ) { |
283 | if (emptyempty( $key )) { |
284 | throw new CacheException( "Missing argument 1 for Cache_File::delete()" ); |
285 | } |
286 |
287 | $cacheFile = self::_getCacheFile( $key ); |
288 | if (!@unlink( $cacheFile )) { |
289 | throw new CacheException( "Cache file could not be deleted" ); |
290 | } |
291 |
292 | return $this ; |
293 | } |
294 |
295 | /** |
296 | * 缓存单元是否已经锁定 |
297 | * |
298 | * @param string $key |
299 | * @return bool |
300 | */ |
301 | public function isLocked( $key ) { |
302 | $cacheFile = self::_getCacheFile( $key ); |
303 | clearstatcache(); |
304 | return file_exists ( $cacheFile . '.lock' ); |
305 | } |
306 |
307 | /** |
308 | * 锁定 |
309 | * |
310 | * @param string $key |
311 | * @return Cache_File |
312 | */ |
313 | public function lock( $key ) { |
314 | $cacheFile = self::_getCacheFile( $key ); |
315 | $cacheDir = dirname( $cacheFile ); |
316 | if (! is_dir ( $cacheDir )) { |
317 | if (!@ mkdir ( $cacheDir , 0755, true)) { |
318 | if (! is_dir ( $cacheDir )) { |
319 | throw new CacheException( "Could not make cache directory" ); |
320 | } |
321 | } |
322 | } |
323 |
324 | // 设定缓存锁文件的访问和修改时间 |
325 | @touch( $cacheFile . '.lock' ); |
326 | return $this ; |
327 | } |
328 |
329 | /** |
330 | * 解锁 |
331 | * |
332 | * @param string $key |
333 | * @return Cache_File |
334 | */ |
335 | public function unlock( $key ) { |
336 | $cacheFile = self::_getCacheFile( $key ); |
337 | @unlink( $cacheFile . '.lock' ); |
338 | return $this ; |
339 | } |
340 |
341 | /** |
342 | * 设置文件缓存目录 |
343 | * @param string $dir |
344 | * @return Cache_File |
345 | */ |
346 | protected function _setCacheDir( $dir ) { |
347 | $this -> _cachesDir = rtrim( str_replace ( '\', ' / ', trim($dir)), ' /'); |
348 | clearstatcache(); |
349 | if (! is_dir ( $this -> _cachesDir)) { |
350 | mkdir ( $this -> _cachesDir, 0755, true); |
351 | } |
352 | // |
353 | return $this ; |
354 | } |
355 |
356 | /** |
357 | * 清空所有缓存 |
358 | * |
359 | * @return Cache_File |
360 | */ |
361 | public function clear() { |
362 | // 遍历目录清除缓存 |
363 | $cacheDir = $this -> _cachesDir; |
364 | $d = dir( $cacheDir ); |
365 | while (false !== ( $entry = $d -> read())) { |
366 | if ( '.' == $entry [0]) { |
367 | continue ; |
368 | } |
369 |
370 | $cacheEntry = $cacheDir . '/' . $entry ; |
371 | if ( is_file ( $cacheEntry )) { |
372 | @unlink( $cacheEntry ); |
373 | } elseif ( is_dir ( $cacheEntry )) { |
374 | // 缓存文件夹有两级 |
375 | $d2 = dir( $cacheEntry ); |
376 | while (false !== ( $entry = $d2 -> read())) { |
377 | if ( '.' == $entry [0]) { |
378 | continue ; |
379 | } |
380 |
381 | $cacheEntry .= '/' . $entry ; |
382 | if ( is_file ( $cacheEntry )) { |
383 | @unlink( $cacheEntry ); |
384 | } |
385 | } |
386 | $d2 -> close(); |
387 | } |
388 | } |
389 | $d -> close(); |
390 |
391 | return $this ; |
392 | } |
393 |
394 | } |
395 |
396 | /** |
397 | * 缓存单元的数据结构 |
398 | * array( |
399 | * 'time' => time(), // 缓存写入时的时间戳 |
400 | * 'expire' => $expire, // 缓存过期时间 |
401 | * 'valid' => true, // 缓存是否有效 |
402 | * 'data' => $value // 缓存的值 |
403 | * ); |
404 | */ |
405 | final class Cache { |
406 | /** |
407 | * 缓存过期时间长度(s) |
408 | * |
409 | * @var int |
410 | */ |
411 | private $_expire = 3600; |
412 | /** |
413 | * 缓存处理类 |
414 | * |
415 | * @var Cache_Abstract |
416 | */ |
417 | private $_storage = null; |
418 | /** |
419 | * @return Cache |
420 | */ |
421 | static public function createCache( $cacheClass = 'Cache_File' ) { |
422 | return new self( $cacheClass ); |
423 | } |
424 |
425 | private function __construct( $cacheClass ) { |
426 | $this -> _storage = new $cacheClass (); |
427 | } |
428 |
429 | /** |
430 | * 设置缓存 |
431 | * |
432 | * @param string $key |
433 | * @param mixed $value |
434 | * @param int $expire |
435 | */ |
436 | public function set( $key , $value , $expire = false) { |
437 | if (! $expire ) { |
438 | $expire = $this -> _expire; |
439 | } |
440 |
441 | $this -> _storage -> checkLock( $key ); |
442 |
443 | $data = array ( 'time' => time(), 'expire' => $expire , 'valid' => true, 'data' => $value ); |
444 | $this -> _storage -> lock( $key ); |
445 |
446 | try { |
447 | $this -> _storage -> store( $key , $data ); |
448 | $this -> _storage -> unlock( $key ); |
449 | } catch (CacheException $e ) { |
450 | $this -> _storage -> unlock( $key ); |
451 | throw $e ; |
452 | } |
453 | } |
454 |
455 | /** |
456 | * 读取缓存 |
457 | * |
458 | * @param string $key |
459 | * @return mixed |
460 | */ |
461 | public function get( $key ) { |
462 | $data = $this -> fetch( $key ); |
463 | if ( $data && $data [ 'valid' ] && ! $data [ 'isExpired' ]) { |
464 | return $data [ 'data' ]; |
465 | } |
466 |
467 | return false; |
468 | } |
469 |
470 | /** |
471 | * 读缓存,包括过期的和无效的,取得完整的存贮结构 |
472 | * |
473 | * @param string $key |
474 | */ |
475 | public function fetch( $key ) { |
476 | $this -> _storage -> checkLock( $key ); |
477 | $data = $this -> _storage -> fetch( $key ); |
478 | if ( $data ) { |
479 | $data [ 'isExpired' ] = (time() - $data [ 'time' ]) > $data [ 'expire' ] ? true : false; |
480 | return $data ; |
481 | } |
482 |
483 | return false; |
484 | } |
485 |
486 | /** |
487 | * 删除缓存 |
488 | * |
489 | * @param string $key |
490 | */ |
491 | public function delete ( $key ) { |
492 | $this -> _storage -> checkLock( $key ) -> lock( $key ) -> delete ( $key ) -> unlock( $key ); |
493 | } |
494 |
495 | public function clear() { |
496 | $this -> _storage -> clear(); |
497 | } |
498 |
499 | /** |
500 | * 把缓存设为无效 |
501 | * |
502 | * @param string $key |
503 | */ |
504 | public function setInvalidate( $key ) { |
505 | $this -> _storage -> checkLock( $key ) -> lock( $key ); |
506 | try { |
507 | $data = $this -> _storage -> fetch( $key ); |
508 | if ( $data ) { |
509 | $data [ 'valid' ] = false; |
510 | $this -> _storage -> store( $key , $data ); |
511 | } |
512 | $this -> _storage -> unlock( $key ); |
513 | } catch (CacheException $e ) { |
514 | $this -> _storage -> unlock( $key ); |
515 | throw $e ; |
516 | } |
517 | } |
518 |
519 | /** |
520 | * 设置缓存过期时间(s) |
521 | * |
522 | * @param int $expire |
523 | */ |
524 | public function setExpire( $expire ) { |
525 | $this -> _expire = (int) $expire ; |
526 | return $this ; |
527 | } |
528 |
529 | } |
相关文章
- php可以逆转的加密类 2012/10/30
- PHP获取指定IP地址的whois数据 2012/10/30
- php5中北京时间差8小时的解决办法 2012/10/30
- PHP计算两个时间相差的天/时/分/秒 2012/10/30
- PHP文件夹复制的函数 2012/10/30
- PHP生成缩略图的函数 2012/10/30
- php获取文件类型和文件信息 2012/10/30
- PHP将多维数组转为一维数组的函数 2012/10/30
- PHP实现的session数据库交互类 2012/10/30
- PHP获取客户端IP地址的函数 2012/10/30