PDO PHP从关联数组插入到DB中

时间:2012-11-22 07:13:03

标签: php mysql database arrays pdo

我有一个像这样的数组

  $a = array( 'phone' => 111111111, 'image' => "sadasdasd43eadasdad" );

当我进行var-dump时,我得到了这个 - >

 { ["phone"]=> int(111111111) ["image"]=> string(19) "sadasdasd43eadasdad" }

现在我尝试使用IN语句将其添加到数据库 -

 $q = $DBH->prepare("INSERT INTO user :column_string VALUES :value_string");
 $q->bindParam(':column_string',implode(',',array_keys($a)));
 $q->bindParam(':value_string',implode(',',array_values($a)));
 $q->execute();

我遇到的问题是implode返回一个字符串。但'phone'列是数据库中的整数,并且数组也将其存储为整数。因此我得到SQL错误,因为我的最终查询看起来像这样 -

INSERT INTO user 'phone,image' values '111111111,sadasdasd43eadasdad';

哪个查询错误。有没有办法解决它。

我的列名是动态的,基于用户想要插入的内容。因此,我无法使用:phone :image 等占位符,因为我可能无法始终获得这两列的值。如果有办法,请告诉我。否则我将不得不为每种类型的更新定义多个函数。

感谢。

7 个答案:

答案 0 :(得分:10)

上次我检查时,不可能准备一份声明,其中受影响的列在准备时是未知的 - 但这似乎有用 - 也许你的数据库系统比我正在使用的那些(主要是postgres)更宽容< / p>

implode()语句显然是错误的,因为每个变量都应该由它自己处理,你还需要在insert语句中的字段列表周围使用括号。

要插入用户定义的字段,我认为你必须做这样的事情(至少我是怎么做的);

$fields=array_keys($a); // here you have to trust your field names! 
$values=array_values($a);
$fieldlist=implode(',',$fields); 
$qs=str_repeat("?,",count($fields)-1);
$sql="insert into user($fieldlist) values(${qs}?)";
$q=$DBH->prepare($sql);
$q->execute($values);

如果您不相信$ a中的字段名称,则必须执行类似

的操作
foreach($a as $f=>$v){
   if(validfield($f)){
      $fields[]=$f;
      $values[]=$v;
   }
}

其中validfields是您编写的函数,用于测试每个fieldname并检查它是否有效(通过创建关联数组来快速和脏化$ valfields = array('name'=&gt; 1,'email'=&gt; 1 ,'phone'=&gt; 1 ...然后通过从服务器获取字段名称来检查$ valfields [$ f]的值,或(我希望如此)

答案 1 :(得分:6)

SQL查询参数只能用于放置文字值的位置。

因此,如果您可以看到自己在查询中的该位置放置带引号的字符串文字,日期文字或数字文字,则可以使用参数。

您不能将参数用于列名,表名,值列表,SQL关键字或任何其他表达式或语法。

对于这些情况,您仍然需要将内容插入到SQL字符串中,因此您有一些SQL注入的风险。防止这种情况的方法是使用白名单列名称,并拒绝任何与白名单不匹配的输入。

答案 2 :(得分:4)

因为所有其他答案都允许 SQL注入。对于用户输入,您需要筛选允许的字段名称:

// change this
$fields = array('email', 'name', 'whatever');
$fieldlist = implode(',', $fields);
$values = array_values(array_intersect_key($_POST, array_flip($fields)));
$qs = str_repeat("?,",count($fields)-1) . '?';
$q = $db->prepare("INSERT INTO events ($fieldlist) values($qs)");
$q->execute($values);

答案 3 :(得分:2)

您实际上可以提前使用空值绑定:phone:image字段。无论如何,表的结构是固定的,你可能应该这样。


但你问题的答案可能如下:

$keys = ':' . implode(', :', array_keys($array)); 
$values = str_repeat('?, ', count($array)-1) . '?';

$i = 1;
$q = $DBH->prepare("INSERT INTO user ($keys) VALUES ($values)");

foreach($array as $value)
    $q->bindParam($i++, $value, PDO::PARAM_STR, mb_strlen($value));

答案 4 :(得分:2)

我知道很久以前这个问题已经得到解答了,但我今天发现它并且除了@MortenSickel的答案之外还有一些贡献。

下面的类允许您将关联数组插入或更新到数据库表。有关MySQL PDO的更多信息,请访问:http://php.net/manual/en/book.pdo.php

<?php

class dbConnection
{
  protected $dbConnection;

  function __construct($dbSettings) {
    $this->openDatabase($dbSettings);
  }

  function openDatabase($dbSettings) {  
    $dsn = 'mysql:host='.$dbSettings['host'].';dbname='.$dbSettings['name'];
    $this->dbConnection = new PDO($dsn, $dbSettings['username'], $dbSettings['password']);
    $this->dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  }

  function insertArray($table, $array) {
    $fields=array_keys($array);
    $values=array_values($array);
    $fieldlist=implode(',', $fields); 
    $qs=str_repeat("?,",count($fields)-1);

    $sql="INSERT INTO `".$table."` (".$fieldlist.") VALUES (${qs}?)";

    $q = $this->dbConnection->prepare($sql);
    return $q->execute($values);
  }

  function updateArray($table, $id, $array) {
    $fields=array_keys($array);
    $values=array_values($array);
    $fieldlist=implode(',', $fields); 
    $qs=str_repeat("?,",count($fields)-1);
    $firstfield = true;

    $sql = "UPDATE `".$table."` SET";
    for ($i = 0; $i < count($fields); $i++) {
        if(!$firstfield) {
        $sql .= ", ";   
        }
        $sql .= " ".$fields[$i]."=?";
        $firstfield = false;
    }
    $sql .= " WHERE `id` =?";

    $sth = $this->dbConnection->prepare($sql);
    $values[] = $id;
    return $sth->execute($values);
  }
}
?>

dbConnection类用法:

<?php
  $dbSettings['host'] = 'localhost';
  $dbSettings['name'] = 'databasename';
  $dbSettings['username'] = 'username';
  $dbSettings['password'] = 'password';
  $dbh = new dbConnection( $dbSettings );

  $a = array( 'phone' => 111111111, 'image' => "sadasdasd43eadasdad" );
  $dbh->insertArray('user', $a);

  // This will asume your table has a 'id' column, id: 1 will be updated in the example below:
  $dbh->updateArray('user', 1, $a);
?>

答案 5 :(得分:2)

我很欣赏MortenSickel的回答,但我想使用命名参数来保证安全:

    $keys = array_keys($a);
    $sql = "INSERT INTO user (".implode(", ",$keys).") \n";
    $sql .= "VALUES ( :".implode(", :",$keys).")";        
    $q = $this->dbConnection->prepare($sql);
    return $q->execute($a);

答案 6 :(得分:0)

public function insert($data = [] , $table = ''){
    $keys = array_keys($data);
    $fields = implode(',',$keys);
    $pre_fields = ':'.implode(', :',$keys);
    $query = parent::prepare("INSERT INTO $table($fields) VALUES($pre_fields) ");
    return $query->execute($data);
}