diff --git a/phpBB/phpbb/cache/driver/base.php b/phpBB/phpbb/cache/driver/base.php index 29352e84b3..a93e6ce08c 100644 --- a/phpBB/phpbb/cache/driver/base.php +++ b/phpBB/phpbb/cache/driver/base.php @@ -115,6 +115,7 @@ abstract class base implements \phpbb\cache\driver\driver_interface */ function sql_exists($query_id) { + $query_id = $this->clean_query_id($query_id); return isset($this->sql_rowset[$query_id]); } @@ -123,6 +124,7 @@ abstract class base implements \phpbb\cache\driver\driver_interface */ function sql_fetchrow($query_id) { + $query_id = $this->clean_query_id($query_id); if ($this->sql_row_pointer[$query_id] < count($this->sql_rowset[$query_id])) { return $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++]; @@ -136,6 +138,7 @@ abstract class base implements \phpbb\cache\driver\driver_interface */ function sql_fetchfield($query_id, $field) { + $query_id = $this->clean_query_id($query_id); if ($this->sql_row_pointer[$query_id] < count($this->sql_rowset[$query_id])) { return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++][$field] : false; @@ -149,6 +152,7 @@ abstract class base implements \phpbb\cache\driver\driver_interface */ function sql_rowseek($rownum, $query_id) { + $query_id = $this->clean_query_id($query_id); if ($rownum >= count($this->sql_rowset[$query_id])) { return false; @@ -163,6 +167,7 @@ abstract class base implements \phpbb\cache\driver\driver_interface */ function sql_freeresult($query_id) { + $query_id = $this->clean_query_id($query_id); if (!isset($this->sql_rowset[$query_id])) { return false; @@ -240,4 +245,21 @@ abstract class base implements \phpbb\cache\driver\driver_interface * @return mixed Cached data */ abstract protected function _read(string $var); + + /** + * {@inheritDoc} + */ + public function clean_query_id($query_id) + { + // Some DBMS functions accept/return objects and/or resources instead of integer identifier + // Attempting to cast object to int will throw error, hence correctly handle all cases + if (is_resource($query_id)) + { + return function_exists('get_resource_id') ? get_resource_id($query_id) : (int) $query_id; + } + else + { + return is_object($query_id) ? spl_object_id($query_id) : $query_id; + } + } } diff --git a/phpBB/phpbb/cache/driver/driver_interface.php b/phpBB/phpbb/cache/driver/driver_interface.php index 61ce39d496..f8d3c307e0 100644 --- a/phpBB/phpbb/cache/driver/driver_interface.php +++ b/phpBB/phpbb/cache/driver/driver_interface.php @@ -164,4 +164,13 @@ interface driver_interface * @return bool */ public function sql_freeresult($query_id); + + /** + * Ensure query ID can be used by cache + * + * @param object|resource|int|string $query_id Mixed type query id + * + * @return int|string Query id in string or integer format + */ + public function clean_query_id($query_id); } diff --git a/phpBB/phpbb/db/driver/driver.php b/phpBB/phpbb/db/driver/driver.php index 3a1cd8c27b..c924d4626a 100644 --- a/phpBB/phpbb/db/driver/driver.php +++ b/phpBB/phpbb/db/driver/driver.php @@ -1331,4 +1331,21 @@ abstract class driver implements driver_interface return $rows_total; } + + /** + * {@inheritDoc} + */ + public function clean_query_id($query_id) + { + // Some DBMS functions accept/return objects and/or resources instead if identifiers + // Attempting to use objects/resources as array keys will throw error, hence correctly handle all cases + if (is_resource($query_id)) + { + return function_exists('get_resource_id') ? get_resource_id($query_id) : (int) $query_id; + } + else + { + return is_object($query_id) ? spl_object_id($query_id) : $query_id; + } + } } diff --git a/phpBB/phpbb/db/driver/driver_interface.php b/phpBB/phpbb/db/driver/driver_interface.php index e781cbd122..e85e0d19a8 100644 --- a/phpBB/phpbb/db/driver/driver_interface.php +++ b/phpBB/phpbb/db/driver/driver_interface.php @@ -495,4 +495,13 @@ interface driver_interface * @return string Quoted version of $msg */ public function sql_quote($msg); + + /** + * Ensure query ID can be used by cache + * + * @param resource|int|string $query_id Mixed type query id + * + * @return int|string Query id in string or integer format + */ + public function clean_query_id($query_id); } diff --git a/phpBB/phpbb/db/driver/factory.php b/phpBB/phpbb/db/driver/factory.php index 5e65b9218f..a5adae6a90 100644 --- a/phpBB/phpbb/db/driver/factory.php +++ b/phpBB/phpbb/db/driver/factory.php @@ -474,4 +474,12 @@ class factory implements driver_interface { return $this->get_driver()->sql_quote($msg); } + + /** + * {@inheritDoc} + */ + public function clean_query_id($query_id) + { + return $this->get_driver()->clean_query_id($query_id); + } } diff --git a/phpBB/phpbb/db/driver/mssql_odbc.php b/phpBB/phpbb/db/driver/mssql_odbc.php index f0528ec74a..9b91aa8e0e 100644 --- a/phpBB/phpbb/db/driver/mssql_odbc.php +++ b/phpBB/phpbb/db/driver/mssql_odbc.php @@ -180,14 +180,16 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base return false; } + $safe_query_id = $this->clean_query_id($this->query_result); + if ($cache && $cache_ttl) { - $this->open_queries[(int) $this->query_result] = $this->query_result; + $this->open_queries[$safe_query_id] = $this->query_result; $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0) { - $this->open_queries[(int) $this->query_result] = $this->query_result; + $this->open_queries[$safe_query_id] = $this->query_result; } } else if ($this->debug_sql_explain) @@ -255,9 +257,10 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base $query_id = $this->query_result; } - if ($cache && $cache->sql_exists($query_id)) + $safe_query_id = $this->clean_query_id($query_id); + if ($cache && $cache->sql_exists($safe_query_id)) { - return $cache->sql_fetchrow($query_id); + return $cache->sql_fetchrow($safe_query_id); } return ($query_id) ? odbc_fetch_array($query_id) : false; @@ -296,13 +299,14 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base $query_id = $this->query_result; } - if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) + $safe_query_id = $this->clean_query_id($query_id); + if ($cache && $cache->sql_exists($safe_query_id)) { - $cache->sql_freeresult($query_id); + $cache->sql_freeresult($safe_query_id); } - else if (isset($this->open_queries[(int) $query_id])) + else if (isset($this->open_queries[$safe_query_id])) { - unset($this->open_queries[(int) $query_id]); + unset($this->open_queries[$safe_query_id]); odbc_free_result($query_id); } } diff --git a/phpBB/phpbb/db/driver/mssqlnative.php b/phpBB/phpbb/db/driver/mssqlnative.php index f329e6d200..8f52e0e39a 100644 --- a/phpBB/phpbb/db/driver/mssqlnative.php +++ b/phpBB/phpbb/db/driver/mssqlnative.php @@ -157,14 +157,16 @@ class mssqlnative extends \phpbb\db\driver\mssql_base return false; } + $safe_query_id = $this->clean_query_id($this->query_result); + if ($cache && $cache_ttl) { - $this->open_queries[(int) $this->query_result] = $this->query_result; + $this->open_queries[$safe_query_id] = $this->query_result; $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0) { - $this->open_queries[(int) $this->query_result] = $this->query_result; + $this->open_queries[$safe_query_id] = $this->query_result; } } else if ($this->debug_sql_explain) @@ -240,9 +242,10 @@ class mssqlnative extends \phpbb\db\driver\mssql_base $query_id = $this->query_result; } - if ($cache && $cache->sql_exists($query_id)) + $safe_query_id = $this->clean_query_id($query_id); + if ($cache && $cache->sql_exists($safe_query_id)) { - return $cache->sql_fetchrow($query_id); + return $cache->sql_fetchrow($safe_query_id); } if (!$query_id) @@ -300,13 +303,14 @@ class mssqlnative extends \phpbb\db\driver\mssql_base $query_id = $this->query_result; } - if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) + $safe_query_id = $this->clean_query_id($query_id); + if ($cache && $cache->sql_exists($safe_query_id)) { - $cache->sql_freeresult($query_id); + $cache->sql_freeresult($safe_query_id); } - else if (isset($this->open_queries[(int) $query_id])) + else if (isset($this->open_queries[$safe_query_id])) { - unset($this->open_queries[(int) $query_id]); + unset($this->open_queries[$safe_query_id]); sqlsrv_free_stmt($query_id); } } diff --git a/phpBB/phpbb/db/driver/mysqli.php b/phpBB/phpbb/db/driver/mysqli.php index 54ff684cf9..38e7f959b1 100644 --- a/phpBB/phpbb/db/driver/mysqli.php +++ b/phpBB/phpbb/db/driver/mysqli.php @@ -250,9 +250,10 @@ class mysqli extends \phpbb\db\driver\mysql_base $query_id = $this->query_result; } - if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) + $safe_query_id = $this->clean_query_id($query_id); + if ($cache && $cache->sql_exists($safe_query_id)) { - return $cache->sql_fetchrow($query_id); + return $cache->sql_fetchrow($safe_query_id); } if ($query_id) @@ -276,9 +277,10 @@ class mysqli extends \phpbb\db\driver\mysql_base $query_id = $this->query_result; } - if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) + $safe_query_id = $this->clean_query_id($query_id); + if ($cache && $cache->sql_exists($safe_query_id)) { - return $cache->sql_rowseek($rownum, $query_id); + return $cache->sql_rowseek($rownum, $safe_query_id); } return ($query_id) ? @mysqli_data_seek($query_id, $rownum) : false; @@ -304,9 +306,10 @@ class mysqli extends \phpbb\db\driver\mysql_base $query_id = $this->query_result; } - if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) + $safe_query_id = $this->clean_query_id($query_id); + if ($cache && $cache->sql_exists($safe_query_id)) { - $cache->sql_freeresult($query_id); + $cache->sql_freeresult($safe_query_id); } else if ($query_id && $query_id !== true) { diff --git a/phpBB/phpbb/db/driver/oracle.php b/phpBB/phpbb/db/driver/oracle.php index 3457ddf2f1..9e2f1c9d2c 100644 --- a/phpBB/phpbb/db/driver/oracle.php +++ b/phpBB/phpbb/db/driver/oracle.php @@ -439,14 +439,16 @@ class oracle extends \phpbb\db\driver\driver return false; } + $safe_query_id = $this->clean_query_id($this->query_result); + if ($cache && $cache_ttl) { - $this->open_queries[(int) $this->query_result] = $this->query_result; + $this->open_queries[$safe_query_id] = $this->query_result; $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0) { - $this->open_queries[(int) $this->query_result] = $this->query_result; + $this->open_queries[$safe_query_id] = $this->query_result; } } else if ($this->debug_sql_explain) @@ -494,9 +496,10 @@ class oracle extends \phpbb\db\driver\driver $query_id = $this->query_result; } - if ($cache && $cache->sql_exists($query_id)) + $safe_query_id = $this->clean_query_id($query_id); + if ($cache && $cache->sql_exists($safe_query_id)) { - return $cache->sql_fetchrow($query_id); + return $cache->sql_fetchrow($safe_query_id); } if ($query_id) @@ -542,9 +545,10 @@ class oracle extends \phpbb\db\driver\driver $query_id = $this->query_result; } - if ($cache && $cache->sql_exists($query_id)) + $safe_query_id = $this->clean_query_id($query_id); + if ($cache && $cache->sql_exists($safe_query_id)) { - return $cache->sql_rowseek($rownum, $query_id); + return $cache->sql_rowseek($rownum, $safe_query_id); } if (!$query_id) @@ -617,13 +621,14 @@ class oracle extends \phpbb\db\driver\driver $query_id = $this->query_result; } - if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) + $safe_query_id = $this->clean_query_id($query_id); + if ($cache && $cache->sql_exists($safe_query_id)) { - $cache->sql_freeresult($query_id); + $cache->sql_freeresult($safe_query_id); } - else if (isset($this->open_queries[(int) $query_id])) + else if (isset($this->open_queries[$safe_query_id])) { - unset($this->open_queries[(int) $query_id]); + unset($this->open_queries[$safe_query_id]); oci_free_statement($query_id); } } diff --git a/phpBB/phpbb/db/driver/postgres.php b/phpBB/phpbb/db/driver/postgres.php index 72004b758c..3d981bc9c7 100644 --- a/phpBB/phpbb/db/driver/postgres.php +++ b/phpBB/phpbb/db/driver/postgres.php @@ -509,25 +509,4 @@ class postgres extends \phpbb\db\driver\driver { return '"' . $msg . '"'; } - - /** - * Ensure query ID can be used by cache - * - * @param resource|int|string $query_id Mixed type query id - * - * @return int|string Query id in string or integer format - */ - private function clean_query_id($query_id) - { - // As of PHP 8.1 PgSQL functions accept/return \PgSQL\* objects instead of "pgsql *" resources - // Attempting to cast object to int will throw error, hence correctly handle all cases - if (is_resource($query_id)) - { - return function_exists('get_resource_id') ? get_resource_id($query_id) : (int) $query_id; - } - else - { - return is_object($query_id) ? spl_object_id($query_id) : $query_id; - } - } } diff --git a/phpBB/phpbb/db/driver/sqlite3.php b/phpBB/phpbb/db/driver/sqlite3.php index 25905a14a7..5c03f0b547 100644 --- a/phpBB/phpbb/db/driver/sqlite3.php +++ b/phpBB/phpbb/db/driver/sqlite3.php @@ -219,9 +219,10 @@ class sqlite3 extends \phpbb\db\driver\driver $query_id = $this->query_result; } - if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) + $safe_query_id = $this->clean_query_id($query_id); + if ($cache && $cache->sql_exists($safe_query_id)) { - return $cache->sql_fetchrow($query_id); + return $cache->sql_fetchrow($safe_query_id); } return is_object($query_id) ? @$query_id->fetchArray(SQLITE3_ASSOC) : false; @@ -247,9 +248,10 @@ class sqlite3 extends \phpbb\db\driver\driver $query_id = $this->query_result; } - if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) + $safe_query_id = $this->clean_query_id($query_id); + if ($cache && $cache->sql_exists($safe_query_id)) { - $cache->sql_freeresult($query_id); + $cache->sql_freeresult($safe_query_id); return; } diff --git a/tests/mock/cache.php b/tests/mock/cache.php index 2306fd9009..cc50d0b81b 100644 --- a/tests/mock/cache.php +++ b/tests/mock/cache.php @@ -168,4 +168,8 @@ class phpbb_mock_cache implements \phpbb\cache\driver\driver_interface { return isset($this->data['_bots']) ? $this->data['_bots'] : array(); } + + public function clean_query_id($query_id) + { + } }