Files
kefu/im/server-fix-20260901/XxiawListPageCache.php
T
2026-09-03 08:38:17 +08:00

109 lines
3.5 KiB
PHP

<?php
/**
* Small response cache for the public app_games list pages.
* Login state is loaded by the existing AJAX endpoint after this HTML is shown.
*/
function xxiaw_list_cache_page_number($server)
{
if (!isset($server['REQUEST_METHOD']) || strtoupper($server['REQUEST_METHOD']) !== 'GET') {
return false;
}
$requestUri = isset($server['REQUEST_URI']) ? $server['REQUEST_URI'] : '';
// Nginx adds the ThinkPHP route to QUERY_STRING during its internal rewrite.
// REQUEST_URI keeps the browser's original URI, so use it to detect real args.
if (strpos($requestUri, '?') !== false) {
return false;
}
$path = parse_url($requestUri, PHP_URL_PATH);
if (!is_string($path) || !preg_match('#^/app_games/index([1-9][0-9]*)[.]html$#D', rawurldecode($path), $matches)) {
return false;
}
return intval($matches[1]);
}
function xxiaw_list_cache_serve($file, $state)
{
$html = @file_get_contents($file);
if ($html === false) {
return false;
}
header('Content-Type: text/html; charset=UTF-8');
header('X-Xxiaw-List-Cache: ' . $state);
echo $html;
return true;
}
function xxiaw_list_cache_bootstrap()
{
if (PHP_SAPI === 'cli') {
return false;
}
$page = xxiaw_list_cache_page_number($_SERVER);
if ($page === false) {
return false;
}
$ttl = 60;
$staleTtl = 300;
$cacheDir = dirname(__DIR__) . '/Runtime/XxiawListPageCache';
if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0750, true) && !is_dir($cacheDir)) {
return false;
}
$cacheFile = $cacheDir . '/app-games-page-' . $page . '.html';
clearstatcache(true, $cacheFile);
$modified = @filemtime($cacheFile);
if ($modified !== false && $modified >= time() - $ttl && @filesize($cacheFile) > 1000) {
if (xxiaw_list_cache_serve($cacheFile, 'HIT')) {
exit;
}
}
$lock = @fopen($cacheFile . '.lock', 'c');
if ($lock === false) {
return false;
}
if (!@flock($lock, LOCK_EX | LOCK_NB)) {
if ($modified !== false && $modified >= time() - $staleTtl && @filesize($cacheFile) > 1000) {
@fclose($lock);
if (xxiaw_list_cache_serve($cacheFile, 'STALE')) {
exit;
}
}
$deadline = microtime(true) + 0.20;
do {
usleep(20000);
clearstatcache(true, $cacheFile);
if (@filemtime($cacheFile) >= time() - $ttl && @filesize($cacheFile) > 1000) {
@fclose($lock);
if (xxiaw_list_cache_serve($cacheFile, 'HIT')) {
exit;
}
}
} while (microtime(true) < $deadline);
@fclose($lock);
return false;
}
header('X-Xxiaw-List-Cache: MISS');
ob_start(function ($html) use ($cacheDir, $cacheFile, $lock) {
$status = http_response_code();
if (($status === false || $status < 400) && strlen($html) > 1000 && strpos($html, 'class="jshwarticle"') !== false) {
$temporary = @tempnam($cacheDir, '.list-cache-');
if ($temporary !== false) {
if (@file_put_contents($temporary, $html, LOCK_EX) !== false) {
@chmod($temporary, 0640);
@rename($temporary, $cacheFile);
}
if (is_file($temporary)) {
@unlink($temporary);
}
}
}
@flock($lock, LOCK_UN);
@fclose($lock);
return $html;
});
return true;
}