我无法让这个工作。我现在已经花了很多时间。
这有效:
$mysqli = new mysqli("localhost", "root", "root", "db");
if(!$mysqli || $mysqli->connect_errno)
{
return;
}
$query_str= "SELECT name FROM table WHERE city IN ('Nashville','Knoxville')";
if($query_prepared && $query_prepared->prepare($query_str))
{
$query_prepared->execute();
但是我无法使用这样的bind_param:
$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();
我做错了什么?
我也尝试了 call_user_func_array ,但似乎无法正确理解语法。 任何帮助将不胜感激!
编辑: 我已经严格尝试了moskito-x的建议和大量的例子列在这里以及SO和随机网站的哪些地方,没有任何效果。我认为问题可能是PHP 5.4,这就是我的MAMP现在设置的。
答案 0 :(得分:10)
您不能将两个变量绑定到一个question mark
!
对于您绑定的每个变量,您需要一个question mark
“bind_param”检查每个变量是否符合要求。之后,字符串值放在引号之间。
这不起作用。
"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')";
必须是。
"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
逐个引用字符串参数
并且变量的数量和字符串类型的长度必须与语句中的参数匹配。
$query_str= "SELECT name FROM table WHERE city IN ('Nashville','Knoxville')";
将成为
$query_str= "SELECT name FROM table WHERE city IN (?,?)";
现在bind_param
必须
bind_param("ss",$arg1,$arg2)
用这个
$query_str= "SELECT name FROM table WHERE city IN (?)";
和bind_param
与
bind_param("s",$cities)
你得到了
$query_str= "SELECT name FROM table WHERE city IN ('Nashville,Knoxville')";
这就是阵列不起作用的原因
这个事实的唯一解决方案是call_user_func_array
如果您初始化声明,则不必执行以下操作
$query_prepared = $mysqli->stmt_init();
if($query_prepared && $query_prepared->prepare($query_str)) {
这是正确的
$query_prepared = $mysqli->stmt_init();
if($query_prepared->prepare($query_str)) {
如果您不想使用call_user_func_array
而且你只有少量的论点
你可以使用以下代码来完成它。
[...]
$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();
}
[...]
}
我建议您尝试使用call_user_func_array
来覆盖。
寻找nick9v
的解决方案
mysqli-stmt.bind-param
答案 1 :(得分:7)
这个问题经常发生,这个问题太老了,无法提供远程可靠的解决方案,但Google仍然将访问者发送到这里。因此,这是2019年及以后的答案。
我将从文章Mysqli prepared statement with multiple values for IN clause中获得解释:
- 首先,我们需要创建一个带有
?
标记的字符串,该标记与数组中的元素数一样多。为此,我们将使用str_repeat()
函数,该函数非常方便。- 然后必须将带有逗号分隔的问号的字符串添加到查询中。尽管它是一个变量,但在这种情况下它是安全的,因为它仅包含常数值
- 然后必须像其他任何查询一样准备该查询
- 然后,我们将需要创建一个字符串,该字符串的类型将与bind_param()一起使用。注意,通常没有理由对绑定变量使用不同的类型-mysql会很乐意接受它们全部作为字符串。有边际案例,但极为罕见。对于日常使用,您可以始终保持简单,并在所有内容中使用“ s”。
str_repeat()
再次获救。- 然后我们需要将数组值绑定到该语句。不幸的是,您不能像
$stmt->bind_param("s", $array)
这样将其写为单个变量,bind_param()
中仅允许标量变量。幸运的是,有一个argument unpacking operator可以完全满足我们的需要-将值的数组发送到函数中,就好像它是一组不同的变量一样!- 其余一切照常-执行查询,获取结果并获取数据!
因此正确的示例代码为
$array = ['Nashville','Knoxville']; // our array
$in = str_repeat('?,', count($array) - 1) . '?'; // placeholders
$sql = "SELECT name FROM table WHERE city IN ($in)";
$stmt = $mysqli->prepare($sql);
$types = str_repeat('s', count($array));
$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
尽管此代码相当大,但与迄今为止在本主题中提供的任何其他合理的解决方案相比,它是无与伦比的。
答案 2 :(得分:5)
像这样使用call_user_func_array:
$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;
答案 3 :(得分:1)
我这样做的方式:使用所有单独的问号以及类型字符串来准备查询。
$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) .')';
连接。
$mysql = new mysqli($host, $user, $pass, $dbname);
$statement =
$mysql->prepare($query)
OR die(sprintf(
'Query error (%s) %s', $mysql->errno, $mysql->error
))
;
if ($statement) {
$statement->bind_param($dibs, ...$cities);
$statement->execute();
$statement->close();
}
$mysql->close();
我知道这样做有点违反了为了逃避绑定的目的(但至少对整数列表(即ID)有效)。如果您发现了改进此方法的方法,请随时进行编辑/注释。
答案 4 :(得分:0)
我也遇到了麻烦,并且在发现大多数人正在使用eval
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);
}
答案 5 :(得分:-1)
这是命名表单输入后与mysql列名相同的操作。
$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];
}
OR
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;
}