[wp-trac] [WordPress Trac] #42040: `$wpdb->prepare` returns blank without notice if less number of arguments are passed. should give a notice or exception

WordPress Trac noreply at wordpress.org
Sat Sep 30 06:20:34 UTC 2017


#42040: `$wpdb->prepare` returns blank without notice if less number of arguments
are passed. should give a notice or exception
--------------------------+-----------------------------
 Reporter:  thekt12       |      Owner:
     Type:  defect (bug)  |     Status:  new
 Priority:  normal        |  Milestone:  Awaiting Review
Component:  Query         |    Version:  4.8.2
 Severity:  normal        |   Keywords:
  Focuses:                |
--------------------------+-----------------------------
 1.A '''`Right Case`''':
 {{{#!php
 <?php
 $wpdb->prepare("select * from wp_posts where ID=%d and post_type=%s",
 array("1","post"))
 }}}
 Returns:[[BR]]
 `select * from wp_posts where ID=1 and post_type='post'`[[BR]]
 which is right[[BR]]

 2.A '''`Right Case`''':
 {{{#!php
 <?php
 $wpdb->prepare("select * from wp_posts where ID=%d and
 post_type=%s",1,"post")
 }}}
 Returns:[[BR]]
 `select * from wp_posts where ID=1 and post_type='post'`[[BR]]
 which is also right[[BR]]

 3.A '''`Semi Right Case`''':
 {{{#!php
 <?php
 $wpdb->prepare("select * from wp_posts where ID=%d and post_type=%s",
 array("1","post","xyz"))
 }}}
 Returns:[[BR]]
 `select * from wp_posts where ID=1 and post_type='post'`[[BR]]
 understood it ignore extra attributes('''`but could give a notice`'''- i
 do understand that it is hard to find out in this case)[[BR]]
 [[BR]]
 '''But''' : [[BR]]
 [[BR]]

 3.A '''`Wrong Case`''' (Case with less argument passed in ) :
 {{{
 $wpdb->prepare("select * from wp_posts where ID=%d and post_type=%s",
 array("1"))
 }}}
 Returns:[[BR]]
 `blank`[[BR]]
 It should either `give a notice` or `an exception`. If it returns blank,
 it actually hides the actual problem.
 [[BR]]

 How serious is this issue?

 Think of the following snippet:

 {{{#!php
 <?php
 //this will return a blank without exception
 $statement = $wpdb->prepare("select * from wp_posts where ID=%d and
 post_type=%s", array("1"));

 // This will also return blank if blank string is passed in
 $results = $wpdb->get_results($statement);

 /* so the developer assumes that the result for this query is blank
  instead of the fact that this is caused due to a wrong number of argument
 that he has passed in.
 This is bound to happen in a large query.
 */
 }}}


 I am yet to figure out the actual way but following code (though not fool
 proof) will work:

 {{{#!php
 <?php
 public 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.0');
         }

         $args = func_get_args();
         array_shift($args);

         // If args were passed as an array (as in vsprintf), move them up
         if (is_array($args[0]) && count($args) == 1) {
             $args = $args[0];
         }

         foreach ($args as $arg) {
             if (! is_scalar($arg) && ! is_null($arg)) {
                 _doing_it_wrong('wpdb::prepare', sprintf('Unsupported
 value type (%s).', gettype($arg)), '4.8.2');
             }
         }

         $query = str_replace("'%s'", '%s', $query); // in case someone
 mistakenly already singlequoted it
         $query = str_replace('"%s"', '%s', $query); // doublequote
 unquoting
         $query = preg_replace('|(?<!%)%f|', '%F', $query); // Force floats
 to be locale unaware
         $query = preg_replace('|(?<!%)%s|', "'%s'", $query); // quote the
 strings, avoiding escaped strings like %%s
         $query = preg_replace('/%(?:%|$|([^dsF]))/', '%%\\1', $query); //
 escape any unescaped percents
         array_walk($args, array( $this, 'escape_by_ref' ));


 // my modification to wp-includes/wp-db.php function prepare()
         $statement = @vsprintf($query, $args);

         if(empty($statement) && !empty($query))
         {
             _doing_it_wrong('wpdb::prepare', "Improper prepare statemnt.
 Check the number of argument passed in" , '4.*.*');
         }


         return $statement;
     }
 }}}


 // will try to provied a better solution for this

--
Ticket URL: <https://core.trac.wordpress.org/ticket/42040>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list