所以我使用MYSQL和PHP制作自己的博客脚本。 我把整个博客写进了一个数据库'工作得很完美,直到我意识到如果你试图写一个带有语音标记的博客,这将阻止INSERT语句起作用(显然 - 语音标记结束了SQL语句)。
所以我尝试使用real_escape_string,现在即使你排除引号,INSERT也不起作用。 我尝试使用:
sqlstate
为了找出问题,它返回" 42000" - 在google搜索一点之后,它指的是语法错误,因为在使用real_escape_string之前没有语法错误,所以没有多大意义。
另外,我现在收到此错误:
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();
?>
我很抱歉,如果这些问题是基本的,会让周围的专业人士感到恼火;我已经尝试遵循这些指导原则并且已经谷歌搜索了一段时间等等。我还没有找到任何与我的问题相符的解决方案。 谢谢你的时间。
答案 0 :(得分:2)
最初发布的代码存在许多问题。主要是,您最初确定的两个问题的原因是滥用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;
}
这应该使您当前的代码正常运行。但是,由于您正在学习这一点,因此现在是开始学习在MySQLi中通过prepare()/bind_param()/execute()
使用预准备语句的绝佳时机。这是防止SQL注入的推荐最佳实践,尽管使用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;
}
答案 1 :(得分:1)
您需要将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可能被误解为查询函数的任何内容,但是您明显希望将查询的某些部分解释为这样。