Cache 類別完整代碼
<?php
class Cache {
public $config = array(
'cacheRoot' => './cache/', // 快取根目錄,結尾需加 /
'cacheTime' => 1, // 快取秒數,0=不快取,負數=永久
'cacheType' => 2, // 1=serialize,2=var_export
'cacheExe' => '.php' // 快取檔副檔名
);
private $return_name = array();
public function __construct($cache_set = array()) {
if (!empty($cache_set)) $this->config = array_merge($this->config, $cache_set);
$this->config['ClassName'] = __CLASS__;
}
// 清除快取
public function clear($filename = '') {
if (empty($filename)) {
$this->clear_dir($this->config['cacheRoot']);
} elseif (file_exists($this->cache_file($filename))) {
@unlink($this->cache_file($filename));
} else {
$this->clear_dir($this->config['cacheRoot'] . $filename);
}
}
private function clear_dir($dir, $to = false) {
if ($list = glob($dir . '/*')) {
foreach ($list as $file) {
is_dir($file) ? $this->clear_dir($file) : unlink($file);
}
}
if ($to === false) @rmdir($dir);
}
// 寫入快取檔
private function cache_write($filename, $text, $mode = 'w') {
if (!file_exists($filename)) $this->makeDir(dirname($filename));
if ($fp = @fopen($filename, $mode)) {
flock($fp, LOCK_EX);
fwrite($fp, $text);
fclose($fp);
return true;
}
return false;
}
// 檢查快取是否有效
public function cache_is($fileName) {
$fileName = $this->cache_file($fileName);
if (!file_exists($fileName)) return false;
if ($this->config['cacheTime'] < 0) return true; // 永久
if ($this->config['cacheTime'] == 0) return false; // 不快取
$ctime = filemtime($fileName);
return (time() - $ctime <= $this->config['cacheTime']);
}
// 存入資料並返回原資料
public function cache_data($name, $data) {
$varname = $name;
$name = $this->cache_file($name);
if ($this->config['cacheTime'] != 0) {
if ($this->config['cacheType'] == 1) {
$write_data = "<?php exit;?>" . serialize($data);
} else {
$write_data = "<?php\r\n\$var = " . var_export($data, true) . ";\r\n?>";
}
$this->cache_write($name, $write_data);
}
return $data;
}
// 讀取快取
public function cache_read($file) {
$file = $this->cache_file($file);
if (!file_exists($file)) return '';
if ($this->config['cacheType'] == 1) {
$content = file_get_contents($file);
$content = substr($content, 13); // 移除
return unserialize($content);
} else {
include_once($file);
return $var;
}
}
private function cache_file($filename) {
return $this->config['cacheRoot'] . $filename . $this->config['cacheExe'];
}
// 遞歸建立目錄
private function makeDir($dir, $mode = 0777) {
$dir = str_replace('\\', '/', $dir);
$mdir = '';
foreach (explode('/', $dir) as $val) {
$mdir .= $val . '/';
if ($val == '..' || $val == '.' || $val == '') continue;
if (!file_exists($mdir)) @mkdir($mdir, $mode);
}
return true;
}
}
使用範例
$cache = new Cache(array('cacheTime' => 300, 'cacheType' => 2)); // 5 分鐘快取,var_export 模式
if ($cache->cache_is('user_list')) {
$users = $cache->cache_read('user_list');
} else {
$users = getUsersFromDB(); // 耗時操作
$cache->cache_data('user_list', $users);
}
兩種儲存模式差異
| 模式 | cacheType | 優點 | 缺點 |
| 序列化 | 1 | 支援所有資料型別、物件、資源 | 較大、需 unserialize 解析 |
| var_export | 2 | 輸出合法 PHP 代碼、include 直接執行、可讀性高 | 不支援資源型別、遞歸參考會截斷 |
安全性設計
- 快取檔開頭
<?php exit;?> 防止直接訪問洩露資料
flock(LOCK_EX) 防止併發寫入衝突
- 目錄可寫權限控制(建議 0755)