109 lines
3.5 KiB
PHP
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;
|
|
}
|