如何使用关联数组编写良好的PHP数据库插入

如何使用关联数组编写良好的PHP数据库插入,php,sql,associative-array,Php,Sql,Associative Array,在PHP中,我想使用字段/值对的关联数组中包含的数据插入数据库 例如: 生成的SQL插入应如下所示: INSERT INTO table (field1,field2,field3) VALUES ('value1','value2','value3'); 我提出了以下PHP一行程序: mysql_query("INSERT INTO table (".implode(',',array_keys($_fields)).") VALUES (".implode(',',array_values

在PHP中,我想使用字段/值对的关联数组中包含的数据插入数据库

例如:

生成的SQL插入应如下所示:

INSERT INTO table (field1,field2,field3) VALUES ('value1','value2','value3');
我提出了以下PHP一行程序:

mysql_query("INSERT INTO table (".implode(',',array_keys($_fields)).") VALUES (".implode(',',array_values($_fields)).")");
它分离关联数组的键和值,并
内爆
以生成逗号分隔的字符串。问题是它不会转义或引用插入数据库的值。为了说明这种危险,假设
$\u字段
包含以下内容:

$_fields = array('field1'=>"naustyvalue); drop table members; --");
将生成以下SQL:

INSERT INTO table (field1) VALUES (naustyvalue); drop table members; --;
幸运的是,引用和转义对于防止SQL注入漏洞是必不可少的

如何编写PHP Mysql插件?


注意:PDO或mysqli准备的查询目前不是我的选择,因为代码库已经广泛使用mysql-计划进行更改,但转换需要大量资源?

这没什么错。我也这么做

但是请确保您
mysql\u escape()
并引用您在查询中粘贴的值,否则您将看到SQL注入漏洞


或者,您可以使用参数化查询,在这种情况下,您实际上可以传递数组本身,而不是构建查询字符串。

最佳做法是使用ORM(条令2.0)、ActiveRecord实现(条令1.0,RedBean)或TableGateway模式实现(Zend_Db_Table,Propel)。这些工具将使您的生活更加轻松,为您处理许多繁重的工作,并帮助您避免SQL注入


除此之外,您所做的事情本身并没有什么错误,您可能只是想将其抽象为一个类或一个函数,这样您就可以在不同的地方重复该功能。

我唯一要改变的是为了可读性而使用sprintf

$sql = sprintf(
    'INSERT INTO table (%s) VALUES ("%s")',
    implode(',',array_keys($_fields)),
    implode('","',array_values($_fields))
);
mysql_query($sql);
并确保值被转义。

使用Galen在a中提到的sprintf技巧,我得到了以下代码:

$escapedfieldValues = array_map(create_function('$e', 'return mysql_real_escape_string(((get_magic_quotes_gpc()) ? stripslashes($e) : $e));'), array_values($_fields));

$sql = sprintf('INSERT INTO table (%s) VALUES ("%s")', implode(',',array_keys($_fields)), implode('","    ',$escapedfieldValues));

mysql_query($sql);
它生成一个转义的带引号的插入。它还可以独立于
magic\u quotes\u gpc
是否打开进行处理。如果我使用新的PHPV5.3.0,代码可能会更好,但我需要它在旧的PHP安装上运行


此代码比原始代码长一点(也慢一点),但更安全。

我使用此代码检索插入部分的值。 但这可能是一种荒谬的做事方式。欢迎提出意见/建议

   function arrayToSqlValues($array)
   {
      $sql = "";
      foreach($array as $val)
      {    
         //adding value
         if($val === NULL)
            $sql .= "NULL";
         else
            /*
            useless piece of code see comments
            if($val === FALSE)
               $sql .= "FALSE";
            else
            */
               $sql .= "'" . addslashes($val) . "'";

         $sql .= ", ";
      };

      return "VALUES(" . rtrim($sql, " ,") . ")";
   }

将NULL(在接受的答案中)值转换为空字符串“”时出现问题。这就是修复,NULL变为NULL,不带引号:

function implode_sql_values($vals)
{
    $s = '';
    foreach ($vals as $v)
        $s .= ','.(($v===NULL)?'NULL':'"'.mysql_real_escape_string($v).'"');

    return substr($s, 1);
}
用法:

implode_sql_values(array_values( array('id'=>1, 'nick'=>'bla', 'fbid'=>NULL) ));
// =='"1","bla",NULL'

如果您想改进您的方法并增加输入验证和卫生的可能性,您可能需要这样做:

function insertarray($table, $arr){
   foreach($arr as $k => $v){
      $col[] = sanitize($k);
      $val[] = "'".sanitize($v)."'";
   }

   query('INSERT INTO '.sanitize($table).' ('.implode(', ', $col).') VALUES ('.implode(', ', $val).')' );
}

在将它们添加到字段和值arraysWatch之前,我只需确保所有内容都经过验证。注意:introde()将NULL转换为空字符串,然后在整数列中变为0。自动不,只需在插入前对每个项目使用哇,这太棒了。您在值中添加了引号,并提高了可读性。非常感谢!我建议您先运行array\u filter(),为了删除数组的空值,这些空值没有用,但会减慢查询速度。@DaNieL:但是array\u filter()是否也会删除字符串“0”?这可能不是一个好主意。@marco:是的,它会,字符串“0”在布尔值中被认为是错误的,因此它将被数组_过滤器删除(不带回调)。注意,根据具体情况,这可能是一个问题。这不应该成为一个答案。应将其添加到原始问题中。至于安全性,现在你最好的选择是使用预先准备好的查询(也称为参数化查询)。我同意,但如果我把它添加到原始问题中,现有的答案就没有那么大意义了?我应该添加它吗?要么A)添加大部分,除了代码(因为这是一个潜在的答案),要么B)将其添加到标题为“更新”的部分。@outis-我选择了选项A。谢谢你的建议。现在这些注释没有多大意义-我们删除它们吗?+1用于参数化查询。参考链接:如果$val===true,那么这将为您提供“1”。@TomHaigh:没错,这不是一个bugSQL查询中的“1”为TRUE。既然如此,为什么要执行“$SQL.=”FALSE”`为假?保持一致不是更好吗?
function insertarray($table, $arr){
   foreach($arr as $k => $v){
      $col[] = sanitize($k);
      $val[] = "'".sanitize($v)."'";
   }

   query('INSERT INTO '.sanitize($table).' ('.implode(', ', $col).') VALUES ('.implode(', ', $val).')' );
}