3 回答
TA贡献1784条经验 获得超7个赞
此脚本的主要目标是连接到 mysql 服务器并尽可能快地、尽可能安全地执行所有可能的查询。
目标很好,但实施可以从许多改进中受益。
免责声明:会有很多指向我自己网站的链接,因为我帮助人们使用 PHP 20 多年,并且痴迷于撰写有关最常见问题的文章。
错误报告的概念
首先,你需要改变错误报告的概念。您的exit()方法对程序员来说将是一场噩梦,因为错误消息是出现问题时的重要信息来源。程序员应该不遗余力地尝试获取完整的错误消息。在我的文章PHP 错误报告中,我确实解释了如何使错误报告对程序员和用户友好。简而言之,你不应该当场捕获错误,而是有一个专门的地方来报告错误和异常,然后可以根据当前服务器的角色轻松配置它。
虽然,正如其他答案中所建议的,您可以在 index.php 文件中使用全局 try-catch 块来充当这样的全局错误处理程序,但我更喜欢专用的错误处理程序脚本,如上面的文章中所述。它会让你的代码更有条理,让 index.php 不那么臃肿。
此外,您认为“在插入查询中返回真实结果”的想法与您使用异常的意图相矛盾。当使用异常时,没有必要验证立即函数的结果。如果出现错误,它只会冒泡到错误处理程序或 catch 块,因此,它永远不会达到条件。一个简单的例子:
function test() {
throw new Exception("Test");
return false;
}
$result = test();
if ($result === false) {
echo "false";
}
此示例中的代码执行永远不会达到条件,因此使您的函数在出错时返回 false 无用。反过来,这使得在成功时返回 true 是多余的。只需返回一个有意义的结果,但不要将其用作标志:只需编写没有任何条件的代码,就好像一切都很好。请记住,您在其他地方拥有错误处理代码,这些代码将在发生错误时神奇地调用。
联系
正如我在另一篇文章如何使用 mysqli 正确连接中所解释的那样,在连接错误的情况下,有一点机会显示连接凭据。为了避免任何可能性但让程序员知道我们必须抛出一个全新的异常,但保留错误信息 - 因此堆栈跟踪将从抛出行开始,因此不包含敏感信息。
此外,连接代码缺少一个必不可少的部分 -设置正确的字符集。尽管在 MySQL 8 中默认设置了正确的字符集,但最好使其明确。
此外,将 mysqli 语句作为类变量是一个严重的错误,会导致竞争条件错误。您的类应该保留的唯一状态是与连接相关的状态,但不应将单个类变量用于语句。
因此,让我们根据上面文章中的代码重写您的构造函数:
public function __construct()
{
mysqli_report(MYSQLI_REPORT_INDEX | MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try {
$this->dbcon = mysqli_init();
$this->dbcon->real_connect('127.0.0.1', '', '', '', 3306, '', MYSQLI_CLIENT_COMPRESS);
$this->dbcon->set_charset('utf8mb4');
} catch (\mysqli_sql_exception $e) {
throw new \mysqli_sql_exception($e->getMessage(), $e->getCode());
}
}
dbquery 函数
坦率地说,这个功能很奇怪。这是准备好的语句和转义之间的奇怪组合。让我们根据我的mysqli helper 函数重写它,该函数实际上使用了 mysqli 准备好的语句
public function dbquery($sql, $data = [], $types = "")
{
$this->dbcon->ping(); // not sure if it's necessary
$stmt = $this->dbcon->prepare($sql);
if ($data) {
$types = $types ?: str_repeat("s", count($data));
$stmt->bind_param($types, ...$data);
}
$stmt->execute();
return $stmt->get_result();
}
现在这个函数满足了你对安全 SQL 查询的渴望
所以最后我们可以重写你的 index.php
<?php
require_once('connection.php');
$DBX = new DBConnect();
$sql = 'INSERT INTO `xathx_key` (`license`, `client`, `server`, `uniquex`) VALUES (?, ?, ?, ?)';
$DBX->dbquery($sql, ['1', '3', '5', '7']);
正如您在上面了解到的,不需要“成功执行查询时的标志”。就好像总是成功一样。如果出现错误,它将在没有任何条件的情况下出现(如果您在索引中包含错误处理程序脚本,则会正确处理实时站点上的错误)。
TA贡献1813条经验 获得超2个赞
你有问题
$this->result = $this->paramquery->get_result();
因为 mysqli_stmt::get_result returns a resultset for successful SELECT queries, or FALSE for other DML queries or on failure.
Other DML-queries是插入、更新、删除。这正是您在示例中所拥有的。
要解决您的问题,您可以通过添加一些额外的检查来修改类$mysqli->errno:
$this->result = $this->paramquery->get_result();
if ($this->result) {
...
}
if ($this->paramquery->errno !== 0) { // we have some real error
exit('Database Query Failed');
}
// we have DML-query (INSERT, UPDATE, DELETE)
// and we can return number of affected rows (if it's necessary)
return $this->paramquery->affected_rows;
PS 我同意这个评论,我认为你的课程应该用于教育目的,因为它有多个严重的缺陷。
TA贡献1873条经验 获得超9个赞
在你的DBConnect课堂上,你有 try catch 块。但是您的 catch 块只是使用exit语句终止请求。你的班级不应该这样做。
想象一下,您将其部署在生产环境中,但由于某种原因数据库连接失败。在这种情况下,用户只会看到一个带有“数据库连接失败”消息的白屏,这看起来一点也不专业。
相反,您的类应该将此信息传递回index.php调用此类的方法并让index.php处理错误消息或异常的类。
因此,我将对您的代码进行以下更改:
DBConnect类应该抛出异常而不是完全终止程序的执行。下面是__contruct()应该的样子。
public function __construct() {
try {
$this->dbcon = mysqli_init();
mysqli_real_connect($this->dbcon, '127.0.0.1', '', '', '', 3306, '', MYSQLI_CLIENT_COMPRESS);
$this->paramquery = $this->dbcon->stmt_init();
} catch (mysqli_sql_exception $e) {
//exit('Database Connection Failed'); Commented this out.
//Throw the Exception Here. This will then be passed to the calling code.
throw $e;
}
}
您将需要相应地更改其他方法。
在您的index.php文件中,您应该寻找捕获上述异常。因此,您应该将代码移到 Try Catch 块中以捕获该异常。
require_once('connection.php');
try {
$DBX = new DBConnect();
$DBX->dbquery('INSERT INTO `xathx_key` (`license`, `client`, `server`, `uniquex`) VALUES (?, ?, ?, ?)', array('ssss', '1', '3', '5', '7'));
} catch (Exception $e) {
$message = 'Caught exception: ', $e->getMessage() . "\n";
//Display this Message to User in an appropriate way.
//Write to Error Log
}
//var_dump($DBX);
//unset($DBX)
因此,如果数据库连接失败以及插入查询失败,这将捕获异常。您可以将异常写入日志,以便稍后检查它们,并且您可以根据导致的异常向用户显示任何适当的错误消息。
您可以在PHP 手册中阅读有关异常的更多信息
- 3 回答
- 0 关注
- 193 浏览
添加回答
举报