php - uncaught - Utilice un bind_param() con un número variable de variables de entrada
stmt execute() php (5)
Intento utilizar un enlace variable como este:
$stmt = $mysqli->prepare("UPDATE mytable SET myvar1=?, myvar2=... WHERE id = ?")) {
$stmt->bind_param("ss...", $_POST[''myvar1''], $_POST[''myvar2'']...);
pero algunos de los $ _POST [''...''] podrían estar vacíos, así que no quiero actualizarlos en el DB.
No es práctico tener en cuenta todas las diferentes combinaciones de vacío $ _POST [''...''] y aunque puedo construir la cadena "ACTUALIZAR mi SET FIJADO ..." a mis necesidades, bind_param () es una bestia diferente.
Podría intentar construir su llamada como una cadena y usar eval () pero no se siente bien :(
Es marginalmente más claro construir tu extracto usando una matriz:
$params = array();
$fragments = array();
foreach($_POST as $col => $val)
{
$fragments[] = "{$col} = ?";
$params[] = $val;
}
$sql = sprintf("UPDATE sometable SET %s", implode(", ", $fragments));
$stmt = $mysqli->prepare($sql);
$stmt->bind_param($params);
Esto es lo que uso para hacer declaraciones preparadas de mysqli con una cantidad variable de params. Es parte de una clase que escribí. Es exageradamente exagerado para lo que necesita, pero debe mostrarle la dirección correcta.
public function __construct($con, $query){
$this->con = $con;
$this->query = $query;
parent::__construct($con, $query);
//We check for errors:
if($this->con->error) throw new Exception($this->con->error);
}
protected static $allowed = array(''d'', ''i'', ''s'', ''b''); //allowed types
protected static function mysqliContentType($value) {
if(is_string($value)) $type = ''s'';
elseif(is_float($value)) $type = ''d'';
elseif(is_int($value)) $type = ''i'';
else throw new Exception("type of ''$value'' is not string, int or float");
return $type;
}
//This function checks if a given string is an allowed mysqli content type for prepared statement (s, d, b, or i)
protected static function mysqliAllowedContentType($s){
return in_array($s, self::$allowed);
}
public function feed($params){
//These should all be empty in case this gets used multiple times
$this->paramArgs = array();
$this->typestring = '''';
$this->params = $params;
$this->paramArgs[0] = '''';
$i = 0;
foreach($this->params as $value){
//We check the type:
if(is_array($value)){
$temp = array_keys($value);
$type = $temp[0];
$this->params[$i] = $value[$type];
if(!self::mysqliAllowedContentType($type)){
$type = self::mysqliContentType($value[$type]);
}
}
else{
$type = self::mysqliContentType($value);
}
$this->typestring .= $type;
//We build the array of values we pass to the bind_params function
//We add a refrence to the value of the array to the array we will pass to the call_user_func_array function. Thus say we have the following
//$this->params array:
//$this->params[0] = ''foo'';
//$this->params[1] = 4;
//$this->paramArgs will become:
//$this->paramArgs[0] = ''si''; //Typestring
//$this->paramArgs[1] = &$this->params[0];
//$this->paramArgs[2] = &$this->params[1].
//Thus using call_user_func_array will call $this->bind_param() (which is inherented from the mysqli_stmt class) like this:
//$this->bind_param( ''si'', &$this->params[0], &$this->params[1] );
$this->paramArgs[] = &$this->params[$i];
$i++;
}
unset($i);
$this->paramArgs[0] = $this->typestring;
return call_user_func_array(array(&$this, ''bind_param''), $this->paramArgs);
}
Lo usas así:
$prep = new theClassAboveHere( $mysqli, $query );
$prep->feed( array(''string'', 1, array(''b'', ''BLOB DATA'') );
La clase debería extender la clase mysqli_stmt.
Espero que esto te ayude en la dirección correcta.
Si quieres, también podría publicar toda la clase, incluye enlaces de resultados variables.
Puede usar la función call_user_func_array
para llamar al método bind_param
con un número variable o argumentos:
$paramNames = array(''myvar1'', ''myvar2'', /* ... */);
$params = array();
foreach ($paramNames as $name) {
if (isset($_POST[$name]) && $_POST[$name] != '''') {
$params[$name] = $_POST[$name];
}
}
if (count($params)) {
$query = ''UPDATE mytable SET '';
foreach ($params as $name => $val) {
$query .= $name.''=?,'';
}
$query = substr($query, 0, -1);
$query .= ''WHERE id = ?'';
$stmt = $mysqli->prepare($query);
$params = array_merge(array(str_repeat(''s'', count($params))), array_values($params));
call_user_func_array(array(&$stmt, ''bind_param''), $params);
}
array_insert no existe, supongo que se refiere a alguna función casera, pero no estoy seguro de qué es exactamente lo que hace ... inserta los tipos de parámetros en la matriz en algún lugar al principio, lo adivinaría ya que se pasa el valor 0 pero bueno, podría ser al final también;)
Constrúyalo como una cadena, pero ponga sus valores en una matriz y páselos a bindd_param. (y sustituya? s por valores en su cadena de SQL.
$ stmt = $ mysqli-> prepare ("UPDATE mytable SET myvar1 = ?, myvar2 = ... WHERE id =?")) {$ stmt-> bind_param ("ss ...", $ _POST [''myvar1''] , $ _POST [''myvar2''] ...);
Por ejemplo:
$args = array();
$sql = "UPDATE sometable SET ";
$sep = "";
$paramtypes = "";
foreach($_POST as $key => $val) {
$sql .= $sep.$key." = ''?''";
$paramtypes .= "s"; // you''ll need to map these based on name
array_push($args, $val);
$sep = ",";
}
$sql .= " WHERE id = ?";
array_push($args, $id);
array_insert($args, $paramtypes, 0);
$stmt = $mysqli->prepare($sql);
call_user_func_array(array(&$stmt, ''bindparams''), $array_of_params);
$stmt->bind_param($args);