【问题标题】:Trouble converting to parameterized queries转换为参数化查询时遇到问题
【发布时间】:2021-02-23 06:30:59
【问题描述】:

所以我试图将我的所有 SQL 语句转换为准备好的语句等,以防止 SQL 注入攻击,但我在获取东西等方面遇到了一些问题

我的代码:

if($_GET["action"] == "ban"){

    if(isset($_GET["username"])){

        $username = $_GET["username"];

        $banMsg = $_GET["banMsg"];

        $email = "test@gmx.ch";

        $sql = "SELECT * FROM bans WHERE username = ?";
        $stmt = $db->prepare($sql);
        $stmt->bind_param("s", $username);
        $stmt->execute();
        $result = $stmt->fetch();
        $stmt->close();

        if($result->num_rows > 0){ //LINE 61
            die(json_encode(array("status" => 400, "message" => "User already banned")));
        }

        $result2 = $db->prepare("INSERT INTO bans (username, ip, email, message, expire, ban_creator) VALUES (?, ?, ?, ?, ?, ?)");
        $result2->bind_param("sssssd", $username, null, $email, $banMsg, null, 1); // LINE 72^^
        $result2->close();
        if($result2){
            updateBanCache();
            die(json_encode(array("status" => 200, "message" => "Successfully banned")));
        } else {

            die(json_encode(array("status" => 400, "message" => "SQL error")));
        }

    }

另外,$result = $stmt->get_result(); 不想为我工作,不过我的 php / cpanel 中确实安装了 mysqlnd 驱动程序。

任何指针都会有所帮助,谢谢!

错误日志:

[11-Nov-2020 04:46:04 America/New_York] PHP Notice:  Trying to get property 'num_rows' of non-object in /home/public_html/index.php on line 61
[11-Nov-2020 04:46:04 America/New_York] PHP Fatal error:  Uncaught Error: Cannot pass parameter 3 by reference in /home/elysianmenu/public_html/index.php:72
Stack trace:
#0 {main}
  thrown in /home/public_html/index.php on line 72

旁注:我也尝试使用$result = $stmt->get_result();,但最终出现错误:

[11-Nov-2020 04:57:30 America/New_York] PHP Fatal error:  Uncaught Error: Call to undefined method mysqli_stmt::get_result() in /home/public_html/index.php:55
Stack trace:
#0 {main}
  thrown in /home/public_html/index.php on line 55

^^ 是的,我确实安装了 mysqlnd 驱动程序

【问题讨论】:

  • 您对$result2->bind_param("sssssd" 的调用表明有 6 个值,而您只通过了 5 个。还要检查您的类型是否正确。
  • 我得到的错误是:[11-Nov-2020 04:23:55 America/New_York] PHP Notice: Trying to get property 'num_rows' of non-object in /home/public_html/ forums/index.php 第 60 行 [2020 年 11 月 11 日 04:23:55 America/New_York] PHP 致命错误:未捕获的错误:调用 /home/public_html/forums//index 中布尔值的成员函数 bind_param() .php:71 堆栈跟踪:#0 {main} 在第 71 行的 /home//public_html/forums//index.php 中抛出,这就是我得到第 71 行的错误
  • 这些细节应该是问题的一部分。
  • 对不起,我忘记了,编辑并添加了它
  • 还注意到我忘记从查询更改为准备,现在这样做了,现在我得到了新的错误:[11-Nov-2020 04:46:04 America/New_York] PHP Notice: Trying to get /home/public_html/forums/index.php 第 61 行 [11-Nov-2020 04:46:04 America/New_York] PHP 致命错误:未捕获错误:无法通过引用传递参数 3 中非对象的属性“num_rows”在 /home/public_html/forums/index.php:72 堆栈跟踪:#0 {main} 在第 72 行的 /home/public_html/forums/index.php 中抛出

标签: php


【解决方案1】:

来自docs从准备好的语句中获取结果到绑定变量中

fetch() 返回TRUEFALSENULL,但不是您期望的结果集。相反,它通过引用将输出设置为您之前绑定的变量(使用bind_param())。这就是为什么您必须使用变量,而不是实际的标量类型。

如果您的查询未返回任何行,fetch() 将返回 NULL。按如下方式更新您的代码:

$stmt = $db->prepare($sql);
$stmt->bind_param("s", $username);
$stmt->execute();
if ($stmt->fetch() === TRUE)
    die(json_encode(array("status" => 400, "message" => "User already banned")));
$stmt->close();

要修复第 72 行的错误,您必须使用变量通过引用传递值。像这样的:

$ip = NULL;
$expire = NULL;
$ban_creator = 1;

$result2->bind_param("sssssd", $username, $ip, $email, $banMsg, $expire, $ban_creator);

别忘了执行查询!在实际发生任何事情之前,您正在检查$result2

【讨论】:

  • 我照你说的做了:$ip = NULL; $电子邮件=空; $过期=空; $result2->bind_param('sssssd', $username, $ip, $email, $banMsg, $expire, 1); $result2->执行(); $result2->close();
  • 但现在我收到此错误:PHP 致命错误:未捕获错误:无法通过 /home/public_html/index.php:66 中的引用传递参数 7
  • ;)。我们更愿意帮助您自助。我已经通过修复更新了我的答案。你现在能明白为什么这会奏效吗?另请参阅this question
  • 啊,我知道这是禁令创建者的问题。这样就解决了。
  • 很高兴知道。如果您发现我的回答有帮助,请考虑对其进行投票并将其标记为已接受的答案:)
【解决方案2】:
  1. 禁止用户的操作不得来自 GET 请求 ($_GET["action"])。这将使网络爬虫非常简单地偶然发现您的禁止脚本并禁止您的所有用户(如果它以某种方式找到用户名列表)。整个有效载荷应该以$_POST 的形式出现。底线是:写入数据时使用$_POST,读取数据时使用$_GET

  2. 您不得盲目相信用户输入。您甚至应该在连接到数据库之前验证数据。如果有效载荷无效,则不应使用任何资源。

  3. 如果您只对结果集的行数(而不是结果集中的值)感兴趣,请在查询中写入 COUNT(1)。通过这种方式,您可以检查单独的值是否为零或非零值,而不会产生不必要的开销。使用类似https://stackoverflow.com/a/51259779/2943403

  4. ipexpireban_creator 应该在表声明中具有默认设置 NULLNULL1。如果您希望存储不同的值,您应该只在 INSERT 查询中提及这些列。您的 INSERT 查询应该只绑定 3 个参数。当然还要检查执行插入的结果,如下所示:$stmt->execute() : How to know if db insert was successful?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多