Wednesday 21 May 2014

Problems with WordPress version 3.9 and 3.9.1 - Prepare Statement

Problems with WordPress version 3.9 and 3.9.1 - Prepare Statement

By Strictly-Software

If you have upgraded to WordPress 3.9.1 and suddenly found yourself with a bunch of errors coming from you in every direction it will probably be due to their decision to re-write their wpdb.php class.

Whilst I applaud their decision to implement their own version of my own code that was fixing the "MySQL Server Has Gone Away" Error that seemed to appear everywhere due to lost connections.

It does this by repeatedly calling a "reconnect" in a loop if the error is spawned.

I have to say as a WordPress developer with not much time on his hands that to be told a day before by email (from WordPress) that they were releasing version 3.9 the very next day was not very helpful indeed.

I did warn all my plugin users NOT to upgrade to it (see >  http://blog.strictly-software.com/2014/04/please-dont-upgade-to-wordpress-39.html) as I have no idea what will break with my own plugins if they do.

I still am on 3.8.2 and I won't upgrade until I know I won't be causing a whole shit storm of bugs for myself.

One of these bugs is the prepare statement.

Whilst a newbie PHP / WordPress developer I got into the habit of using $wpdb->prepare all the time when creating inline SQL statements - "where are the decent, transaction, multi recordset returning stored procedures that MS SQL did 10 years ago I still cry in the air at MySQL in vain!"

Therefore a statement like this where I am replacing certain parameters with values is what prepare is aimed for and will work fine in WP 3.9.1


$sql = $wpdb->prepare("UPDATE {$wpdb->posts} SET post_content = %s WHERE id = %d;", $newcontent,$object->ID);


However because of the new re-write of their wpdb.php class in /wp-includes to handle both old and new versions of the MySQL library functions they have also added some unnecessary (or maybe they think they are - forgetting the millions of people who use their code and the plugins built on it) methods and new functionality to existing methods.

One of those is in the prepare method


At the top of the function are these lines of code.

function prepare( $query, $args ) {

if ( is_null( $query ) )
   return;

// This is not meant to be foolproof -- but it will catch obviously incorrect usage.
if ( strpos( $query, '%' ) === false ) {

              _doing_it_wrong( 'wpdb::prepare', sprintf( __( 'The query argument of %s must have a placeholder.' ), 'wpdb::prepare()' ), '3.9' );

}


Notice what it is doing?

It is making sure that the query passed into the prepare method has at least one % symbol in it.

Therefore if you are a plugin write who has just got into the habit of wrapping all their WordPress SQL strings in $wpdb->prepare functions - whether OR NOT they actually have parameters to be replaced you are now in a big hole of doom.

Instead of the error message I guess they hope users see ("The query argument of %s must have a placeholder") is shown to people instead I am getting complaints (see > WordPress bug in my plugin - really WP 3.9.1 ) that don't contain that error message at all.

Instead it will just be a warning that

Warning: Missing argument 2 for wpdb::prepare(), called in XXXX

Therefore quick fixes

1. Use my own wpdb.php class in 3.9.1 and forget about the newer MySQL functions but still have the fix for MySQL Server Has Gone Away and NO ERRORS when Prepare is used without parameters.

2. Remove those lines of code from the top of the wpdb.php class. e.g

function prepare( $query, $args ) {

if ( is_null( $query ) )
   return;

// REMOVE THESE LINES BELOW!
// This is not meant to be foolproof -- but it will catch obviously incorrect usage.
if ( strpos( $query, '%' ) === false ) {

              _doing_it_wrong( 'wpdb::prepare', sprintf( __( 'The query argument of %s must have a placeholder.' ), 'wpdb::prepare()' ), '3.9' );

}

3. Return to using WordPress 3.8.1. There might be some legitimate security holes that the WordPress team have fixed so be careful and check what they actually did in the 3.9 and 3.9.1 updates. Also make sure you are blocking spammers, hackers and the like with tools like fail2ban, .htaccess rules, firewalls, DenyHosts, WordPress firewall plugins and constant analysis of your log files.

Read my article on WordPress security for more information: blog.strictly-software.com/2012/03/wordpress-survival-guide-part-3.html

4. Or get every plugin developer who has used this method without placeholders to rewrite his code, even though he has a hectic day job and may not care or have the time.

If you do - donate!

If you do try and get him to change his code due to WordPress changing theirs as it's not the plugin developers fault in my eyes.

No comments: