connect('127.0.0.1', 6379, 0.15);
// Optional auth: $redis->auth('yourpass');
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_NONE);
}
} catch (Throwable $e) {
$redis = null; // Fail open with no cache
}
})();
function cache_get(string $key): ?string {
global $redis;
if (!$redis) return null;
try { return $redis->get($key) ?: null; } catch (Throwable $e) { return null; }
}
function cache_set(string $key, string $val, int $ttl): void {
global $redis;
if (!$redis) return;
try { $ttl > 0 ? $redis->setex($key, $ttl, $val) : $redis->set($key, $val); } catch (Throwable $e) {}
}
/*
* ---------------------------
* Input handling
* ---------------------------
*/
$roundParam = $_GET['round'] ?? '0';
$modeParam = $_GET['mode'] ?? '';
$gidParam = $_GET['gid'] ?? '';
$roundNumber = (int)preg_replace('/\D+/', '', (string)$roundParam);
$mode = is_string($modeParam) ? $modeParam : '';
// Base64 GID can be large; decode safely
$groupID = '';
if ($gidParam !== '') {
$decoded = base64_decode((string)$gidParam, true);
if ($decoded !== false) {
$groupID = sanitize_string($decoded);
}
}
if ($roundNumber === 0) {
$algoURL = WW_FOLDER_PATH . 'algorand/';
redirectAndDieTo($algoURL);
}
/*
* ---------------------------
* Data fetch with caching
* ---------------------------
*
* Strategy:
* - Rounds are immutable, so cache forever for older rounds.
* - For very recent rounds (age < 60s), use a short TTL.
* - Optional nocache=1 will bypass cache for debugging.
*/
$nocache = isset($_GET['nocache']) && $_GET['nocache'] !== '0';
$cachePrefix = 'ag:round:v2:' . (defined('WW_CHAINNAME') ? WW_CHAINNAME : 'algo') . ':';
$roundKey = $cachePrefix . $roundNumber . ':json';
$roundData = null;
$roundJson = null;
if (!$nocache && ($roundJson = cache_get($roundKey))) {
$roundData = json_decode($roundJson);
}
if ($roundData === null) {
// This function presumably calls the Indexer/Node.
// Make sure inside it you set low timeouts and disable HTTP exceptions.
$roundData = getAlgorandRound($roundNumber);
// Cache only if we got a valid response object with minimal shape
if ($roundData && is_object($roundData)) {
// If timestamp is present, decide TTL from age; else default
$ts = isset($roundData->timestamp) ? (int)$roundData->timestamp : 0;
$age = $ts > 0 ? (time() - $ts) : 999999;
// Fresh round: tiny TTL (10s). Otherwise “forever-ish” (1 year)
$ttl = ($age >= 60) ? 31536000 : 10;
cache_set($roundKey, json_encode($roundData, JSON_UNESCAPED_SLASHES), $ttl);
}
}
/*
* ---------------------------
* Group filter (in-PHP, cheap)
* ---------------------------
*/
$transactionList = [];
if ($roundData && isset($roundData->transactions) && is_array($roundData->transactions)) {
$transactionList = $roundData->transactions;
if ($groupID !== '' && str_contains($mode, 'group')) {
$gid = $groupID; // closure capture
// Filtering is CPU-cheap; safe to do per request.
$transactionList = array_values(array_filter(
$transactionList,
static fn($obj) => is_object($obj) && isset($obj->group) && $obj->group === $gid
));
}
}
/*
* ---------------------------
* Smart HTTP caching headers
* ---------------------------
*
* Immutable for old rounds ⇒ let CDN/browser cache.
* Recent rounds ⇒ short max-age. 304 handling for free CPU savings.
*/
$isFound = (bool)$roundData;
$roundTs = ($isFound && isset($roundData->timestamp)) ? (int)$roundData->timestamp : 0;
$age = $roundTs ? max(0, time() - $roundTs) : 999999;
$isFresh = ($age < 60);
// If client provides If-Modified-Since and this is old, honor 304
if ($roundTs > 0) {
$lastMod = gmdate('D, d M Y H:i:s', $roundTs) . ' GMT';
header('Last-Modified: ' . $lastMod);
if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
$ims = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
if ($ims !== false && $ims >= $roundTs && !$nocache) {
header('Cache-Control: public, max-age=31536000, immutable, stale-while-revalidate=30, stale-if-error=86400');
http_response_code(304);
exit;
}
}
}
// Cache policy
if ($nocache) {
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Pragma: no-cache');
} else {
if ($isFresh) {
header('Cache-Control: public, max-age=10, stale-while-revalidate=30, stale-if-error=86400');
} else {
header('Cache-Control: public, max-age=31536000, immutable, stale-while-revalidate=30, stale-if-error=86400');
}
}
/*
* ---------------------------
* HTML output (avoid flush)
* ---------------------------
*
* Avoiding flush() keeps the FPM worker from sitting on a socket,
* which can reduce run-queue pressure under load.
*/
?>
= WW_CHAINNAME ?> Round = htmlspecialchars((string)$roundNumber, ENT_QUOTES) ?> Details - = WW_APPNAME ?>
Algorand Round = displayRoundNumber($roundNumber) ?>
Displaying Transactions from Group ID: = htmlspecialchars($groupID, ENT_QUOTES) ?>
Connect a wallet or enter a search to continue...