1

From the PHP Manual :

You cannot bind multiple values to a single named parameter in, for example, the IN() clause of an SQL statement.

But can you use multiple values using question mark parameter markers? Or do you have to prepare() a new statement every time the number of values changes?

SELECT * FROM `table` WHERE `column` IN(?)

If this is allowed how do you make it work?

EDIT: The two previous questions indicated were both about named variables, which the manual says can't be bound to multiple parameters. I was asking about question mark (anonymous) variables.

5
  • 2
    This is asked often. Here's one and here's another Commented Feb 13, 2014 at 19:07
  • make a string from multiple values and bind it Commented Feb 13, 2014 at 19:08
  • Generally, you need to make as many ?,?,?,?,? as you have array elements. Commented Feb 13, 2014 at 19:08
  • I did search before I asked but I didn't find what I was looking for. I would have been surprised if it hadn't been adked before. Commented Feb 13, 2014 at 19:45
  • There are no difference between named and anonymous in this matter. The manual is plainly wrong, emphasizing named placeholedr in the cited sentence. Commented Feb 16, 2014 at 9:44

1 Answer 1

1

Here's some code I whipped up to simulate the desired outcome:

<?php
function preprepare(&$query, &$data) {
    preg_match_all('/\?/', $query, $matches, PREG_OFFSET_CAPTURE);
    $num = count($matches[0]);
    for ($i = $num; $i;) {
        --$i;
        if (array_key_exists($i, $data) && is_array($data[$i])) {
            $query = substr_replace($query, implode(',', array_fill(0, count($data[$i]), '?')), $matches[0][$i][1], strlen($matches[0][$i][0]));
            array_splice($data, $i, 1, $data[$i]);
        }
    }
}

$query = 'SELECT * FROM `table` WHERE `col1` = ? AND `col2` IN(?) AND `col3` = ? AND `col4` IN(?)';
$data = array('foo', array(1, 2, 3), 'bar', array(4, 2));
preprepare($query, $data);
var_dump($query, $data);
?>

It outputs:

array (size=2)
  0 => string 'SELECT * FROM `table` WHERE `col1` = ? AND `col2` IN(?,?,?) AND `col3` = ? AND `col4` IN(?,?)' (length=93)
  1 => 
    array (size=7)
      0 => string 'foo' (length=3)
      1 => int 1
      2 => int 2
      3 => int 3
      4 => string 'bar' (length=3)
      5 => int 4
      6 => int 2

The query and data can then be used in a normal PDO prepared statement. I don't know if it accounts for all PDO magic niceness but it works pretty well so far.

Sign up to request clarification or add additional context in comments.

5 Comments

Although the idea is quite right, but the code is full of magic and silent considerations. Also, you cannot use the real prepare anyways, means you still have to prepare() a new statement every time the number of values changes - so, the goal is still not reached.
However, you are moving towards the right direction. Implementing your own placeholder is the only proper solution.
I thought my solution was a bit nicer than others where you have to build the array in the right order yourself. Although the query needs to be "prepared" twice it works the way I would expect it to if it was supported natively.
Try to look a little further. IN() clause is not the only one that needs to be handled. SET clause is another one that asks to be automated. Are you really going to write long and windy INSERT or UPDATE queries by hand, are you? Wouldn't it be better to send an already formed array into query? You'll be unable to distinguish, which formatting is needed. Here is the article I wrote on the matter, covering the exact problem. It isn't finished yet, but I hope you will find it interesting: The Hitchhiker's Guide to SQL Injection protection
+1 for Hitchhiker's reference! Good article, however, I'm not trying to solve all the problems you mention with prepared statements, only the multiple parameter issue. I accept that currently SET is "too hard" to fix. As far as I'm aware my solution neither adds to nor removes from PDO any format detection problems.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.