为了账号安全,请及时绑定邮箱和手机立即绑定

插入查询中没有真正的结果返回

插入查询中没有真正的结果返回

PHP
烙印99 2021-11-19 16:45:09
这是我创建的用于查询的类:<?phpmysqli_report(MYSQLI_REPORT_INDEX | MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);class DBConnect {    private $dbcon;    private $paramquery;    private $result;    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');        }    }    public function dbquery($querysql, $querydata) {        try {            mysqli_ping($this->dbcon);            $this->paramquery->prepare($querysql);            array_walk($querydata, function(&$escval){$escval = mysqli_real_escape_string($this->dbcon, $escval);});   //Problem            call_user_func_array(array($this->paramquery, 'bind_param'), $querydata);   //Problem            $this->paramquery->execute();        } catch (mysqli_sql_exception $e) {            exit('Database Query Failed');        }        $this->result = $this->paramquery->get_result();  // problem        if ($this->result) {            $drs = $this->result->fetch_array();            $this->result->free_result();            return $drs;        }    }    public function __destruct() {        if (($this->dbcon !== null) && ($this->paramquery !== null) && ($this->result !== null)) {            $this->paramquery->close();            $this->dbcon->close();        }        unset($this->result);        unset($this->paramquery);        unset($this->dbcon);    }}?>我正在尝试在这种情况下执行 INSERT 查询。并且我想在查询成功执行时获得成功结果或标志。但是在对象的 var_dump 中我得到了一些不相关的数据,如果我使用 echo 我得到一个错误,该对象无法转换为字符串。我只想获得 0 表示查询执行失败、损坏或问题,以及 1 表示完成、成功、正常状态。我什么时候在代码中出错了?编辑:你们能告诉我这个简单的脚本有什么问题吗?此脚本的主要目标是连接到 mysql 服务器并尽可能快地、尽可能安全地执行所有可能的查询。完整项目来源:https : //github.com/FSMySQL/PHP-FSMySQL
查看完整描述

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']);

正如您在上面了解到的,不需要“成功执行查询时的标志”。就好像总是成功一样。如果出现错误,它将在没有任何条件的情况下出现(如果您在索引中包含错误处理程序脚本,则会正确处理实时站点上的错误)。


查看完整回答
反对 回复 2021-11-19
?
慕姐8265434

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 我同意这个评论,我认为你的课程应该用于教育目的,因为它有多个严重的缺陷。


查看完整回答
反对 回复 2021-11-19
?
眼眸繁星

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 手册中阅读有关异常的更多信息


查看完整回答
反对 回复 2021-11-19
  • 3 回答
  • 0 关注
  • 193 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信