【问题标题】:How to write a good PHP database insert using an associative array如何使用关联数组编写好的 PHP 数据库插入
【发布时间】:2010-12-17 04:21:05
【问题描述】:

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

例子:

$_fields = array('field1'=>'value1','field2'=>'value2','field3'=>'value3');

生成的 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)).")");

它将关联数组的键和值与implodes 分开以生成逗号分隔的字符串。问题是它不会转义或引用插入到数据库中的值。为了说明危险,想象一下$_fields 是否包含以下内容:

$_fields = array('field1'=>"naustyvalue); drop table members; --");

将生成以下 SQL:

INSERT INTO table (field1) VALUES (naustyvalue); drop table members; --;

幸运的是,multiple queries are not supported,不过引用和转义对于防止 SQL 注入漏洞是必不可少的。

如何编写 PHP Mysql 插入?

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

【问题讨论】:

  • 我只是确保在将所有内容添加到字段和值数组之前都已经过验证
  • 注意:implode() 将 NULL 转换为空字符串,然后在整数列中变为 0

标签: php sql associative-array


【解决方案1】:

我唯一要改变的就是使用 sprintf 来提高可读性

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

并确保值被转义。

【讨论】:

  • 自动不,插入前在每个项目上使用php.net/manual/en/function.mysql-real-escape-string.php
  • 哇,这太棒了。您为值添加了引号并提高了可读性。非常感谢!
  • 我建议之前运行array_filter(),以删除数组的空值,它们无用但会减慢查询速度。
  • @DaNieL:但是 array_filter() 不会也删除字符串“0”吗?这可能不是一个好主意。
  • @marco:是的,它会,字符串“0”在布尔值中被认为是假的,所以它会被 array_filter 删除(没有回调)。请注意,根据具体情况,这可能是个问题。
【解决方案2】:

这没有错。我也是这样。

但请确保您 mysql_escape() 并引用您在查询中粘贴的值,否则您正在查看 SQL 注入漏洞。

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

【讨论】:

【解决方案3】:

最佳实践是使用 ORM(Doctrine 2.0)、ActiveRecord 实现(Doctrine 1.0、RedBean)或 TableGateway 模式实现(Zend_Db_Table、Propel)。这些工具将使您的生活变得更轻松,并为您处理大量繁重的工作,并有助于保护您免受 SQL 注入。

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

【讨论】:

    【解决方案4】:

    使用 Galenprevious answer 中提到的 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_quotes_gpc 是打开还是关闭。如果我使用新的 PHP v5.3.0 anonymous functions,代码可能会更好,但我需要它在较旧的 PHP 安装上运行。

    此代码比原始代码稍长(且速度较慢),但更安全。

    【讨论】:

    • 这真的不值得回答。它应该添加到原始问题中。至于安全性,这些天你最好的选择是使用准备好的查询(又名参数化查询)。
    • 我同意,但是如果我将它添加到原始问题中,现有答案将没有多大意义?我还是应该添加它吗?
    • 要么 A) 添加大部分内容,但代码除外(因为它是潜在的答案)或 B) 将其添加到标题“更新”中。
    • @outis - 我选择了选项 A。感谢您的建议。现在这些 cmets 没有多大意义了——我们要删除它们吗?
    【解决方案5】:

    我使用它来检索 INSERT 的 VALUES 部分。 但这可能是一种荒谬的做事方式。欢迎提出意见/建议。

       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, " ,") . ")";
       }
    

    【讨论】:

    • 如果 $val === true,那么这给你 '1'。
    • @TomHaigh:没错,这不是错误。 SQL 查询中的“1”为 TRUE。
    • 在这种情况下,你为什么要为 false 做 `$sql .= "FALSE";`?保持一致不是更好吗?
    【解决方案6】:

    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'
    

    【讨论】:

      【解决方案7】:

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

      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).')' );
      }
      

      【讨论】:

        猜你喜欢
        • 2012-11-10
        • 2023-03-29
        • 1970-01-01
        • 2015-06-21
        • 1970-01-01
        • 1970-01-01
        • 2017-06-18
        • 2011-05-29
        • 2017-10-03
        相关资源
        最近更新 更多