【问题标题】:PHP how to extract keys names and values from associative array for mysql queryPHP如何从关联数组中提取键名和值以进行mysql查询
【发布时间】:2017-07-28 08:05:04
【问题描述】:

您好,我已经尝试了这两个问题的解决方案(最终目标添加在底部)

INSERT array - PDO

Binding values from arrays?

但我在 $fields 和 $newdata 中没有得到预期的变量内容

所以我请在这里打印一些 var_dump 并投射以请求您的支持。

我的数组来自一个 html 表格

为了简化我的学习实验,我使用了一个只有 5 个字段的虚拟表,如您所见:selecteduser_iduser_nameuser_companyuser_email。 最后我只插入了 2 行值。

表格内容以 JSON.stringify 形式发布。

这是我的结果

正常使用

print_r ( $Arr );

我可以看到这个输出

Array ( 
[0] => Array ( [selected] => [user_id] => 3 [user_name] => nome3 [user_company] => azien3 [user_email] => email3 ) 
[1] => Array ( [selected] => 1 [user_id] => 6 [user_name] => nome6 [user_company] => azien6 [user_email] => email6 ) 
)

接下来我尝试应用上面两个问题的代码

24  $fields = implode(",", array_keys($Arr));
25  $newdata = "'" . implode("','", $Arr) . "'";
26  
27  var_dump($fields);
28  echo "<br><br>";
29  var_dump($newdata);

但是我的解释或我的代码有问题,因为输出是

注意:第 25 行 D:\xampp\htdocs\ajax-json\post.php 中的数组到字符串转换

注意:第 25 行 D:\xampp\htdocs\ajax-json\post.php 中的数组到字符串转换
字符串(3)“0,1”

string(15) "'数组','数组'"

你能指出什么是错的吗? 例如我的数组是否正确形成?

最终目标是构建一个查询,其中它们将从关联数组中获取的键名和键值直接绑定到用于 INSERT 到 mysql 表中的列和值。

换句话说,由于数组的键名与数据库表的列名相同,我想知道如何自动创建查询,就像本问题开头的两个问题一样。

使用“自动化”意味着拥有变量和可能循环来构建查询而不是编写单个列名称并且对于要插入的列值相同


编辑:从接受的答案来看,这是工作代码。
$my_keys = array_keys($Arr[0]);

// ---- This prevents PDO SQL Injection
$stmt=$pdo->prepare("DESC my_table");
$stmt->execute();
$whitelist_columns=$stmt->fetchAll(PDO::FETCH_COLUMN);
foreach($my_keys as $key){
    if(!array_search($key,$whitelist_columns)){ echo "ERROR!"; }
}
// ---- End of prevention

$field_names = implode(",", $my_keys);   // build column list

/** @JBH this foreach is needed otherwise the $q_markers will result not PDO placeholders like.
If this is missing, the query inserts all "" values, no matter if you'll adopt bindValue or bindParam**/
foreach($my_keys as &$key){
    $key = ":".$key; 
}
$q_markers = implode(",", $my_keys);     // build PDO value markers

$stmt = $pdo->prepare("INSERT INTO my_table (".$field_names.") VALUES (".$q_markers.")");
foreach($Arr as $key => $val){
    foreach($val as $bind_marker => &$bind_val){   /** @ JBH Without "&" here, it will work 
only bindValue. Instead with "&", they work both bindParam and bindValue **/
        $stmt->bindParam($bind_marker, $bind_val);  
    }
    $stmt->execute();
}

【问题讨论】:

  • 您对 $newdata 有什么期望?您正在尝试内爆两个数组,这是您无法做到的。您是否要内爆每个阵列? $Arr[0] 和 $Arr[1]?即使这样也不对。您不能内爆关联数组。请输入您希望看到的示例。
  • $Arr 是一个多维数组。它的行为与您的预期不同。
  • 嗯,最终目标是构建一个查询,其中它们将从关联数组中获取的键名和键值直接绑定到 mysql 表的列和值。换句话说,由于键名与数据库表的列名相同,我想知道如何自动创建查询,就像在顶部的两个链接中一样。
  • @JBH 感谢您的回复。我想要实现的是顶部两个链接中的答案。在此之上阅读我的评论。使用“自动化”意味着拥有变量和可能循环来构建查询而不是编写单个列名,并且对于要插入的列值也是如此

标签: php mysql arrays


【解决方案1】:

您可以内爆关联数组,但不能内爆多维数组。这就是错误告诉你的。比如……

$my_array = array('a'=>'1', 'b'=>'2', 'c'=>'3');
echo "\n\n".implode(',',array_keys($my_array));
echo "\n\n".implode(',',$my_array)."\n\n";

结果...

a,b,c

1,2,3

但是……

$my_array = array(
    array('a'=>'1', 'b'=>'2', 'c'=>'3'),
    array('d'=>'4', 'e'=>'5', 'f'=>'6')
);
echo "\n\n".implode(',',array_keys($my_array));
echo "\n\n".implode(',',$my_array)."\n\n";

结果...

0,1
PHP Notice:  Array to string conversion in /test.php on line 9

修复代码意味着处理单个数据元素。回声他们看起来像这样:

selected, user_id, user_name, user_company, user_email
,3,nome3,azien3,email3
1,6,nome6,azien6,email6

所以,基本代码看起来像......

$fields = implode(",", array_keys($Arr));
echo $fields."\n";
foreach($Arr as $key=>$val){
    $newdata = "'" . implode("','", $Arr[$key]) . "'";
    echo $newdata."\n";
}

PDO INSERT 语句将像这样构建...

$my_keys = array_keys($Arr[0]);

$stmt=$pdo->prepare("DESC my_table");
$stmt->execute();
$whitelist_columns=$stmt->fetchAll(PDO::FETCH_COLUMN);
foreach($my_keys as $key){
    if(!array_search($key,$whitelist_columns)){ echo "ERROR!"; }
}

$field_names = implode(",", $my_keys);       // build column list
$q_markers = implode(",", $my_keys);     // build PDO value markers

$stmt = $pdo->prepare("INSERT INTO my_table (".$field_names.") VALUES (".$q_markers.")");
foreach($Arr as $key => $val){
    foreach($val as $bind_marker => $bind_val){
        $stmt->bindParam($bind_marker, $bind_val);
    }
    $stmt->execute();
}

注意带有whitelist 变量的代码部分。该代码的目的是防止由于使用未绑定的列引用创建查询而导致的 SQL 注入。 PDO 不允许您以与单元格数据相同的方式绑定列名。为了保护自己,您必须证明传入的数据与表中的列匹配。如果他们不这样做,请采取措施 (echo "ERROR";)。通常您希望完全停止该 INSERT 并在某处记录问题。

$my_keys = array_keys($Arr[0]);
$q_marks = array();

$stmt=$pdo->prepare("DESC my_table");
$stmt->execute();
$whitelist_columns=$stmt->fetchAll(PDO::FETCH_COLUMN);
foreach($my_keys as $key){
    if(!array_search($key,$whitelist_columns)){ echo "ERROR!"; }
    array_push($q_marks, "?");
}

$field_names = implode(",", $my_keys);       // build column list
$field_markers = implode(",", $q_marks);

$stmt = $pdo->prepare("INSERT INTO my_table (".$field_names.") VALUES (".$field_markers.")");

foreach($Arr as $key => $val){
    $stmt->execute($val);
}

上面的代码是一个没有bindParambindValue的使用PDO的例子。它带有价格,但通常没有实际成本。 bindParambindValue 允许您专门识别数据类型。例如,bindParam('myval', $myval, PDO::PARAM_INT)。如上所述传递变量时,您不能这样做。大多数情况下,这不是问题,因为 PHP 可以正确识别数据类型。当 PHP 确实感到困惑时(或者如果您只是想检查数据是否符合您的预期),那么您必须使用 bindParambindValue

【讨论】:

  • 谢谢JBH,我迫不及待想试试(目前我不在家)。这似乎是正确的过程。这个问题源于我打开的另一个问题,但它已被标记为重复的stackoverflow.com/questions/45349503/…,我在那里提到 PDO 作为首选!你读懂了我的想法 ;-)(尽管 PDO 可能是这种情况下的唯一选择(?))
  • PDO 始终是最佳选择,因为它可以保护您免受 SQL 注入。您应该始终使用 PDO。
  • 这是我的目标,我一直使用 PDO,必须学习,我知道它是针对 msqli 学习的。我对 PDO 感觉很舒服,它使事情变得非常可读,而如果实施得当,它会使结构更有效、轻量级和直接,例如准备语句时使用循环(如果需要)。例如。我想知道如果没有 PDO 占位符他们怎么办(被问到“没有咖啡他们怎么办”:-)).. 我们知道可以做到,但真是一团糟。然而,PDO 提出了对象概念,这是一种习惯性的观点。
  • 关于 PDO 虽然这里 phpdelusions.net/pdo/sql_injection_example 解释说,如果使用准备好的语句,一个 SQL 注入是可能的......但是......从上下文中解释了如何避免这种情况:-)
  • 这很好。我忘记了我们正在动态构建列名列表。我已经编辑了我的答案以包含防止这种注入的白名单代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-11
  • 2014-10-22
  • 2012-06-16
  • 1970-01-01
  • 2018-01-03
  • 2014-11-17
相关资源
最近更新 更多