-
Bug
-
Resolution: Fixed
-
Major
-
3.3.13, 3.3.14, 3.3.15, 3.3.16, 3.3.17, 3.3.18, 3.3.19
-
None
Since 3.3.13 (PHPBB-17358), phpbb\cache\driver\redis::_write() always sets an absolute expiry:
return $this->redis->set($var, $data, ['EXAT' => time() + $ttl]);
With PHPBB-17358 a TTL of 0 now means "expire immediately" (consistent with the file driver).
However, phpbb\cache\driver\memory::sql_save(), which is shared by the Redis driver, still
writes the per-table query index with a TTL of 0, expecting it to never expire:
// This must never expire
$this->write('sql' . $table_name, $temp, 0);
With Redis this becomes SET ... EXAT <current second>. Because that timestamp is already in the
past (sub-second), Redis replies OK but does not store the key. As a result, the
sql_<table_name> index keys never exist, and memory::destroy('sql', $table) finds no index and
deletes nothing. Cached query results (sql_<md5>) are only dropped when their own TTL runs out.
Impact: after any change that relies on destroy('sql', TABLE) for invalidation (styles, forums,
moderator cache, teampage, bbcodes, banlist, groups, smilies, extensions using the same pattern),
stale data keeps being served until the query cache TTL expires. That is up to 1 hour for several
core queries (e.g. user.php style query, functions_display.php moderators, memberlist.php
teampage) and 10 minutes for the jumpbox.
Steps to reproduce:
1. Configure $acm_type = 'phpbb\\cache\\driver
redis'.
2. Browse the board so cached queries are stored.
3. Run "redis-cli --scan --pattern '<prefix>sql_*'": only sql_<md5> keys exist and no
sql_<table_name> index keys are present.
4. Or run "redis-cli MONITOR" while a cached query is saved. It shows:
"SET" "<prefix>sql_phpbb_forums" "..." "EXAT" "1790591323"
issued at 1790591323.53, so the key is discarded on write.
5. Change something in the ACP whose queries are cached with a TTL (e.g. forum/moderator data):
the old result is still served until the TTL expires.
Expected: the per-table index keys persist (at least as long as the cached queries they
reference), so destroy('sql', $table) invalidates those queries immediately.
Actual: the index keys are never stored and per-table invalidation is a no-op on Redis.
Environment: phpBB 3.3.17, Redis 7.0.15, phpredis 6.3.0, PHP 8.3. The same _write() code is
present on the current 3.3.x and master branches.
Suggested fix: do not use 0 for the index in memory::sql_save(). Write it with a long TTL, e.g.
the default:
$this->write('sql' . $table_name, $temp);
Alternatively, keep a dedicated "no expiry" path for these keys in the Redis driver. Treating
ttl <= 0 as "no expiry" in redis::_write() would also work, but it reverts the semantics
introduced by PHPBB-17358.
Related: PHPBB-17358, PHPBB-15320.

