带有可变列的预备语句

时间:2015-04-06 20:05:02

标签: php sql mysqli prepared-statement

我正在为我一直在努力的游戏创建一个数据库,我需要用户能够互相杀戮,所以我设置了这样的表:

...
`alive1` => Player 1's status
`alive2` => Player 2's status
`alive3` => Player 3's status
`alive4` => Player 4's status
...

我需要能够基于每个案例修改数据库中的这些列,并且可以直接从用户输入。但是,做这样的事情:

$stmt = $link->prepare("UPDATE `games` SET `alive{$_GET["player"]}`=0 WHERE `id`=?")

易受SQL注入攻击。有没有一种方法可以将列名“绑定”到查询中,以便我可以安全地修改表格?

$ _GET [“player”]的正确输入应该只是一个整数1..4,所以我想我可以直接检查输入,如果需要,并确保它是这四种可能性之一,但我是希望能有更优雅的解决方案。这可能会在稍后的另一个项目中再次出现,其中可能的输入集将会更大,并且对每个案例进行硬编码将非常耗时。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

标识符不能绑定到预准备语句中,因此您应该将它们列入白名单。

通常,对于白名单,您需要创建一个有效标识符数组,并检查传递的标识符是否在列表中。例如:

$validColumns = array('alive1', 'alive2', 'alive3', 'alive4');
$col = 'alive' . $_GET["player"];
$isSafeToUse = in_array($col, $validColumns);

在你的情况下,你可以

$id = (int)$_GET["player"];

然后检查$id是否在[1, 4]范围内。

答案 1 :(得分:0)

我会使用正则表达式/^[1-4]$/

if(preg_match('/^[1-4]$/', $_GET['player'])){
    $stmt = $link->prepare('UPDATE `games` SET `alive' . $_GET['player'] . '` =0 WHERE `id`=?');
} else {
    die;
}

要将此功能用于将来的项目,您可以将其扩展为/^[0-9]{1,3}$/,这样您就可以接受最多999

的数字