williamrast
Forum Replies Created
-
Hello @vmarko
Problem OverviewThe database caching layer in
Enterprise_Dbcache_WpdbInjection_Cluster.phpdoes not properly handle:- Invalid SQL queries with MySQL reserved keywords
- Boolean return values from DDL queries (CREATE TABLE, DROP TABLE, ALTER TABLE)
- Type checking before using mysqli_* functions that require mysqli_result objects
This leads to a cascade of fatal errors when plugins use WordPress’s
dbDelta()function. Error SequenceError 1 (Line 684):
Uncaught Exception: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IF' at line 1Error 2 (Line 757):
Uncaught Error: mysqli_fetch_object(): Argument #1 ($result) must be of type mysqli_result, bool givenRoot Causes
- No query validation before executing
mysqli_query()(line 684) - Incomplete type checking –
is_a()check exists for one loop but missing fordo-whileloop (line 757) - Assumption that all queries return mysqli_result – DDL queries return boolean, not result objects
Complete Fix Fix #1: Add Query Validation (Lines 683-684)
Location:
Enterprise_Dbcache_WpdbInjection_Cluster.php:683-684Original code:
php
$this->wpdb_mixin->timer_start(); $this->wpdb_mixin->result = mysqli_query( $this->wpdb_mixin->dbh, $query ); $elapsed = $this->wpdb_mixin->timer_stop();Fixed code:
php
$this->wpdb_mixin->timer_start(); // Validate query before execution // Block DESCRIBE queries with MySQL reserved keywords if (preg_match('/^\s*DESCRIBE\s+(IF|AND|OR|NOT|NULL|TRUE|FALSE|SELECT|FROM|WHERE|CASE|WHEN|THEN|ELSE|END|EXISTS|IN|LIKE|BETWEEN|IS|AS|ON|JOIN|LEFT|RIGHT|INNER|OUTER|UNION|GROUP|ORDER|HAVING|LIMIT|OFFSET|SET|VALUES|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|GRANT|REVOKE)\s*;?\s*$/i', $query)) { $this->wpdb_mixin->result = false; $this->wpdb_mixin->last_error = 'Invalid table name in DESCRIBE query (reserved MySQL keyword)'; error_log('W3TC DB Cache: Blocked invalid DESCRIBE query: ' . $query); return false; } // Block DESCRIBE queries with empty table names if (preg_match('/^\s*DESCRIBE\s*;?\s*$/i', $query)) { $this->wpdb_mixin->result = false; $this->wpdb_mixin->last_error = 'Empty table name in DESCRIBE query'; error_log('W3TC DB Cache: Blocked DESCRIBE with empty table name'); return false; } $this->wpdb_mixin->result = mysqli_query( $this->wpdb_mixin->dbh, $query ); $elapsed = $this->wpdb_mixin->timer_stop();Fix #2: Complete Type Checking (Lines 741-768)
Location:
Enterprise_Dbcache_WpdbInjection_Cluster.php:741-768Original code:
php
} else { $i = 0; $this->wpdb_mixin->col_info = array(); $col_info = array(); if ( is_a( $this->wpdb_mixin->result, 'mysqli_result' ) ) { while ( $i < @mysqli_num_fields( $this->wpdb_mixin->result ) ) { $col_info[ $i ] = @mysqli_fetch_field( $this->wpdb_mixin->result ); ++$i; } } $this->wpdb_mixin->col_info = $col_info; $num_rows = 0; $this->wpdb_mixin->last_result = array(); do { // ❌ NO TYPE CHECK HERE - CAUSES FATAL ERROR $row = @mysqli_fetch_object( $this->wpdb_mixin->result ); if ( $row ) { $this->wpdb_mixin->last_result[ $num_rows ] = $row; ++$num_rows; } } while ( $row ); // Log number of rows the query returned. $this->num_rows = $num_rows; // Return number of rows selected. return $num_rows; }Fixed code:
php
} else { $i = 0; $this->wpdb_mixin->col_info = array(); $col_info = array(); if ( is_a( $this->wpdb_mixin->result, 'mysqli_result' ) ) { while ( $i < @mysqli_num_fields( $this->wpdb_mixin->result ) ) { $col_info[ $i ] = @mysqli_fetch_field( $this->wpdb_mixin->result ); ++$i; } } $this->wpdb_mixin->col_info = $col_info; $num_rows = 0; $this->wpdb_mixin->last_result = array(); // ✅ ADD TYPE CHECK BEFORE do-while LOOP if ( is_a( $this->wpdb_mixin->result, 'mysqli_result' ) ) { do { $row = @mysqli_fetch_object( $this->wpdb_mixin->result ); if ( $row ) { $this->wpdb_mixin->last_result[ $num_rows ] = $row; ++$num_rows; } } while ( $row ); } // Log number of rows the query returned. $this->num_rows = $num_rows; // Return number of rows selected. return $num_rows; }Why These Fixes Work
- Query Validation (Fix #1): Prevents execution of malformed SQL queries that would cause MySQL syntax errors
- Complete Type Checking (Fix #2): Ensures
mysqli_fetch_object()is only called on valid mysqli_result objects, not boolean values
Affected Files
wp-content/plugins/w3-total-cache/Enterprise_Dbcache_WpdbInjection_Cluster.php- Lines 683-684 (query validation)
- Lines 755-761 (type checking for do-while loop)
Request
Please incorporate these fixes into the next release of W3 Total Cache. These issues affect any plugin that uses WordPress’s
dbDelta()function during initialization, making Database Cache incompatible with a significant number of plugins.Thank you for your attention to this critical issue.
Hello @vmarko
I posted it https://github.com/BoldGrid/w3-total-cache/issues/1120, but no one is responding. It’s like you’ve been mocking me for four months. What’s so difficult about posting the suggested code???
Hello @vmarko
I posted it https://github.com/BoldGrid/w3-total-cache/issues/1120, but no one is responding. It’s like you’ve been mocking me for two months. What’s so difficult about posting the suggested code???
Fatal error: Uncaught TypeError: mysqli_fetch_object(): Argument #1 ($result) must be of type mysqli_result, bool given in /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/w3-total-cache/Enterprise_Dbcache_WpdbInjection_Cluster.php:739 Stack trace: #0 /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/w3-total-cache/Enterprise_Dbcache_WpdbInjection_Cluster.php(739): mysqli_fetch_object(true) #1 /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/w3-total-cache/DbCache_WpdbNew.php(217): W3TC\Enterprise_Dbcache_WpdbInjection_Cluster->query(‘CREATE TABLE IF…’) #2 /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/w3-total-cache/DbCache_WpdbNew.php(664): W3TC\DbCache_WpdbNew->query(‘CREATE TABLE IF…’) #3 /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/w3-total-cache/DbCache_WpdbInjection_QueryCaching.php(213): W3TC\_CallUnderlying->query(‘CREATE TABLE IF…’) #4 /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/w3-total-cache/DbCache_WpdbNew.php(217): W3TC\DbCache_WpdbInjection_QueryCaching->query(‘CREATE TABLE IF…’) #5 /var/www/www-root/data/www/ap71.tw1.ru/wp-admin/includes/upgrade.php(3280): W3TC\DbCache_WpdbNew->query(‘CREATE TABLE IF…’) #6 /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/daftplug-progressify/includes/modules/dashboard.php(71): dbDelta(Array) #7 /var/www/www-root/data/www/ap71.tw1.ru/wp-includes/class-wp-hook.php(324): DaftPlug\Progressify\Module\Dashboard->createPwaUsersTable(”) #8 /var/www/www-root/data/www/ap71.tw1.ru/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters(NULL, Array) #9 /var/www/www-root/data/www/ap71.tw1.ru/wp-includes/plugin.php(517): WP_Hook->do_action(Array) #10 /var/www/www-root/data/www/ap71.tw1.ru/wp-settings.php(727): do_action(‘init’) #11 /var/www/www-root/data/www/ap71.tw1.ru/wp-config.php(140): require_once(‘/var/www/www-ro…’) #12 /var/www/www-root/data/www/ap71.tw1.ru/wp-load.php(50): require_once(‘/var/www/www-ro…’) #13 /var/www/www-root/data/www/ap71.tw1.ru/wp-admin/admin.php(35): require_once(‘/var/www/www-ro…’) #14 /var/www/www-root/data/www/ap71.tw1.ru/wp-admin/plugin-install.php(16): require_once(‘/var/www/www-ro…’) #15 {main} thrown in /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/w3-total-cache/Enterprise_Dbcache_WpdbInjection_Cluster.php on line 739
Hello @vmarko I still get the error
Hello @vmarko
Why you don’t use my solution?@vmarko Here is the plugin for your testing. A license is not required.
https://drive.google.com/file/d/1y0nUz9X00z2R7YzowGR39a3exrzFTdeK/view?usp=sharing
Hello @vmarko
Fatal error: Uncaught TypeError: mysqli_fetch_object(): Argument #1 ($result) must be of type mysqli_result, bool given in /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/w3-total-cache/Enterprise_Dbcache_WpdbInjection_Cluster.php:739 Stack trace: #0 /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/w3-total-cache/Enterprise_Dbcache_WpdbInjection_Cluster.php(739): mysqli_fetch_object(true) #1 /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/w3-total-cache/DbCache_WpdbNew.php(217): W3TC\Enterprise_Dbcache_WpdbInjection_Cluster->query(‘CREATE TABLE IF…’) #2 /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/w3-total-cache/DbCache_WpdbNew.php(664): W3TC\DbCache_WpdbNew->query(‘CREATE TABLE IF…’) #3 /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/w3-total-cache/DbCache_WpdbInjection_QueryCaching.php(213): W3TC\_CallUnderlying->query(‘CREATE TABLE IF…’) #4 /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/w3-total-cache/DbCache_WpdbNew.php(217): W3TC\DbCache_WpdbInjection_QueryCaching->query(‘CREATE TABLE IF…’) #5 /var/www/www-root/data/www/ap71.tw1.ru/wp-admin/includes/upgrade.php(3280): W3TC\DbCache_WpdbNew->query(‘CREATE TABLE IF…’) #6 /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/_daftplug-progressify/includes/modules/dashboard.php(71): dbDelta(Array) #7 /var/www/www-root/data/www/ap71.tw1.ru/wp-includes/class-wp-hook.php(324): DaftPlug\Progressify\Module\Dashboard->createPwaUsersTable(”) #8 /var/www/www-root/data/www/ap71.tw1.ru/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters(NULL, Array) #9 /var/www/www-root/data/www/ap71.tw1.ru/wp-includes/plugin.php(517): WP_Hook->do_action(Array) #10 /var/www/www-root/data/www/ap71.tw1.ru/wp-settings.php(727): do_action(‘init’) #11 /var/www/www-root/data/www/ap71.tw1.ru/wp-config.php(140): require_once(‘/var/www/www-ro…’) #12 /var/www/www-root/data/www/ap71.tw1.ru/wp-load.php(50): require_once(‘/var/www/www-ro…’) #13 /var/www/www-root/data/www/ap71.tw1.ru/wp-admin/admin.php(35): require_once(‘/var/www/www-ro…’) #14 /var/www/www-root/data/www/ap71.tw1.ru/wp-admin/plugin-install.php(16): require_once(‘/var/www/www-ro…’) #15 {main} thrown in /var/www/www-root/data/www/ap71.tw1.ru/wp-content/plugins/w3-total-cache/Enterprise_Dbcache_WpdbInjection_Cluster.php on line 739
Hello @vmarko
Thank you for your quick response and suggested fix. Unfortunately, after implementing the change you recommended (modifying line 444 with
if ( is_a( $this->wpdb_mixin->result, 'mysqli_result' ) ) {), the error still persists. Observed ErrorThe same error continues to appear:
Fatal error: Uncaught TypeError: mysqli_num_fields(): Argument #1 ($result) must be of type mysqli_result, bool given in /wp-content/plugins/w3-total-cache/Enterprise_Dbcache_WpdbInjection_Cluster.php:727Issue Analysis
After further analysis, I’ve identified that:
- The error occurs at line 727, not line 444
- The stack trace shows
mysqli_num_fields(true)is being called with a boolean value - Your check at line 444 doesn’t affect the execution path that reaches line 727
Proposed Solution
I’ve implemented a different fix that successfully resolves the issue. It involves adding type checking directly before both calls that can cause errors:
php
else { $i = 0; $this->wpdb_mixin->col_info = array(); $col_info = array(); // Add type checking before calling mysqli_num_fields() if (is_object($this->wpdb_mixin->result) && !is_bool($this->wpdb_mixin->result)) { while ( $i < @mysqli_num_fields( $this->wpdb_mixin->result ) ) { $col_info[ $i ] = @mysqli_fetch_field( $this->wpdb_mixin->result ); ++$i; } } $this->wpdb_mixin->col_info = $col_info; $num_rows = 0; $this->wpdb_mixin->last_result = array(); // Add type checking before fetching rows if (is_object($this->wpdb_mixin->result) && !is_bool($this->wpdb_mixin->result)) { do { $row = @mysqli_fetch_object( $this->wpdb_mixin->result ); if ( $row ) { $this->wpdb_mixin->last_result[ $num_rows ] = $row; ++$num_rows; } } while ( $row ); }These changes ensure that both critical sections that interact with the mysqli_result object are properly protected with type checking. The fix works by:
- Only attempting to call
mysqli_num_fields()when the result is an actual object (not a boolean) - Similarly protecting the row fetching loop
- Maintaining all the variables and arrays to preserve the method’s logic
I’ve verified this solution successfully resolves the conflict with the Daftplug Progressify plugin while maintaining W3 Total Cache functionality.
I’d be happy to provide any additional information or testing to help resolve this issue in the official release.
Forum: Plugins
In reply to: [Query Monitor] I don’t see Debugging blocks in version 3.17.2.done
Forum: Plugins
In reply to: [Query Monitor] I don’t see Debugging blocks in version 3.17.2.I’m an idiot, why doesn’t it say anywhere that blocks only works with the gutenberg editor?
It’s not even in the FAQ!
https://querymonitor.com/wordpress-debugging/blocks/