Come posso mettere i risultati di una dichiarazione MySQLi preparata in un array associativo?
-
13-09-2019 - |
Domanda
Ho una query SQL e una dichiarazione preparata mysqli:
$sql = 'SELECT photographers.photographer_id, photographers.photographer_name
FROM photographers';
$stmt = $conn->stmt_init();
if ($stmt->prepare($sql)) {
$stmt->bind_result($photographer_id, $photographer_name);
$OK = $stmt->execute();
$stmt->fetch();
}
Come faccio a memorizzare i risultati in un array associativo in modo da posso ciclo più tardi e arrivare a tutti i dati restituiti dalla stringa sql?
Soluzione
Provare quanto segue:
$meta = $statement->result_metadata();
while ($field = $meta->fetch_field()) {
$params[] = &$row[$field->name];
}
call_user_func_array(array($statement, 'bind_result'), $params);
while ($statement->fetch()) {
foreach($row as $key => $val) {
$c[$key] = $val;
}
$hits[] = $c;
}
$statement->close();
Per prima cosa è ottenere i metadati di query e da quello di ottenere tutti i campi che avete recuperato (si può fare manualmente, ma questo codice funziona per tutte le query piuttosto che costruire a mano). call_user_func_array()
funzione chiama la funzione mysqli_stmt::bind_result()
per voi su ciascuno di tali parametri.
Dopo che è solo una questione di esecuzione attraverso ogni riga e creando un array associativo per ogni riga e aggiungendo che a un array con conseguente tutti i risultati.
Altri suggerimenti
Aggiornamento:. Dal PHP 5.3.0 è possibile ottenere un oggetto mysqli_result che fornisce un metodo fetch_array
$sql = 'SELECT photographers.photographer_id, photographers.photographer_name
FROM photographers';
$data = null;
$stmt = $conn->stmt_init();
if ($stmt->prepare($sql)) {
$stmt->bind_result($photographer_id, $photographer_name);
$OK = $stmt->execute();
$result = $stmt->get_result();
$data = $result->fetch_array();
}
Documentazione: http://php.net/manual/en/ mysqli-stmt.get-result.php
Mi sono imbattuto in questa discussione, al fine di trovare una soluzione per ottenere i dati da MySQLi istruzioni preparate senza l'mysqlnd. Ho sviluppato una classe per la gestione di istruzioni preparate con MySQLi in un modo pratico. Si prega, date un'occhiata al codice, o semplicemente utilizzarlo (vedere un esempio di utilizzo, alla fine del pezzo di codice) di scrivere velocemente istruzioni preparate e ottenere i suoi risultati.
class DbUtils {
private $host;
private $user;
private $pass;
private $database;
private $connection;
public function __construct($host, $user, $pass, $database) {
$this->host = $host;
$this->user = $user;
$this->pass = $pass;
$this->database = $database;
$this->connection = new mysqli($host, $user, $pass, $database);
}
public function query(Array $params) {
$args = array();
// 0. Correct the input function parameters
if (array_key_exists("query", $params)) {
$args["query"] = $params["query"];
} else {
throw new Exception("Parameter not found: 'query'.");
}
if (array_key_exists("types", $params)) {
$args["types"] = $params["types"];
} else {
$args["types"] = '';
}
if (array_key_exists("input", $params)) {
$args["input"] = $params["input"];
} else {
$args["input"] = array();
}
// 1. Check the connection:
if ($this->connection->connect_errno) {
echo "Connection to MySQL failed: [" . $this->connection->connect_errno . "]: " . $this->connection->connect_error . "<br/>";
}
// 2. Prepare the sentence:
if (!($stmt = $this->connection->prepare($args["query"]))) {
echo "Prepared statement failed: [" . $stmt->errno . "]: " . $stmt->error . "<br/>";
}
// 3. Bind the input parameters:
if ( ( 0 != sizeof( $args["input"] ) ) && !(call_user_method_array("bind_param", $stmt, array_merge(array($args["types"]), $args["input"])))) {
echo "Binding parameters failed: [" . $stmt->errno . "]: " . $stmt->error . "<br/>";
}
// 4. Execute the sentence
if (!($stmt->execute())) {
echo "Sentence execution failed: [" . $stmt->errno . "]: " . $stmt->error . "<br/>";
}
// 5. Bind the results:
$data = array();
$meta = $stmt->result_metadata();
$row = array();
while( $field = $meta->fetch_field() ) {
$argos[] = &$row[$field->name];
}
call_user_method_array('bind_result', $stmt, $argos);
// 6. Collect the results:
while ($stmt->fetch()) {
foreach($argos as $key => $val) {
$dataItem[$key] = $val;
}
$data[] = $dataItem;
}
// 7. Close the sentence:
$stmt->close();
// 8. Return interesting data properly ordered:
return $data;
}
}
// 1. Instantiate it:
$dbUtils = new DbUtils(
"127.0.0.1",
"user",
"password",
"database"
);
// 2. Query prepared statements like this:
$users = $dbUtils->query(array(
"query" => "SELECT * FROM user WHERE name LIKE ? AND pass LIKE ?;",
"input" => array('%', '%'),
"types" => 'ss'
));
// 3. Enjoy securely CRUD Ops!
Stranamente, non si può. Non c'è alcun modo per ottenere un oggetto mysqli_result da un'istanza mysqli_stmt. Ho sempre considerato questo un grave difetto, e immagino che questo è uno dei motivi principali che mysqli non ha mai raggiunto una vera popolarità. In questi giorni è stato praticamente sostituiti da DOP, che fa quello che si vuole con uno sforzo fuori.
Modifica La mia risposta significa solo che non si può fare di default. Naturalmente è possibile implementare da soli, come Chris suggerito. Eppure, penso che si dovrebbe usare DOP, invece, se è possibile.
Se non è possibile utilizzare l'estensione PDO. O si hanno difficoltà a costruire la vostra classe di database con le istruzioni preparate. Come utilizzare per l'aggiornamento inserire, cancellare e inserire:
$db = new database();
$db->query = "INSERT INTO blabla (name,date,number) VALUES(?,?,?)";
$db->params = array($name,$date,$number);
$db->type = 'ssi'; //s=string,i=integer
if($db->insert())
echo 'success';
Fetch funziona un po 'diverso
$array = array();
$db = new database();
$db->query = "SELECT * FROM blabla WHERE id=? and someother=?";
$db->params = array($id,$other);
$db->type = 'is';
$r = $db->fetch();
//$r[0]['id'] for row 1
//$r[0]['name'] for row 1
//$r[1] .... For row 2
//$r[2] .... For row 3
//etc...
Ora, per la classe di database
class database {
private $stmt;
private $mysqli;
private $query;
private $params = array();
private $type;
public function __set($name, $value) {
switch ($name) {
case 'params':
$this->params = $value;
break;
case 'query':
$this->query = $value;
break;
case 'type':
$this->type = $value;
break;
default:
break;
}
}
public function __get($name) {
if ($name !== "mysqli" && $name !== "stmt")
return $this->$name;
}
public function __construct() {
$this->mysqli = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME, DB_PORT);
$this->stmt = $this->mysqli->stmt_init();
}
private function close_con($bool) {
if ($bool) {
$this->stmt->free_result();
}
$this->stmt->close();
$this->mysqli->close();
}
private function nofetch() {
$this->stmt->prepare($this->query);
$bind_names[] = $this->type;
for ($i = 0; $i < count($this->params); $i++) {
$bind_name = 'bind' . $i;
$$bind_name = $this->params[$i];
$bind_names[] = &$$bind_name;
}
call_user_func_array(array($this->stmt, "bind_param"), $bind_names);
if ($this->stmt->execute()) {
$this->close_con(false);
return true;
}
$this->close_con(false);
return false;
}
public function insert() {
if ($this->nofetch()) {
return true;
}
return false;
}
public function update() {
if ($this->nofetch()) {
return true;
}
return false;
}
public function delete() {
if ($this->nofetch()) {
return true;
}
return false;
}
public function fetch() {
$result_out = array();
$this->stmt->prepare($this->query);
$bind_names[] = $this->type;
if (count($this->params) > 0) {
for ($i = 0; $i < count($this->params); $i++) {
$bind_name = 'bind' . $i;
$$bind_name = $this->params[$i];
$bind_names[] = &$$bind_name;
}
call_user_func_array(array($this->stmt, "bind_param"), $bind_names);
}
if ($this->stmt->execute()) {
$result = $this->stmt->result_metadata();
$cols = $result->fetch_fields();
foreach ($cols as $col) {
$name = str_replace("-", "_", $col->name);
$$name = null;
if ($name == null)
$name = 'name';
$bindarray[$name] = &$$name;
}
call_user_func_array(array($this->stmt, 'bind_result'), $bindarray);
$this->stmt->store_result();
$copy = create_function('$a', 'return $a;');
while ($this->stmt->fetch()) {
$result_out[] = array_map($copy, $bindarray);
}
}
$this->close_con(true);
return $result_out;
}
}
Spero che questo è utile
Un semplice quello che funziona in realtà sorprendentemente. Lo so che è procedurale, ma ancora:
$query = "SELECT * FROM foo WHERE bar = ?;";
$stmt = mysqli_prepare($dbc, $query);
mysqli_stmt_bind_param($stmt, "s", $bar);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
return mysqli_fetch_assoc($result);
https://stackoverflow.com/users/5849505/carl-gentleman
La sua risposta è un modo per le versioni precedenti di PHP come "call_user_method_array" è stata sconsigliata a PHP 4.1.0 e PHP 7.0.0 rimossa in.
Così mi trovo rilevante per inviare una risposta aggiornata, per almeno PHP7, dal momento che ho di recente mi sono trovato senza il driver nativo MYSQLND per l'estensione mysqli su un nuovo host che ho trasferito a. Yay! ...
Nota: Ci sono 2 funzioni qui. è necessario l'ultimo. E 'l'unico modo che conosco tutto di lavorare. (MODIFICA La risposta non produce un array associativo ... Fisso)
public function arr($query, $data, $format) { // Some parts have been used from others. I don't know who.
$d = array();
$row = array();
// 1. Connect to the database // This is how I do it
$db = $this->con;
// 2. Prepare the sentence:
if( !($stmt = $db->prepare($query)) ) {
echo "Prepared statement failed: [" . $stmt->errno . "]: " . $stmt->error . "<br>";
$d[0] = false;// I return an object array so [0] I can check later. It is true or false however I define it.
return $d;
}
// cast to array
$data = (array) $data;
$format = (array) $format;
//Normalize format
$format = implode('', $format);
$format = str_replace('%', '', $format);
// Prepend $format onto $values
array_unshift($data, $format);
// 3. Bind the input parameters: (note "call_user_func_array" is not depriciated)
if ( !(call_user_func_array( array( $stmt, 'bind_param'), $this->ref_values($data) )) ) {
echo "Binding parameters failed: [" . $stmt->errno . "]: " . $stmt->error . ";<br>";
}
// 4. Execute the sentence
if ( !($stmt->execute()) ) {
echo "Sentence execution failed: [" . $stmt->errno . "]: " . $stmt->error . ";<br>";
}
// 5. Prepare to Bind the results:
$meta = $stmt->result_metadata();
while( $field = $meta->fetch_field() ) {
$argos[] = &$row[$field->name];
$fld_nms[] = $field->name;
}
// 6. Bind the results to the argos array:
call_user_func_array( array( $stmt, 'bind_result'), $argos);
/* // I left some debuging tools that are helpful
echo "<br>argos<br>";
print_r($argos);
echo "<br><br>";
$class_methods = get_class_methods($stmt);
foreach ($class_methods as $method_name) {
echo "$method_name<br>";
}
*/
// 7. Collect the results:
while ($ftch = $stmt->fetch()) {
$dataItem = array();
/*
echo "<br>ftch<br>";
print_r($ftch);
echo "<br><br>";
*/
foreach($argos as $key => $val) {
echo "Args: k:" . $key . "; v:" . $val . ";<br>";
$nme = $fld_nms[$key];
$dataItem[$nme] = $val;
//$dataItem[$key] = $val;
}
$d[] = $dataItem; // I am not interested in returning the multi level array yet but I left it
}
// 8. Close the sentence:
$stmt->close();
// 9. Return interesting data properly ordered:
return $d;
}
private function ref_values($array) {
$refs = array();
foreach ($array as $key => $value) {
$refs[$key] = &$array[$key];
}
return $refs;
}