156 lines
4.1 KiB
PHP
156 lines
4.1 KiB
PHP
<?php
|
|
/**
|
|
* 文件缓存系统
|
|
*
|
|
* 将数据序列化后写入 storage/cache/ 目录。
|
|
* 支持设置 TTL(过期时间)、标签清除、全局清除。
|
|
*
|
|
* 用法:
|
|
* Cache::put('user_123', $data, 3600); // 缓存 1 小时
|
|
* $data = Cache::get('user_123'); // 读取(过期返回 null)
|
|
* Cache::forget('user_123'); // 删除单个
|
|
* Cache::clear(); // 清除全部
|
|
*/
|
|
if (!defined('IN_APP')) exit('Forbidden');
|
|
|
|
class Cache
|
|
{
|
|
/** @var string 缓存目录 */
|
|
private static $dir;
|
|
|
|
/** @var bool 是否启用 */
|
|
private static $enabled = true;
|
|
|
|
/** @var string 缓存文件扩展名 */
|
|
const EXT = '.cache';
|
|
|
|
/**
|
|
* 初始化缓存系统。
|
|
* @param string $dir 缓存目录路径
|
|
* @param bool $enabled 是否启用
|
|
*/
|
|
public static function init($dir, $enabled = true)
|
|
{
|
|
self::$dir = rtrim($dir, '/\\');
|
|
self::$enabled = $enabled;
|
|
if (!is_dir(self::$dir)) {
|
|
@mkdir(self::$dir, 0755, true);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 写入缓存。
|
|
* @param string $key 缓存键
|
|
* @param mixed $value 值(任意可序列化类型)
|
|
* @param int $ttl 有效期(秒),0=永不过期
|
|
* @return bool
|
|
*/
|
|
public static function put($key, $value, $ttl = 3600)
|
|
{
|
|
if (!self::$enabled) return false;
|
|
$file = self::fileName($key);
|
|
$data = [
|
|
'expires' => $ttl > 0 ? time() + $ttl : 0,
|
|
'created' => time(),
|
|
'value' => $value,
|
|
];
|
|
$content = serialize($data);
|
|
return (bool)@file_put_contents($file, $content, LOCK_EX);
|
|
}
|
|
|
|
/**
|
|
* 读取缓存。过期或不存在返回默认值。
|
|
* @param string $key
|
|
* @param mixed $default 不存在时的默认值
|
|
* @return mixed
|
|
*/
|
|
public static function get($key, $default = null)
|
|
{
|
|
if (!self::$enabled) return $default;
|
|
$file = self::fileName($key);
|
|
if (!file_exists($file)) return $default;
|
|
|
|
$content = @file_get_contents($file);
|
|
if ($content === false) return $default;
|
|
|
|
$data = @unserialize($content);
|
|
if (!is_array($data)) {
|
|
@unlink($file);
|
|
return $default;
|
|
}
|
|
|
|
// 检查过期
|
|
if ($data['expires'] > 0 && time() > $data['expires']) {
|
|
@unlink($file);
|
|
return $default;
|
|
}
|
|
|
|
return $data['value'];
|
|
}
|
|
|
|
/**
|
|
* 检查缓存是否存在且未过期。
|
|
*/
|
|
public static function has($key)
|
|
{
|
|
return self::get($key, '__NOT_FOUND__') !== '__NOT_FOUND__';
|
|
}
|
|
|
|
/**
|
|
* 删除单个缓存。
|
|
*/
|
|
public static function forget($key)
|
|
{
|
|
$file = self::fileName($key);
|
|
if (file_exists($file)) {
|
|
return @unlink($file);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 清除所有缓存。
|
|
*/
|
|
public static function clear()
|
|
{
|
|
if (!is_dir(self::$dir)) return;
|
|
$files = glob(self::$dir . DIRECTORY_SEPARATOR . '*' . self::EXT);
|
|
foreach ($files as $f) {
|
|
@unlink($f);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 带回掉的缓存读取(缓存命中直接返回,未命中执行回调并缓存)。
|
|
* @param string $key
|
|
* @param int $ttl
|
|
* @param callable $callback 无参回调,返回要缓存的值
|
|
* @return mixed
|
|
*/
|
|
public static function remember($key, $ttl, callable $callback)
|
|
{
|
|
$value = self::get($key, null);
|
|
if ($value !== null) return $value;
|
|
|
|
$value = $callback();
|
|
self::put($key, $value, $ttl);
|
|
return $value;
|
|
}
|
|
|
|
/**
|
|
* 获取或设置(简化版 remember)。
|
|
*/
|
|
public static function getOrSet($key, $ttl, callable $callback)
|
|
{
|
|
return self::remember($key, $ttl, $callback);
|
|
}
|
|
|
|
// ─── 内部 ───
|
|
|
|
private static function fileName($key)
|
|
{
|
|
// 用 md5 确保文件名安全
|
|
return self::$dir . DIRECTORY_SEPARATOR . md5($key) . self::EXT;
|
|
}
|
|
}
|