从 mysqli 转换为准备好的语句

Converting from mysqli to prepared statements

我正在尝试将代码从 mysqli_* 语句转换为准备好的语句以防止 SQL 注入。以下代码是我试图转换的代码(目前它可以正常工作):

$details = mysqli_query($linkDB,"SELECT * FROM ".PREFIX."Issues WHERE id='".$_POST['article']."' AND disabled='0' LIMIT 1");
$detail = mysqli_fetch_assoc($details);

这是我转换为准备好的语句的尝试。任何使它更简洁的方法都将不胜感激(因为我要从 2 行代码变成很多行):

$SQL = "SELECT * FROM ".PREFIX."Issues WHERE id='?' AND disabled='0' LIMIT 1";
$PRE = mysqli_stmt_init($linkDB);
//if (! $PRE = mysqli_prepare($linkDB, $SQL)) {   (alt attempt)
    if (! mysqli_stmt_prepare($PRE, $SQL)) {
        echo "<f><msg>ERROR: Could not prepare query: ".$SQL.", ".mysqli_error($linkDB)."</msg></f>";
    } else {
        mysqli_stmt_bind_param($PRE, "i", $test);
        $test = $_POST['article'];
        if (! mysqli_stmt_execute($PRE)) {
            echo "<f><msg>ERROR: Could not execute query: ".$SQL.", ".mysqli_error($linkDB)."</msg></f>";
        } else{
            $details = mysqli_stmt_get_result($PRE);
            $detail = mysqli_fetch_assoc($details);
            mysqli_stmt_close($PRE);
        }
}

以上代码没有 return/store $detail 变量中的 db 值,以便稍后在脚本中进行处理。我试过注释掉 mysqli_stmt_close($PRE) 调用,但这没有区别。感谢您的帮助!

如果您不是经验丰富的编码人员,我会推荐 PDO。它是面向对象的,适合现代编码方式 PHP。

在你的配置文件中你输入:

$db = new PDO('mysql:host=localhost;dbname=test', $user, $pass);

还有你的脚本:

$statement = $pdo->prepare('SELECT * FROM '.PREFIX.'Issues WHERE id = :id AND disabled = 0 LIMIT 1';
$statement->execute(['id' => $_POST['article']);
$result = $statement->fetch(PDO::FETCH_ASSOC);

代码中的主要错误是查询中 '?' 的拼写错误。如果 ? 在引号内,它不会被视为占位符,而是被视为文字值。

使用 MySQLi 时,您应该 enable MySQLi exception mode。如果这样做,则不再需要检查每个函数的结果。您还应该使用 OOP 样式,因为它不那么冗长并且您不太可能犯下愚蠢的错误。

// put this line before you open the MySQLi connection
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

$stmt = $linkDB->prepare('SELECT * FROM '.PREFIX.'Issues WHERE id=? AND disabled=0 LIMIT 1');
$stmt->bind_param('i', $_POST['article']);
$stmt->execute();
$detail = $stmt->get_result()->fetch_assoc();