PHP Warning: Missing argument 2 for wpdb::prepare()
Hello plugin or theme author! You possibly found this post after searching the Internet for the error above: “PHP Warning: Missing argument 2 for wpdb::prepare().”
So, this is a new warning in 3.5. No sites are broken, everything is fine as before. But, this is indeed something you need to look at, because you may be exposing your users to a possible SQL injection vulnerability. Now that’s no fun!
First, if you’re a user and you want to get rid of these errors, you should turn off the displaying of errors in PHP. There are many ways to do this, such as in php.ini, .htaccess, etc. For this, you can just put this in wp-config.php. (Note that hiding errors on production sites is good practice anyway.)
@ini_set('display_errors', 0);
If you’re a user, you can stop here. (If you need more help, please don’t comment here, try the helpful Support Forums.) Just be sure to send a link to this post to the developer of the theme or plugin referenced in the error.
Now, developers: Here’s how $wpdb->prepare() is supposed to work:
$wpdb->prepare( "SELECT * FROM table WHERE ID = %d AND name = %s", $id, $name );
See how $id — an integer, presumably — was passed as the second argument? That corresponds to the first placeholder, %d. Then, $name (a string) was passed as the third argument, thus the second placeholder, %s. This makes sure your query is safe, and prevents something like little bobby tables. (Note: the comic is wrong, don’t sanitize — always prepare your queries.)
The problem is, a number of people were calling $wpdb->prepare() with only one argument, like so:
$wpdb->prepare( "SELECT COUNT(*) FROM table" );
See, there’s no parameter (%d, %s, or for floats, %f) in this query. This happens to work fine, but the prepare call isn’t doing anything. You should instead the query directly, as there are no inputs.
But here’s where the problem lies:
$wpdb->prepare( "SELECT * FROM table WHERE id = $id" );
See the problem? That query isn’t secure! You may think you are “preparing” this query, but you’re not — you’re passing $id directly into the query, unprepared. And this, right here, is why $wpdb->prepare() now issues a warning if it isn’t called with more than one argument. Because you can’t prepare a query without more than one argument. Here’s a correct example:
$wpdb->prepare( "SELECT * FROM table WHERE id = %d", $id );
This wasn’t a decision done lightly. We don’t like shoving PHP warnings into the faces of users and developers. But given the potential security risks, we wanted everyone to immediately look at how they are running queries. And, of course, always prepare them properly.
For more: wpdb Codex reference, #22262, and [22429].
Samuel Wood (Otto) 6:17 am on December 12, 2012 Permalink
Dangit. Stole my ottopress post for tomorrow. Now I have to come up with fresh, original content.
Pippin (mordauk) 6:21 am on December 12, 2012 Permalink
Damn, stole my Pippin’s Plugins post for tomorrow. Seriously
Andrew Nacin 6:23 am on December 12, 2012 Permalink
Find something else, suckers.
Lots of juicy stuff in 3.5! Also, make/plugins and make/core could both use content!
Ipstenu (Mika Epstein) 6:47 am on December 12, 2012 Permalink
And he updated the forums… Well hell, I’m having a drink and going to bed!
Justin Sternberg 3:33 pm on December 12, 2012 Permalink
We need comment “like” buttons.
tmontg2 5:49 pm on December 14, 2012 Permalink
lol! too funny. Thanks for the post!
Emil Uzelac 6:23 am on December 12, 2012 Permalink
Good one, just submitted this http://wordpress.org/support/topic/warning-missing-argument-2-for-wpdbprepare-3 15 minutes ago. Let me link to this post as well, to help author out
Thanks,
Emil
chacha102 6:30 am on December 12, 2012 Permalink
I think you mean, you can’t prepare a query without more than one argument.
Andrew Nacin 6:31 am on December 12, 2012 Permalink
Updated, thanks.
Brian Layman 6:56 am on December 12, 2012 Permalink
Interesting.. So the rule of “Always use prepare on queries” is simply wrong.
It should be “Always use prepare on queries that built with variable arguments.”
I’d always thought it did further sanitization of the query string itself, but I suppose that would be really hard to do without blocking some valid query people would inevitably want.
Samuel Wood (Otto) 6:58 am on December 12, 2012 Permalink
The *vast* majority of problems with this I’ve seen today had variable arguments, but were putting them directly in the strings, like the third code example there. Which basically means that prepare did nothing to protect them.
Previously, prepare(‘string’) returned ‘string’. Now it returns ‘string’ and a warning that you are doing-it-wrong.
chacha102 7:03 am on December 12, 2012 Permalink
If you check out the source code for wpdb::prepare it really isn’t that interesting.
Vitor Carvalho 11:17 am on December 12, 2012 Permalink
Fantastic explanation Nacin
Joost de Valk 2:14 pm on December 12, 2012 Permalink
Had to chuckle a bit when I found this:
Missing argument 2 for wpdb::prepare(), called in /home/example/public_html/wp-content/plugins/akismet/admin.php
rfair404 2:14 pm on December 12, 2012 Permalink
Thanks Nacin, I started seeing these notices in the last few weeks on several plugins that I use. glad to know what’s going on here.
a6april 3:18 pm on December 12, 2012 Permalink
Thanks Huge Andrew, I had no idea! I am always glad to learn something everyday! I appreciate the quick followup and all of the responses. Have a great day all!
Josh 4:31 pm on December 12, 2012 Permalink
Extremely useful… and “juicy”! Thanks Andrew! Saved me tons of time. Nice to know you guys are on top of security. Thanks again!
nomadentech 11:29 am on December 13, 2012 Permalink
This is works perfectly, i think similar error will found in another plugins, so we dont need to fear for updating WordPress core.
Thank you,
Teguh
properwp 6:01 pm on December 13, 2012 Permalink
Thank you very much! We’re using a modified version of a clunky plugin in the repo and we keep finding new, wonderful problems. Another one of those “probably should have started from scratch” situations!
Mark de Scande BlogLines 8:04 pm on December 13, 2012 Permalink
The only thing here is that it should have been noted some were or it was and i did not see it or i did not read i had the same problem on my Wife site SuperBlogs.co.za but on BlogLines.co.za it all was perfect on SB i just added some dirty code to make it go away
http://wordpress.org/support/topic/err-after-upgrade-to-35?replies=9
But thx for posting it here for us all to see
Nashwan Doaqan 5:32 pm on December 14, 2012 Permalink
Thank You Andrew Nacin , I see many plugins have this PHP warning .
I hope a good life for all plugins authors