|
|
@@ -13,10 +13,61 @@ namespace BCJD;
|
|
|
class LinkManager
|
|
|
{
|
|
|
private Database $db;
|
|
|
+ private string $cacheDir;
|
|
|
+ private int $cacheTtl = 60; // 缓存有效期(秒)
|
|
|
|
|
|
public function __construct()
|
|
|
{
|
|
|
$this->db = Database::instance();
|
|
|
+ $this->cacheDir = __DIR__ . '/../cache';
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取缓存文件路径
|
|
|
+ */
|
|
|
+ private function cachePath(string $key): string
|
|
|
+ {
|
|
|
+ return $this->cacheDir . '/links_' . md5($key) . '.json';
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 读取缓存
|
|
|
+ */
|
|
|
+ private function cacheGet(string $key): ?array
|
|
|
+ {
|
|
|
+ $path = $this->cachePath($key);
|
|
|
+ if (!file_exists($path)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (time() - filemtime($path) > $this->cacheTtl) {
|
|
|
+ @unlink($path);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ $data = @file_get_contents($path);
|
|
|
+ if ($data === false) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ $decoded = json_decode($data, true);
|
|
|
+ return is_array($decoded) ? $decoded : null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 写入缓存
|
|
|
+ */
|
|
|
+ private function cacheSet(string $key, array $data): void
|
|
|
+ {
|
|
|
+ $path = $this->cachePath($key);
|
|
|
+ @file_put_contents($path, json_encode($data, JSON_UNESCAPED_UNICODE), LOCK_EX);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 清除所有链接缓存
|
|
|
+ */
|
|
|
+ private function clearCache(): void
|
|
|
+ {
|
|
|
+ foreach (glob($this->cacheDir . '/links_*.json') as $file) {
|
|
|
+ @unlink($file);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -25,6 +76,13 @@ class LinkManager
|
|
|
public function getLinks(): array
|
|
|
{
|
|
|
$isLoggedIn = Auth::isLoggedIn();
|
|
|
+ $cacheKey = $isLoggedIn ? 'auth' : 'guest';
|
|
|
+
|
|
|
+ // 尝试读取缓存
|
|
|
+ $cached = $this->cacheGet($cacheKey);
|
|
|
+ if ($cached !== null) {
|
|
|
+ return $cached;
|
|
|
+ }
|
|
|
|
|
|
if ($isLoggedIn) {
|
|
|
$rows = $this->db->fetchAll(
|
|
|
@@ -36,7 +94,12 @@ class LinkManager
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- return $this->groupLinks($rows);
|
|
|
+ $result = $this->groupLinks($rows);
|
|
|
+
|
|
|
+ // 写入缓存
|
|
|
+ $this->cacheSet($cacheKey, $result);
|
|
|
+
|
|
|
+ return $result;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -85,14 +148,16 @@ class LinkManager
|
|
|
|
|
|
$this->db->execute(
|
|
|
"INSERT INTO links
|
|
|
- (title, url, description, icon_svg, group_name, keywords, tag_label, tag_class, meta_domain, is_private, sort_order)
|
|
|
- VALUES (:title, :url, :description, :icon_svg, :group_name, :keywords, :tag_label, :tag_class, :meta_domain, :is_private, :sort_order)",
|
|
|
+ (title, url, description, icon_svg, group_name, group_label, group_hint, keywords, tag_label, tag_class, meta_domain, is_private, sort_order)
|
|
|
+ VALUES (:title, :url, :description, :icon_svg, :group_name, :group_label, :group_hint, :keywords, :tag_label, :tag_class, :meta_domain, :is_private, :sort_order)",
|
|
|
[
|
|
|
'title' => $title,
|
|
|
'url' => $url,
|
|
|
'description' => Validator::truncate($data['description'] ?? '', 255),
|
|
|
'icon_svg' => Validator::sanitizeSvg($data['icon_svg'] ?? ''),
|
|
|
'group_name' => Validator::validateGroupName($data['group_name'] ?? 'default'),
|
|
|
+ 'group_label' => Validator::truncate($data['group_label'] ?? '', 50),
|
|
|
+ 'group_hint' => Validator::truncate($data['group_hint'] ?? '', 100),
|
|
|
'keywords' => Validator::sanitizeKeywords($data['keywords'] ?? ''),
|
|
|
'tag_label' => Validator::truncate($data['tag_label'] ?? '', 30),
|
|
|
'tag_class' => Validator::validateTagClass($data['tag_class'] ?? ''),
|
|
|
@@ -102,6 +167,8 @@ class LinkManager
|
|
|
]
|
|
|
);
|
|
|
|
|
|
+ $this->clearCache();
|
|
|
+
|
|
|
return (int)$this->db->lastInsertId();
|
|
|
}
|
|
|
|
|
|
@@ -124,6 +191,8 @@ class LinkManager
|
|
|
if ($affected === 0) {
|
|
|
Response::error('链接不存在', 404);
|
|
|
}
|
|
|
+
|
|
|
+ $this->clearCache();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -144,6 +213,8 @@ class LinkManager
|
|
|
'description' => fn($v) => Validator::truncate($v, 255),
|
|
|
'icon_svg' => fn($v) => Validator::sanitizeSvg($v ?? ''),
|
|
|
'group_name' => fn($v) => Validator::validateGroupName($v ?? 'default'),
|
|
|
+ 'group_label' => fn($v) => Validator::truncate($v ?? '', 50),
|
|
|
+ 'group_hint' => fn($v) => Validator::truncate($v ?? '', 100),
|
|
|
'keywords' => fn($v) => Validator::sanitizeKeywords($v ?? ''),
|
|
|
'tag_label' => fn($v) => Validator::truncate($v ?? '', 30),
|
|
|
'tag_class' => fn($v) => Validator::validateTagClass($v ?? ''),
|
|
|
@@ -167,6 +238,8 @@ class LinkManager
|
|
|
|
|
|
$sql = "UPDATE links SET " . implode(', ', $updates) . " WHERE id = :id";
|
|
|
$this->db->execute($sql, $params);
|
|
|
+
|
|
|
+ $this->clearCache();
|
|
|
}
|
|
|
|
|
|
/**
|