代码之家  ›  专栏  ›  技术社区  ›  sparkhead95

Real_escape_string阻止INSERT语句运行MYSQL PHP

  •  0
  • sparkhead95  · 技术社区  · 11 年前

    所以我正在使用MYSQL和PHP制作自己的博客脚本。 我把“把博客写到数据库”这件事做得很好,直到我意识到,如果你试图用语音标记写博客,这会阻止INSERT语句的工作( 明显地 -语音标记正在结束SQL语句)。

    所以我尝试使用real_escape_string,现在即使排除引号,INSERT也不起作用。 我尝试使用:

    sqlstate
    

    为了找出问题,它返回了“42000”,在谷歌搜索了一段时间后,这是一个语法错误,这没有多大意义,因为在使用realescapestring之前没有语法错误。

    此外,我现在收到了以下错误:

     Call to a member function close() on a non-object in /postarticle.php on line 37
    

    它引用ELSE语句中的close()调用。

    请你帮忙好吗?已经绕了一段时间了。这是我的代码:

    <?php
    $host = 'CENSORED';
    $user = 'CENSORED';
    $pass = 'CENSORED';
    $db = 'CENSORED';
    
    $connection = new mysqli($host,$user,$pass,$db);
    
    $_SESSION["article"] = $_POST["article"];
    $date_of_blog = getdate(); 
    
    $article = ($_SESSION["article"]);
    
    $sql1 = "SELECT * FROM `Blogs`";
    $res1 = $connection->query($sql1);
    $newrows = $res1->num_rows + 1;
    
    $sql2 = "INSERT INTO Blogs(BlogID, Blog_Contents, D_O_B) VALUES ('$newrows','$article','$date_of_blog')";
    $sql2 = $connection->real_escape_string($sql2);
    $res2 = $connection->query($sql2);
    
    if ($res2->num_rows == $newrows)
    {
        $res->close();
        $connection->close();
        header( 'Location: adminpanel.php' );
    
    }
    else
    {
    
    echo ($connection->sqlstate);
    $connection->close();
    $res->close();
    }
    
    exit();
    
    
    ?>
    

    另外,顺便说一句,我得到的getdate()调用从未奏效。在数据库中,每一篇博客文章都如下: 0000:00:00 00:00:00

    编辑: 问题现已解决。查找以下功能代码:

    <?php
    $host = 'CENSORED';
    $user = 'CENSORED';
    $pass = 'CENSORED';
    $db = 'CENSORED';
    
    
    $connection = new mysqli($host,$user,$pass,$db);
    
    $_SESSION["article"] = $_POST["article"];
    
    $article = ($_SESSION["article"]);
    
    $article = $connection->real_escape_string($article);
    
    $sql1 = "SELECT * FROM `Blogs`";
    $res1 = $connection->query($sql1);
    $newrows = $res1->num_rows + 1;
    
    $sql2 = "INSERT INTO Blogs(BlogID, Blog_Contents, D_O_B) VALUES (\"$newrows\",\"$article\",CURDATE())";
    $res2 = $connection->query($sql2);
    
    if ($res2 != false)
    {
        header( 'Location: adminpanel.php' );
    }
    else
    {   
        echo ($connection->sqlstate);
    }
    $connection->close();
    $res->close();
    
    
    exit();
    
    
    ?>
    

    很抱歉,如果这些问题是基本的,会惹恼这里的专业人士;我已经试着遵循这些准则,我已经在谷歌上搜索了一段时间。我只是没有找到任何与我的问题相匹配的解决方案。 谢谢你抽出时间。

    2 回复  |  直到 11 年前
        1
  •  2
  •   Community Mohan Dere    9 年前

    最初发布的代码存在一些问题。首先,您最初确定的两个问题的原因是误用 mysqli::real_escape_string() 。它需要被调用 每个变量单独 其出现在代码中。因此,与其在整个语句中调用它,不如对多个变量多次调用它,例如:

    $article = $connection->real_escape_string($connection);
    

    由于引用错误导致查询失败(由于 real_escape_string() )是错误消息调用的原因 close() .

    如评论中所确定的,您正在使用 num_rows + 1 以验证是否已根据先前返回的行数插入了一个新行。这是一个问题,原因有几个。主要是,它暴露了一种竞争条件,其中一行可以同时从两个会话中插入,其中一个或两个会话将失败,因为 $newrows 不匹配。真正地 BlogID 应该是 auto_increment 列。这消除了 任何 围绕它的逻辑。你甚至不需要在 INSERT 因为它将自动递增。

    这也完全消除了第一个 SELECT 陈述

    替换MySQL的本机 NOW() 函数,可以将语句简化为:

    INSERT INTO Blogs (Blog_Contents, D_O_B) VALUES ('$article', NOW())
    

    要测试插入的成功或失败,只需验证其变量是否 false .

    把这些放在一起,您的代码可以简化为:

    if (!isset($_POST['article'])) {
       // exit or handle an empty post somehow...
    }
    $connection = new mysqli($host,$user,$pass,$db);
    $_SESSION["article"] = $_POST["article"];
    
    // Escape $article for later use
    $article = $connection->real_escape_string($_SESSION["article"]);
    
    // Only an INSERT is needed. $article is already escaped
    $sql = "INSERT INTO Blogs (Blog_Contents, D_O_B) VALUES ('$article', NOW())";
    // Run the query
    $res = $connection->query($sql);
    
    // Test for failure by checking for a false value
    if ($res) {
      // The connection & resource closure can be omitted
      // PHP will handle that automatically and implicitly.
      header( 'Location: adminpanel.php' );
      // Explictly exit as good practice after redirection
      exit();
    }
    else {
      // The INSERT failed. Check the error message
      echo $connection->error;
    }
    

    这将使您的当前代码进入工作状态。然而,由于您正在学习这一点,现在是开始学习使用准备好的语句的绝佳时机 prepare()/bind_param()/execute() 在MySQLi中。虽然使用了 real_escape_string() 只要你正确使用它并且永远不会忘记,它就可以工作。

    看见 How can I prevent SQL injection in PHP 例如。

    但它看起来像:

    // connection already established, etc...
    // Prepare the statement using a ? placeholder for article
    $stmt = $connection->prepare("INSERT INTO Blogs (Blog_Contents, D_O_B) VALUES (?, NOW())");
    if ($stmt) {
      // bind in the variable and execute
      // Note that real_escape_string() is not needed when using
      // the ? placeholder for article
      $stmt->bind_param('s', $_SESSION['article']);
      $stmt->execute();
    
      // Redirect
      header( 'Location: adminpanel.php' );
      exit();
    }
    else {
      echo $connection->error;
    }
    
        2
  •  1
  •   Geoff Atkins    11 年前

    您需要将real_escape_string函数应用于变量,而不是整个SQL字符串。

    $sql2 = "INSERT INTO Blogs(BlogID, Blog_Contents, D_O_B) VALUES ('".$connection->real_escape_string($newrows)."','".$connection->real_escape_string($article)."','".$connection->real_escape_string($date_of_blog)."')";
    

    其目的是删除任何可能被MySQL误解为查询函数的内容,但您显然希望将查询的某些部分解释为查询函数。

    推荐文章