false, 'data' => null, 'updated_at' => 0, 'stale' => true]; if ($personId <= 0 || $key === '') { return $miss; } $db = Database::get(); try { $st = $db->prepare( 'SELECT v, UNIX_TIMESTAMP(updated_at) AS ts FROM weread_snapshots WHERE person_id = ? AND k = ?' ); $st->execute([$personId, $key]); $row = $st->fetch(); } catch (\Throwable $e) { // 表还没建(升级中)→ 当作"没有快照",绝不让缓存层把页面打挂 return $miss; } if (!$row) { return $miss; } $ts = (int)($row['ts'] ?? 0); $stale = (time() - $ts) > WeRead::SNAP_TTL; if ($freshOnly && $stale) { return $miss; } $data = json_decode((string)($row['v'] ?? ''), true); return ['ok' => true, 'data' => $data, 'updated_at' => $ts, 'stale' => $stale]; } /** 写一份快照(覆盖旧的)。失败静默 —— 缓存写不进去不该影响功能。 */ public static function put(int $personId, string $key, $data): void { if ($personId <= 0 || $key === '') { return; } $json = json_encode($data, JSON_UNESCAPED_UNICODE); if ($json === false) { return; } try { $db = Database::get(); $st = $db->prepare( 'INSERT INTO weread_snapshots (person_id, k, v, updated_at) VALUES (?, ?, ?, NOW()) ON DUPLICATE KEY UPDATE v = VALUES(v), updated_at = VALUES(updated_at)' ); $st->execute([$personId, $key, $json]); } catch (\Throwable $e) { // 静默(缓存是加速手段,不是功能本体) } } /** 最后一次落盘是什么时候(页面上显示"数据更新于 …") */ public static function updatedAt(int $personId, string $key): int { return (int)self::get($personId, $key)['updated_at']; } /** 这个人有没有**任何**快照(判断"是不是第一次用") */ public static function hasAny(int $personId): bool { if ($personId <= 0) { return false; } try { $st = Database::get()->prepare( 'SELECT COUNT(*) FROM weread_snapshots WHERE person_id = ?' ); $st->execute([$personId]); return (int)$st->fetchColumn() > 0; } catch (\Throwable $e) { return false; } } /** 清掉一个人的全部快照(换 Key / 停用自动同步时用) */ public static function forget(int $personId): void { if ($personId <= 0) { return; } try { Database::get()->prepare('DELETE FROM weread_snapshots WHERE person_id = ?') ->execute([$personId]); } catch (\Throwable $e) { } } }