Forum Replies Created

Viewing 11 replies - 1 through 11 (of 11 total)
  • Thread Starter williamrast

    (@williamrast)

    Hello @vmarko
    Problem Overview

    The database caching layer in Enterprise_Dbcache_WpdbInjection_Cluster.php does not properly handle:

    1. Invalid SQL queries with MySQL reserved keywords
    2. Boolean return values from DDL queries (CREATE TABLE, DROP TABLE, ALTER TABLE)
    3. 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 Sequence

    Error 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 1

    Error 2 (Line 757):

    Uncaught Error: mysqli_fetch_object(): Argument #1 ($result) must be of type mysqli_result, bool given

    Root Causes

    1. No query validation before executing mysqli_query() (line 684)
    2. Incomplete type checkingis_a() check exists for one loop but missing for do-while loop (line 757)
    3. 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-684

    Original 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-768

    Original 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

    1. Query Validation (Fix #1): Prevents execution of malformed SQL queries that would cause MySQL syntax errors
    2. 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.

    Thread Starter williamrast

    (@williamrast)

    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???

    Thread Starter williamrast

    (@williamrast)

    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???

    Thread Starter williamrast

    (@williamrast)

    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

    Thread Starter williamrast

    (@williamrast)

    Hello @vmarko I still get the error

    Thread Starter williamrast

    (@williamrast)

    Hello @vmarko
    Why you don’t use my solution?

    Thread Starter williamrast

    (@williamrast)

    @vmarko Here is the plugin for your testing. A license is not required.

    https://drive.google.com/file/d/1y0nUz9X00z2R7YzowGR39a3exrzFTdeK/view?usp=sharing

    Thread Starter williamrast

    (@williamrast)

    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

    Thread Starter williamrast

    (@williamrast)

    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 Error

    The 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:727

    Issue Analysis

    After further analysis, I’ve identified that:

    1. The error occurs at line 727, not line 444
    2. The stack trace shows mysqli_num_fields(true) is being called with a boolean value
    3. 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:

    1. Only attempting to call mysqli_num_fields() when the result is an actual object (not a boolean)
    2. Similarly protecting the row fetching loop
    3. 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.

    Thread Starter williamrast

    (@williamrast)

    done

    Thread Starter williamrast

    (@williamrast)

    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/

Viewing 11 replies - 1 through 11 (of 11 total)