我使用 PDO 访问我的 MySQL 数据库,并想使用 IN。但遗憾的是它不能与 prepare 一起工作,所以我写了这个函数
function is_numeric_array($array){
if(!is_array($array))
return is_numeric($array);
if(is_array($array))
foreach($array as $int)
if(!is_numeric($int))
return false;
return true;
}
然后就这样用了
if(!is_numeric_array($_SESSION['story'])){
die("Error, array contains non-integers");
}
$query = "(";
for($i = 0; $i<count($_SESSION['story']); $i++)
$query .= $_SESSION['story'][$i].(count($_SESSION['story'])-1 != $i ? "," : "");
$query .= ")";
//Collect all data needed
$stories = openConnection() -> query("SELECT * FROM `stories` WHERE `id` IN {$query}") -> fetchAll();
我知道,看起来很丑。但我不想要任何 SQL 注入(inject)。
最佳答案
您实际上不必测试输入是否为数字,因为在 MySQL 中,任何字符串,例如'123abc'
在数字上下文中(比如与整数列 id
进行比较)隐含地只接受数字并忽略其余部分。像 'abc'
这样的非数字字符串只有整数值 0,因为没有前导数字。
重点是,如果您使用查询参数,则值不会受到 SQL 注入(inject)的影响。输入是来自 $_SESSION 还是其他来源是无关紧要的。对于 SQL 注入(inject),$_SESSION 既不安全也不安全,重要的是将数据传递给查询的方式。
我还会简化代码以格式化参数占位符列表:
$placeholders = implode(',', array_fill(1, count((array)$_SESSION['story']), '?'));
忘记 bindParam(),只需将数组传递给 execute()
。
//Collect all data needed
$storyQuery = openConnection() -> prepare("SELECT * FROM `stories`
WHERE `id` IN ({$placeholders})");
$storyQuery -> execute((array)$_SESSION['story']);
$story = $storyQuery -> fetchAll();
回复你的评论:
在 PDO 中,您可以使用命名参数,如 :id
,也可以使用位置参数,它们始终是 ?
(但不要混合使用这两种类型在给定的查询中,使用一个或另一个)。
将数组传递给 execute()
会自动将数组元素绑定(bind)到参数。一个简单的数组(即由整数索引)很容易绑定(bind)到位置参数。
如果您使用命名参数,则必须传递一个关联数组,其中数组的键与参数名称匹配。数组键可以选择以 :
为前缀,但这不是必需的。
如果您是 PDO 的新手,阅读 documentation 确实值得.有代码示例和一切!
关于php - $_SESSION 对 sql 注入(inject)安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23941182/