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.

CJ Dennis
  • 4,226
  • 2
  • 40
  • 69
  • 2
    This is asked often. [Here's one](http://stackoverflow.com/questions/920353/php-pdo-can-i-bind-an-array-to-an-in-condition) [and here's another](http://stackoverflow.com/questions/14767530/php-using-pdo-with-in-clause-array) – Michael Berkowski Feb 13 '14 at 19:07
  • make a string from multiple values and bind it – Awlad Liton Feb 13 '14 at 19:08
  • Generally, you need to make as many `?,?,?,?,?` as you have array elements. – Michael Berkowski Feb 13 '14 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. – CJ Dennis Feb 13 '14 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. – Your Common Sense Feb 16 '14 at 09:44

1 Answers1

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.

CJ Dennis
  • 4,226
  • 2
  • 40
  • 69
  • 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. – Your Common Sense Feb 16 '14 at 09:37
  • However, you are moving towards the right direction. Implementing your own placeholder is the only proper solution. – Your Common Sense Feb 16 '14 at 09:45
  • 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. – CJ Dennis Feb 16 '14 at 11:26
  • 1
    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](http://phpdelusions.net/sql_injection) – Your Common Sense Feb 16 '14 at 13:21
  • +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. – CJ Dennis Feb 17 '14 at 01:55