sqlite-database-integration icon indicating copy to clipboard operation
sqlite-database-integration copied to clipboard

Wordfence fails to load in Playground with undefined method WP_SQLite_Driver::prepare error

Open bgrgicak opened this issue 1 month ago • 8 comments

When I try to start Playground with the Wordfence plugin it fails to activate the plugin with the following error.

[06-Nov-2025 12:06:48 UTC] PHP Fatal error: Uncaught Error: Call to undefined method WP_SQLite_Driver::prepare() in /wordpress/wp-content/plugins/wordfence/lib/wfConfig.php:883 Stack trace: #0 /wordpress/wp-content/plugins/wordfence/models/scanner/wfScanner.php(1339): wfConfig::set_ser('allScansSchedul...', Array) #1 /wordpress/wp-content/plugins/wordfence/models/scanner/wfScanner.php(1199): wfScanner->unscheduleAllScans() #2 /wordpress/wp-content/plugins/wordfence/lib/wordfenceClass.php(1130): wfScanner->scheduleScans() #3 /wordpress/wp-content/plugins/wordfence/lib/wordfenceClass.php(1195): wordfence::runInstall() #4 /wordpress/wp-content/plugins/wordfence/wordfence.php(146): wordfence::install_actions() #5 /wordpress/wp-admin/includes/plugin.php(2): include_once('/wordpress/wp-c...') #6 /wordpress/wp-admin/includes/plugin.php(2): plugin_sandbox_scrape('wordfence/wordf...') #7 /internal/eval.php(20): activate_plugin('wordfence/wordf...') #8 {main} thrown in /wordpress/wp-content/plugins/wordfence/lib/wfConfig.php on line 883

bgrgicak avatar Nov 06 '25 12:11 bgrgicak

@bgrgicak I've seen this one before, but I thought there was nothing we could do on our side. The problem is that Wordfence uses the $wpdb->dbh property directly, considering it an instance of mysqli, without checking if it really is.

Now, digging deeper, I can see that this logic is optional on their side, so we could make sure it's never triggered:

$useMySQLi = (is_object($dbh) && (PHP_MAJOR_VERSION >= 7 || $wpdb->use_mysqli) && wfConfig::get('allowMySQLi', true) && WORDFENCE_ALLOW_DIRECT_MYSQLI);

It's certainly something we should let them know about, as a simple $wpdb->dbh instanceof mysqli on their side would fix it, but in the meantime, we could perhaps make the condition above fail.

I see two possibilities for a quick fix:

  1. Set WORDFENCE_ALLOW_DIRECT_MYSQLI to false. Risk—emitting Constant already defined warning when someone defines it manually (probably a pretty low chance).
  2. Set $wpdb->use_mysqli to false. Maybe even better, because the SQLite driver is not mysqli indeed. However, it was originally used differently: "Whether to use the mysqli extension over mysql. This is no longer used as the mysql extension is no longer supported." Since it's no longer used, the risk of breaking things is likely low as well.

What do you think, @bgrgicak and @adamziel? I'm leaning to option 2 now as a super-quick fix, plus contacting Wordfence about it so that they consider adding the mysqli instance check.

JanJakes avatar Nov 06 '25 13:11 JanJakes

Option 2 + engaging with Wordfence sounds great!

adamziel avatar Nov 06 '25 15:11 adamziel

@adamziel Oh, option 2 won't work due to the || part in (PHP_MAJOR_VERSION >= 7 || $wpdb->use_mysqli) 😬

Should we do option 1 for now? Or only ping Wordfence first?

JanJakes avatar Nov 06 '25 15:11 JanJakes

I'd only ping WordFence, we don't want to unexpectedly break anyone's site which emitting a warning could do.

adamziel avatar Nov 06 '25 16:11 adamziel

Actually... what would it take to make this false? wfConfig::get('allowMySQLi', true)

adamziel avatar Nov 06 '25 16:11 adamziel

I created a ticket on their side: https://wordpress.org/support/topic/sqlite-and-wordpress-playground-compatibility/

Actually... what would it take to make this false? wfConfig::get('allowMySQLi', true)

I can check that path too. If it's not too complex, it could be a viable temporary hotfix. But let's see how it goes with a fix on their side. Using a quick fix with the constant definition, it reveals another error, so Wordfence support is not there yet anyway:

<p>MySQL query:</p>
<p>SELECT COUNT(*) FROM wp_wflivetraffichuman WHERE IP = X'00000000000000000000ffff7f000001' AND identifier = '��B�����șo�$\'�A�d��L���R�U' AND expiration >= UNIX_TIMESTAMP()</p>
<p>Queries made or created this session were:</p>
<ol>
<li>Executing: BEGIN IMMEDIATE | (no parameters)</li>
<li>Executing: ROLLBACK | (no parameters)</li>
</ol>
</div>
<div style="clear:both;margin-bottom:2px;border:red dotted thin;" class="error_message" style="border-bottom:dotted blue thin;">
Return value of WP_MySQL_Token::get_value() must be of the type string, null returned

I wonder if there are some non-UTF-8 characters being used.

JanJakes avatar Nov 06 '25 16:11 JanJakes

Is it them or is it us? I doubt it throws that error with MySQL

adamziel avatar Nov 06 '25 17:11 adamziel

Is it them or is it us? I doubt it throws that error with MySQL

@adamziel Yeah, I'm pretty sure the second error will be on our side, but I don't know yet what's happening there.

JanJakes avatar Nov 06 '25 19:11 JanJakes