如何使用关联数组编写良好的 PHP 数据库插入
-
20-09-2019 - |
题
在 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; --;
幸运的是, 不支持多个查询, ,尽管如此,引用和转义对于防止 SQL 注入漏洞至关重要。
你如何编写 PHP Mysql 插入?
笔记:PDO 或 mysqli 准备的查询目前对我来说不是一个选择,因为代码库已经广泛使用 mysql - 计划进行更改,但需要大量资源来转换?
解决方案
我想改变的唯一事情是使用出于可读性目的的sprintf
$sql = sprintf(
'INSERT INTO table (%s) VALUES ("%s")',
implode(',',array_keys($_fields)),
implode('","',array_values($_fields))
);
mysql_query($sql);
和确保值被转义。
其他提示
没有错。我也一样。
但要确保你mysql_escape()
并注明您在查询坚守的价值观,否则,你正在寻找SQL注入漏洞。
可替换地,可以使用参数化的查询,在这种情况下,可以通过实际上本身阵列,而不是建立一个查询字符串。
最好的做法是要么使用ORM(学说2.0),一个ActiveRecord实现(学说1.0,红豆),或一个TableGateway模式实现(Zend_Db_Table类,行走)。这些工具将让您的生活轻松了许多,并处理大量繁重的你,并能帮助您防止SQL注入攻击。
除此之外,没有什么内在的错误,你在做什么,你就可能要抽象它带到一个类或函数,这样就可以在不同的地方重复的功能。
使用 冲刺函数 提到的技巧 盖伦 在一个 之前的回答, ,我想出了以下代码:
$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,代码可能会更好 匿名函数 但我需要它在较旧的 PHP 安装上运行。
此代码比原始代码稍长(且速度较慢),但更安全。
我用这个检索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, " ,") . ")";
}
有与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).')' );
}