Wie binde ich ein Array von Strings mit einer vorbereiteten mysqli-Anweisung?

Lesezeit: 12 Minuten

Benutzer-Avatar
Markieren

Ich muss ein Array von Werten an binden WHERE IN(?) Klausel. Wie kann ich das machen?

Das funktioniert:

$mysqli = new mysqli("localhost", "root", "root", "db");
if(!$mysqli || $mysqli->connect_errno)
{
    return;
}
$query_str= "SELECT name FROM table WHERE city IN ('Nashville','Knoxville')";
$query_prepared = $mysqli->stmt_init();
if($query_prepared && $query_prepared->prepare($query_str))
{       
    $query_prepared->execute();

Aber das kann ich mit einem bind_param wie diesem nicht zum Laufen bringen:

$query_str= "SELECT name FROM table WHERE city IN (?)";
$query_prepared = $mysqli->stmt_init();
if($query_prepared && $query_prepared->prepare($query_str))
{       
    $cities= explode(",", $_GET['cities']);
    $str_get_cities=  "'".implode("','", $get_cities)."'"; // This equals 'Nashville','Knoxville'

    $query_prepared->bind_param("s", $cities);
    $query_prepared->execute();

Was mache ich falsch?

Ich habe auch versucht call_user_func_arraykann aber anscheinend nicht die richtige Syntax abrufen.

  • $str_get_cities= "'".implode("','", $get_cities)."'"; . Verwenden Sie keine Anführungszeichen !! Das ist erledigt bind_param mit der Option “s” !

    – moskito-x

    10. Juli 2013 um 14:14 Uhr

  • Wie andere empfehlen, verwenden call_user_func_array Funktion, um die erforderlichen Parameter an Ihre parametrisierte Abfrage zu binden. Nur um zu betonen, dass es Parameter akzeptiert, die als Referenz übergeben werden. Ich konnte nur Teile des Codes finden, wie parametrisierte Abfragen mit dynamischer Menge an zu bindenden Parametern ausgeführt werden, also habe ich am Ende meine eigene Funktion gemacht (siehe diesen Beitrag). Es akzeptiert alle parametrisierten SELECT-, UPDATE-, INSERT- und DELETE-Abfragen und hilft mir sehr dabei, jede MySQL-DB-Interaktion in meinem PHP-Code dynamisch auszuführen.

    – Mbuster

    23. Januar 2017 um 15:16 Uhr

  • Frühere, klare, vollständige Frage, die genau dasselbe stellt: Verwenden Sie ein Array in einer vorbereiteten mysqli-Anweisung: WHERE .. IN(..) Anfrage

    – mickmackusa

    3. April um 4:59


Benutzer-Avatar
Ihr gesunder Menschenverstand

Seit PHP 8.1 können Sie ein Array direkt zur Ausführung übergeben:

$sql = "INSERT INTO users (email, password) VALUES (?,?)"; // sql
$stmt = $mysqli->prepare($sql); // prepare
$stmt->execute([$email, $password]); // execute with data! 

Für die früheren Versionen ist die Aufgabe etwas aufwendig, aber machbar. Für einen einfachen Fall, in dem Sie bereits eine Abfrage mit Platzhaltern haben, wäre der Code

$sql = "INSERT INTO users (email, password) VALUES (?,?)"; // sql
$data = [$email, $password]; // put your data into array
$stmt = $mysqli->prepare($sql); // prepare
$stmt->bind_param(str_repeat('s', count($data)), ...$data); // bind array at once
$stmt->execute();

Während wir, wie in Ihrem Fall, eine beliebige Anzahl von Platzhaltern haben, müssen wir etwas mehr Code hinzufügen. Die Erklärung entnehme ich meinem Artikel Vorbereitete Mysqli-Anweisung mit mehreren Werten für die IN-Klausel:

  • Zuerst müssen wir eine Zeichenfolge mit so vielen erstellen ? markiert, wie viele Elemente sich in Ihrem Array befinden. Dafür würden wir verwenden str_repeat() Funktion, die für den Zweck sehr praktisch ist.
  • Dann muss dieser String mit Komma-separierten Fragezeichen zur Abfrage hinzugefügt werden. Obwohl es sich um eine Variable handelt, ist sie in diesem Fall sicher, da sie nur konstante Werte enthält
  • dann muss diese Abfrage wie jede andere Abfrage vorbereitet werden
  • dann müssen wir einen String mit Typen erstellen, die mit bind_param() verwendet werden sollen. Beachten Sie, dass es normalerweise keinen Grund gibt, unterschiedliche Typen für die gebundenen Variablen zu verwenden – mysql akzeptiert sie alle gerne als Strings. Es gibt Randfälle, aber extrem selten. Für den täglichen Gebrauch können Sie es immer einfach halten und “s” für alles verwenden. str_repeat() ist wieder zur Rettung.
  • Dann müssen wir unsere Array-Werte an die Anweisung binden. Leider können Sie es nicht einfach so als einzelne Variable schreiben $stmt->bind_param("s", $array)nur skalare Variablen sind erlaubt bind_param(). Zum Glück gibt es eine Argument Entpackoperator das macht genau das, was wir brauchen – sendet ein Array von Werten an eine Funktion, als wäre es eine Menge unterschiedlicher Variablen!
  • Der Rest ist wie gewohnt – führen Sie die Abfrage aus, erhalten Sie das Ergebnis und rufen Sie Ihre Daten ab!

Der richtige Beispielcode wäre also

$array = ['Nashville','Knoxville']; // our array
$in    = str_repeat('?,', count($array) - 1) . '?'; // placeholders
$sql   = "SELECT name FROM table WHERE city IN ($in)"; // sql
$stmt  = $mysqli->prepare($sql); // prepare
$types = str_repeat('s', count($array)); //types
$stmt->bind_param($types, ...$array); // bind array at once
$stmt->execute();
$result = $stmt->get_result(); // get the mysqli result
$data = $result->fetch_all(MYSQLI_ASSOC); // fetch the data   

Obwohl dieser Code ziemlich groß ist, ist er unvergleichlich kleiner als jede andere plausible Lösung, die bisher in diesem Thema angeboten wurde.

  • Ich verstehe den ersten Absatz Ihrer Antwort nicht. Ich denke nicht, dass eine Frage eine Antwort liefern soll, er sucht eine Antwort, die Sie und andere beantwortet haben. Was ich gesucht habe, war nicht, wie viele Fragezeichen ich hinzufügen muss, die ich bereits hatte. Ich konnte keine richtige Erklärung für bind_param finden, da sich das php.net-Dokument anscheinend nicht darum gekümmert hat. Ich wollte wissen, ob ich ein Array als Parameter übergeben kann.

    – AaA

    17. April 2020 um 14:00 Uhr

  • @AaA In meiner Antwort gibt es einen weiteren Absatz, in dem ein Operator zum Entpacken von Argumenten erwähnt wird. hat es deine Frage beantwortet?

    – Ihr gesunder Menschenverstand

    18. April 2020 um 3:39 Uhr


  • Danke, das “Argument unpacked operator” war für mich die Antwort. Diese Antwort löst viele andere ähnliche Fragen mit sehr ausgearbeiteten Lösungen.

    – Marco Muciño

    23. Juli 2020 um 22:02 Uhr

  • das funktioniert nicht.$stmt->bind_param($paramstring, $params ); Gib mir Array to string conversion jedes Mal

    – djack109

    31. Dezember 2020 um 17:01 Uhr

Benutzer-Avatar
moskito-x

Sie können nicht zwei Variablen mit einer binden question mark !

Für jede Variable, die Sie binden, benötigen Sie eine question mark

„bind_param“ prüft jede Variable, ob sie den Anforderungen entspricht. danach wird der Stringwert in Anführungszeichen gesetzt.

Das wird nicht funktionieren.

"SELECT name FROM table WHERE city IN (?)"; ( becomes too )
$q_prepared->bind_param("s", $cities);
"SELECT name FROM table WHERE city IN ('city1,city2,city3,city4')";

muss sein.

"SELECT name FROM table WHERE city IN (?,?,?,?)"; ( becomes too )
$q_prepared->bind_param("ssss", $city1,$city2,$city3,$city4);
"SELECT name FROM table WHERE city IN ('city1','city2','city3','city4')";

$query_prepared->bind_param setzt String-Parameter einzeln in Anführungszeichen.
Und die Anzahl der Variablen und die Länge der Zeichenfolgentypen müssen mit den Parametern in der Anweisung übereinstimmen.

$query_str= "SELECT name FROM table WHERE city IN ('Nashville','Knoxville')";

wird werden

$query_str= "SELECT name FROM table WHERE city IN (?,?)";

jetzt bind_param muss sein

bind_param("ss",$arg1,$arg2)

mit diesem

$query_str= "SELECT name FROM table WHERE city IN (?)";

und bind_param mit

bind_param("s",$cities)

du erhältst

$query_str= "SELECT name FROM table WHERE city IN ('Nashville,Knoxville')";

Deshalb funktioniert ein Array nicht.
Die einzige Lösung für diese Tatsache ist call_user_func_array

Wenn Sie eine Anweisung einleiten, ist Folgendes nicht erforderlich

$query_prepared = $mysqli->stmt_init();
if($query_prepared && $query_prepared->prepare($query_str)) {

Das ist richtig

$query_prepared = $mysqli->stmt_init();
if($query_prepared->prepare($query_str)) {

wenn Sie nicht verwenden möchten call_user_func_array

und Sie haben nur eine kleine Anzahl von Argumenten
Sie können dies mit dem folgenden Code tun.

[...]
$cities= explode(",", $_GET['cities']);
if (count($cities)>3) { echo "too many arguments"; }
else
{ 
$count = count($cities); 
$SetIn = "(";
  for($i = 0; $i < $count; ++$i) {    
      $code.='s';
      if ($i>0) {$SetIn.=",?";} else {$SetIn.="?";}
  }
$SetIn.=")";
$query_str= "SELECT name FROM table WHERE city IN ".$SetIn;
// with 2 arguments $query_str will look like
// SELECT name FROM table WHERE city IN (?,?)
$query_prepared = $mysqli->stmt_init();
if($query_prepared->prepare($query_str))
  {       
    if ($count==1) { $query_prepared->bind_param($code, $cities[0]);}
    if ($count==2) { $query_prepared->bind_param($code, $cities[0],$cities[1]);}
    if ($count==3) { $query_prepared->bind_param($code, $cities[0],$cities[1],$cities[2]);
    // with 2 arguments $query_prepared->bind_param() will look like
    // $query_prepared->bind_param("ss",$cities[0],$cities[1])      
  }    

    $query_prepared->execute();
  } 
 [...]
 }

Ich würde vorschlagen, dass Sie es mit versuchen call_user_func_array erreichen.

Suche nach der Lösung von nick9v
mysqli-stmt.bind-param

  • Sie schlagen vor zu verwenden call_user_func_array aber du zeigst es hier nie, wie es geht. =_=’

    – ggDeGreat

    24. Oktober 2015 um 5:24 Uhr

  • Hier ist ein Anwendungsfall von call_user_func_array und das ganze Problem erklärt pontikis.net/blog/dynamically-bind_param-array-mysqli

    – Mochi

    11. April 2020 um 10:09 Uhr

  • „Bei der Verwendung von mysqli_stmt_bind_param() in Verbindung mit call_user_func_array() ist Vorsicht geboten. Beachten Sie, dass mysqli_stmt_bind_param() die Übergabe von Parametern als Referenz erfordert, während call_user_func_array() als Parameter eine Liste von Variablen akzeptieren kann, die Referenzen oder Werte darstellen können. ” Quelle -> php.net/manual/en/mysqli-stmt.bind-param.php

    – Ich bemühe mich so sehr, aber ich weine stärker

    3. Juli 2020 um 18:20 Uhr

Verwenden Sie call_user_func_array wie folgt:

$stmt = $mysqli->prepare("INSERT INTO t_file_result VALUES(?,?,?,?)");

$id = '1111';
$type = 2;
$result = 1;
$path="/root";

$param = array('siis', &$id, &$type, &$result, &$path);
call_user_func_array(array($stmt, 'bind_param'), $param);

$stmt->execute();

printf("%d row inserted. \n", $stmt->effected_rows);
$stmt->close;

  • Wenn Sie der Dokumentation weitere Erklärungen und Quellen hinzufügen, wird dies mit Sicherheit akzeptiert! schöne antwort hier!

    – Gonaties

    27. Mai 2017 um 21:28 Uhr

  • Das wird nicht funktionieren, alle Parameter müssen Referenzen sein. Sie müssen also das Format wie in definiert haben $format = "siis"; und dann in dem Array, das Sie verwenden &$format. Alle Parameter müssen Referenzen sein.

    – Alexis Wilke

    22. Juli 2017 um 9:22 Uhr

Benutzer-Avatar
Mike32

Ab PHP-Version 8.1, Bindung ist nicht mehr erforderlich. Wie bei PDO seit Version 5.0 können Sie jetzt Parameter als Array direkt an übergeben die Ausführungsmethode.

$mysqli       = new mysqli("localhost", "root", "root", "db");
$params       = ['Nashville','Knoxville'];
$placeholders = str_repeat('?,', count($params) - 1) . '?'
$query        = "SELECT name FROM table WHERE city IN ($placeholders)";
$stmt         = $mysqli->prepare($query);

$stmt->execute($params);

Ein weiteres Beispiel, wenn Sie ein assoziatives Array mit Schlüsseln haben, die mit Spaltennamen übereinstimmen:

$mysqli       = new mysqli("localhost", "root", "root", "db");
$data         = ["bar" => 23, "baz" => "some data"];
$params       = array_values($data);
$placeholders = str_repeat('?,', count($params) - 1) . '?'
$columns      = implode("`,`", array_keys($data));
$query        = "INSERT INTO foo (`$columns`) VALUES ($placeholders)";
$stmt         = $mysqli->prepare($query);

$stmt->execute($params);

Erwähnenswert ist auch, dass die Bibliothek jetzt Vorgabe um im Fehlerfall Ausnahmen auszulösen. Vor Version 8.1 war dies nicht der Fall.

Ich hatte auch Probleme damit und habe es zum Laufen gebracht eval bevor Sie herausfinden, dass die meisten Menschen es verwenden call_user_func_array

$fields = array('model','title','price'); // fields in WHERE clause
$values = array( // type and value for each field
    array('s','ABCD-1001'),
    array('s','[CD] Test Title'),
    array('d','16.00')
);
$sql = "SELECT * FROM products_info WHERE "; // start of query
foreach ($fields as $current){ // build where clause from fields
    $sql .= '`' . $current . '` = ? AND ';
}
$sql = rtrim($sql,'AND '); // remove last AND 
$stmt = $db->prepare($sql);
$types=""; $vals="";
foreach ($values as $index => $current_val){ // build type string and parameters
    $types .= $current_val[0];
    $vals .= '$values[' . $index . '][1],';
}
$vals = rtrim($vals,','); // remove last comma
$sql_stmt="$stmt->bind_param("" . $types . '",' . $vals . ');'; // put bind_param line together
eval($sql_stmt); // execute bind_param
$stmt->execute();
$stmt->bind_result($col1,$col2,$col3,$col4,$col5,$col6); // this could probably also be done dynamically in the same way
while ($stmt->fetch()){
    printf("%s %s %s %s %s %s\n", $col1,$col2,$col3,$col4,$col5,$col6);
}

  • Erfordert definitiv etwas Spielerei, aber ich mag diese Antwort wirklich sehr. Es kann ein bisschen voluminöser sein als call_user_func_array aber es ist ehrlich gesagt einfacher zu lesen und herauszufinden, was los ist.

    – Ethan Moore

    20. Juli 2020 um 0:35 Uhr

So habe ich es gemacht: Bereite die Abfrage mit all ihren separaten Fragezeichen sowie dem Typ String vor.

$cities = array('Nashville','Knoxville');
$dibs="";
$query = "SELECT name FROM table WHERE city IN (";
$marks = array();

foreach ($cities as $k => $city) {
    // i,s,b,d type based on the variables to bind.
    $dibs .= 's';
    array_push($marks, '?');
}

$query .= implode(',', $marks) .')';

Verbinden.

$mysql = new mysqli($host, $user, $pass, $dbname);
$statement =
    $mysql->prepare($query)
OR  die(sprintf(
        'Query error (%s) %s', $mysql->errno, $mysql->error
    ))
;

Dann verwenden Sie “…” Token / Ellipse (Dokumentation), um das Array zu binden.

if ($statement) {
    $statement->bind_param($dibs, ...$cities);
    $statement->execute();

    $statement->close();
}
$mysql->close();

Ich weiß, dass es irgendwie den Zweck der Bindung zunichte macht, um zu entkommen (aber zumindest funktioniert es gut mit einer Liste von ganzen Zahlen, dh IDs). Wenn Sie eine Möglichkeit sehen, diesen Ansatz zu verbessern, können Sie ihn gerne bearbeiten/kommentieren.

  • Erfordert definitiv etwas Spielerei, aber ich mag diese Antwort wirklich sehr. Es kann ein bisschen voluminöser sein als call_user_func_array aber es ist ehrlich gesagt einfacher zu lesen und herauszufinden, was los ist.

    – Ethan Moore

    20. Juli 2020 um 0:35 Uhr

Benutzer-Avatar
Jennifer

Dies habe ich getan, nachdem ich die Formulareingaben genauso benannt hatte wie die mysql-Spaltennamen.

$post_fields = array_keys($_POST);
$post_values = array_values($_POST);

$fields_type_i = array("age","age_share","gender_share");  // all mysql col names type int

$fields = "";           // user input fields
$values = "";           // user input vals
$placeholders = "";     // ?,?,?
$params_type = "";      // s=string i=integer

foreach ($post_fields as $field) {
    $fields .= "`".$field."`,"; 
}

for ($i=0;$i<count($post_fields);$i++) {      // bind i and s param types
    $placeholders .= "?,";
    if (in_array($post_fields[$i],$fields_type_i)) {        
        $params_type .= "i";    
    } else {                                            
        $params_type .= "s";
    }
    $values .= $post_values[$i];
}

ODER

for ($i=0;$i<count($post_fields);$i++) {        // binding only s param type
    if (in_array($post_fields[$i],$fields_type_i)) {
        $placeholders .= $post_values[$i].",";  
    } else {
        $placeholders .= "?,";
        $params_type .= "s";
        $values .= $post_values[$i];
    }
}

$fields = rtrim($fields,",");  // removing last commas
$values = rtrim($values,",");
$placeholders = rtrim($placeholders,",");

$params_string = $params_type.','.$values;
$params_vals = explode(",",$params_string);  // array of vals

$params_refs = array();
foreach($params_vals as $key => $value) $params_refs[$key] = &$params_vals[$key];  // array of refs

$stmt = $mysqli -> prepare('INSERT INTO pets ('.$fields.') VALUES ('.$placeholders.')');

if ($stmt && call_user_func_array(array($stmt, 'bind_param'), $params_refs) && $stmt -> execute()) {
    echo 'Success';
} else {
    echo $stmt -> error;
}

1019020cookie-checkWie binde ich ein Array von Strings mit einer vorbereiteten mysqli-Anweisung?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy