1

I am new to PHP and hope someone can help me with this.

I currently have the following PHP which is part of an Ajax call in jQuery. When entering IDs manually instead of ? (e.g. 1,2,3,4,5) then this works as intended but when I use the query as below it only returns one item as shown below so I believe the combination of IN(?) and my attempt to prevent SQL injection don't work here.

Can someone tell me what I am doing wrong here ?
Also, this creates a multi-dimensional array and I was wondering if this could be simplified since I only need the ID (tID) and value (content) for each item.

My PHP:

$content = implode(",", $_POST["content"]);  // an array containing IDs retrieved from Ajax
$languageFrm = $_POST["languageFrm"];

$stmt = $conn->prepare("SELECT tID, " . $languageFrm . " FROM TranslationsMain WHERE tID IN(?) ORDER BY tID");
$stmt->bind_param("s", $content);
$stmt->execute();
$result = $stmt->get_result();
while($arrTranslations = $result->fetch_assoc()){
    $translations[] = array("tID" => $arrTranslations["tID"], "content" => $arrTranslations[$languageFrm]);
}
var_dump($translations);

Current result in Ajax:

array(1) {
  [0]=>
  array(2) {
    ["tID"]=>
    int(1)
    ["content"]=>
    string(6) "Value1"
  }
}

Update:
My issue is that even though the posted links and current answer seem to refer to the proper solutions I am not able to get the rest of the PHP code working since whenever I use one of the suggested solutions I get the error "Call to a member function fetch_assoc() on a non-object...".

Many thanks for any help with this,
Mike

keewee279
  • 1,656
  • 5
  • 28
  • 60
  • 1
    See: http://stackoverflow.com/q/1586587/3933332 – Rizier123 Jul 19 '15 at 16:48
  • 1
    Use one of the workarounds to expand placeholder `?,?,?,…` lists for parameter binding. [MySQLi using an IN in a where](http://stackoverflow.com/q/3269407), [Can I bind an array to an IN() condition?](http://stackoverflow.com/q/920353), [MySQLi prepared statements with IN operator](http://stackoverflow.com/q/11938876) – mario Jul 19 '15 at 16:49
  • @Rizier123: Thanks - I'll have a look. – keewee279 Jul 19 '15 at 16:51
  • @mario: Thanks - I will check this out as well. – keewee279 Jul 19 '15 at 16:51
  • I had a look at the links provided here and they seem to target the issue I have but I am still having trouble to apply this to my query. – keewee279 Jul 19 '15 at 17:03

1 Answers1

1

You're binding a string to a single parameter in your SQL code. Meaning your SQL translates to SELECT something FROM table WHERE attribute IN ("1,2,3,4,5") and that's clearly not what you want.

What you're trying to do is bind multiple parameters to your SQL dynamically. This can be achieved by dynamically setting the number of parameters in the prepared statement as demonstrated in the PHP manual under Example #5 of PDOStatement::execute(). I've added this as a general example in the manual since it's a pretty common use case.


Since you're using MySQLi and not PDO here I'll provide the MySQLi equivelant example...

$params = $_POST["content"];

$place_holders = implode(',', array_fill(0, count($params), '?'));


$stmt = $conn->prepare("SELECT tID, " . /* no way on earth will I ever do
                                           this $languageFrm */ null .
                       " FROM TranslationsMain WHERE tID IN($place_holders) ORDER BY tID");
// substitute PDO::execute() for call_user_func_array to bind_params because MySQLi sucks
call_user_func_array([$stmt, 'bind_param'], $params);
$stmt->execute();
$result = $stmt->get_result();
while($arrTranslations = $result->fetch_assoc()){
    $translations[] = array(
                            "tID" => $arrTranslations["tID"],
                            "content" => $arrTranslations[$languageFrm],
                           );
}
var_dump($translations);

You are still vulnerable to SQL Injection

Please also consider that your prepared statement is vulnerable to SQL injection since you are unsafely concatenating user-supplied input directly in to your SQL statement from $_POST["languageFrm"] in the line

$stmt = $conn->prepare("SELECT tID, " . $languageFrm .
        " FROM TranslationsMain WHERE tID IN(?) ORDER BY tID");

That big red glaring $languageFRM in your prepared statement is from user input and is a part of your SQL code, i.e. rendering all your efforts to use parameters in your query quite useless here.

Sherif
  • 11,786
  • 3
  • 32
  • 57
  • Thank you very much - this helps a lot ! – keewee279 Jul 19 '15 at 17:37
  • Update: I had a look at your example and updated my code accordingly but it looks like then I can't use the rest of my code (i.e. everythng after $stmt->execute();) since this is throwing the error "Call to a member function fetch_assoc() on a non-object...". Can you let me know how I would have to adjust this ? Also, I am not sure but it looks to me like you might have to replace ($place_holders) in your example with (" . $place_holders . ") ? – keewee279 Jul 19 '15 at 18:20
  • 1
    That would indicate that `$result` is not an object, further inferring that your call to `$stmt->get_result()` failed. See [what MySQLiStatement::getResult returns on failure](http://php.net/manual/en/mysqli-stmt.get-result). Notice the example I'm pointing out is for PDO, whereas you're using `MySQLi` here. To adapt this code to MySLQi you'll need to call `MySQLiStatement::bindParam()` with `call_user_func_array` . And no, the example is correct, as the SQL string contains the braces in the call to prepare. – Sherif Jul 19 '15 at 19:07
  • Thanks a lot for the updates and your explanations. I applied this as suggested but it doesn't work. If I use it as above then Dreamweaver marks the call_user_func_array line as invalid (perhaps due to the square brackets) and if I use array($stmt, "bind_param") instead then Dreamweaver accepts it but I get again the following error: "Call to a member function fetch_assoc() on a non-object...". – keewee279 Jul 20 '15 at 06:16
  • Same logic applies. That still means that `$result` is not an object. And if `$result` is not an object that tells you that `$stmt->get_result()` failed. And if `$stmt->get_result()` failed that tells you that it returned `false`. Consequently, if `var_dump($result)` is `false` that supports that `$stmt->get_result()` failed. Now, I'll leave up to the reader as an exercise to [dig in the manual and find out how to get useful error information from mysql](http://php.net/mysqli-stmt.error) on why the statement failed. – Sherif Jul 20 '15 at 18:27