简体   繁体   English

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

[英]No true result return in insert query

This is the class I have created which I am using for the queries:这是我创建的用于查询的类:

<?php
mysqli_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);
    }
}
?>

The index.php file code is this: index.php 文件代码是这样的:

<?php

require_once('connection.php');

$DBX = new DBConnect();

$DBX->dbquery('INSERT INTO `xathx_key` (`license`, `client`, `server`, `uniquex`) VALUES (?, ?, ?, ?)', array('ssss', '1', '3', '5', '7'));

var_dump($DBX);
unset($DBX)
?>

I am trying to do an INSERT query in this instance.我正在尝试在这种情况下执行 INSERT 查询。 And I want to get a success result or flag when the query is executed successfully.并且我想在查询成功执行时获得成功结果或标志。 But in the var_dump of the object I get some irrelevant data and if I use echo I get an error that the object cannot be converted to a string.但是在对象的 var_dump 中我得到了一些不相关的数据,如果我使用 echo 我得到一个错误,该对象无法转换为字符串。 I just want to get a 0 for query execution failure, corruption or problem and a 1 for completion, success, ok status.我只想获得 0 表示查询执行失败、损坏或问题,以及 1 表示完成、成功、正常状态。 When am I going wrong in the code?我什么时候在代码中出错了?

EDIT: Can you guys just tell me what are the things that are wrong with this simple script?编辑:你们能告诉我这个简单的脚本有什么问题吗? The main goal of this script is to connect to mysql server and execute all possible queries as fast as possible, as securely as possible.该脚本的主要目标是连接到 mysql 服务器并尽可能快地、尽可能安全地执行所有可能的查询。

Full Project Source: https://github.com/FSMySQL/PHP-FSMySQL完整项目来源: https : //github.com/FSMySQL/PHP-FSMySQL

The main goal of this script is to connect to mysql server and execute all possible queries as fast as possible, as securely as possible. 该脚本的主要目标是连接到mysql服务器,并尽可能安全地执行所有可能的查询。

The goal is a good one but the implementation could benefit from many improvements. 目标是一个很好的目标,但可以从许多改进中受益。

Disclaimer: there will be a lot of links to my own site because I am helping people with PHP for 20+ years and got an obsession with writing articles about most common issues. 免责声明:将有很多链接到我自己的网站,因为我在20多年的时间里一直在帮助使用PHP的人们,并且对撰写有关最常见问题的文章很着迷。

The concept of error reporting 错误报告的概念

First of all, you need to change the concept of error reporting . 首先,您需要更改错误报告的概念 Your exit() approach would be a nightmare for a programmer, as error messages are a vital source of information when something goes wrong . 您的exit()方法对于程序员来说将是一场噩梦 ,因为当出现问题时 ,错误消息是至关重要的信息源 A programmer should go at any lengths trying to get the error message in the full detail. 程序员应不遗余力地尝试获取完整的错误消息。 In my article, PHP error reporting , I do explain how to make error reporting both programmer- and user-friendly. 在我的文章PHP错误报告中 ,我确实解释了如何使错误报告既对程序员又对用户友好。 In short, you shouldn't catch errors on the spot, but have a single dedicated place to report errors and exceptions, and then it could be easily configured depends on the current server's role. 简而言之,您不应该当场捕获错误,而应该在单个位置报告错误和异常,然后可以根据当前服务器的角色轻松进行配置。

Although, as suggested in the other answer, you could use a global try-catch block in your index.php file to act as such a global error handler, I would prefer a dedicated error handler script, as explained in the article above. 尽管,正如另一个答案中所建议的那样,您可以在index.php文件中使用全局try-catch块充当此类全局错误处理程序,但我还是希望使用专用的错误处理程序脚本,如上面的文章中所述。 It will make your code better organized and make index.php less bloated. 这将使您的代码井井有条,并减少index.php的膨胀。

Besides, your idea of having "a true result return in insert query" contradicts with your intention to use exceptions. 此外,您的“在插入查询中返回真实结果”的想法与您使用异常的意图相矛盾。 When one is using exceptions, there is no point to verify the immediate function's result. 当使用异常时,没有必要验证立即函数的结果。 In case of error it will just bubble up to the error handler or a catch block, so, it will never reach the condition. 万一发生错误,它只会冒泡到错误处理程序或catch块,因此,它将永远不会达到条件。 A quick example: 一个简单的例子:

function test() {
    throw new Exception("Test");
    return false;
}
$result = test();
if ($result === false) {
    echo "false";
}

The code execution in this example will never reach the condition , therefore making your functions return false on error useless. 此示例中的代码执行永远不会达到条件 ,因此使您的函数在错误时返回false毫无用处。 Which, in turn, makes returning true on success superfluous. 反过来,这使得在成功时返回真实是多余的。 Just return a meaningful result but don't use it as flag: simply write your code without any conditions, as though everything is fine. 只是返回有意义的结果,但不要将其用作标志:只需编写代码而没有任何条件,就好像一切都很好。 Remember that you have your error handling code elsewhere that will be magically invoked in case of error. 请记住,您在其他地方有错误处理代码,如果发生错误,这些代码将被神奇地调用。

Connection 连接

As explained in my other article, How to connect properly using mysqli , there is a slight chance to reveal connection credentials in case of a connection error. 正如我在另一篇文章“ 如何使用mysqli正确连接”中所解释的那样,如果出现连接错误,则有少许机会显示连接凭据。 To avoid even a possibility but keep the programmer informed we have to throw a brand new exception , however keeping the error information - so the stack trace will begin from the throw line, and thus contain no sensitive information. 为了避免发生这种情况,但要使程序员知道,我们必须抛出一个全新的异常 ,但是要保留错误信息-因此堆栈跟踪将从throw行开始,因此不包含任何敏感信息。

Also, the connection code lacks an essential part - setting the correct charset . 而且,连接代码缺少必要的部分- 设置正确的字符集 Although in MySQL 8 the correct charset is set by default, it's better to make it explicit. 尽管在MySQL 8中默认设置了正确的字符集,但最好将其明确化。

Also, making a mysqli statement a class variable is a grave mistake that will lead to race condition errors . 同样,使mysqli语句成为类变量也是一个严重的错误,它将导致竞争条件错误 The only state that your class should keep is that related to the connection but not a single class variable should be used for a statement. 您的类应保留的唯一状态是与连接有关的状态,但不能将单个类变量用于语句。

So let's rewrite your constructor based on the code from the article above: 因此,让我们根据以上文章中的代码重写您的构造函数:

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());
    }
}

The dbquery function dbquery函数

The function is, frankly, weird. 坦率地说,该功能很奇怪。 It's a strange mix between prepared statements and escaping. 准备好的语句和转义之间是奇怪的混合。 Let's rewrite it based on my mysqli helper function that actually utilizes mysqli prepared statements 让我们根据我的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();
}

Now this function fulfills your desire for secure SQL queries 现在,此功能可以满足您对安全SQL查询的需求

So finally we can rewrite your index.php 所以最后我们可以重写您的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']);

Just as you learned above, there is no need for a "flag when the query is executed successfully". 就像您在上面学到的那样,不需要“成功执行查询时的标志”。 Just act as though there is always a success. 就像总能成功一样。 In case of error it will appear without any conditions (an on a live site will be handled properly if you include an error handler script in your index). 如果出现错误,它将无条件显示(如果在索引中包含错误处理程序脚本,则将正确处理实时站点上的错误)。

You have a problem with 你有一个问题

$this->result = $this->paramquery->get_result();

because mysqli_stmt::get_result returns a resultset for successful SELECT queries, or FALSE for other DML queries or on failure. 因为mysqli_stmt::get_result returns a resultset for successful SELECT queries, or FALSE for other DML queries or on failure.

Other DML-queries are INSERT, UPDATE, DELETE. Other DML-queries是INSERT,UPDATE,DELETE。 And that's exactly what you have in the example. 这就是示例中的内容。

To resolve your problem you can modify the class by adding some extra-checks to $mysqli->errno : 要解决您的问题,您可以通过向$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 I agree with this comment and I think that your class should be used for educational purposes only because it has multiple serious flaws. PS:我同意这一评论 ,我认为您的课程仅应用于教育目的,因为它有多个严重缺陷。

In your DBConnect Class, you have try catch blocks. 在您的DBConnect类中,您有try catch块。 But your catch blocks are simply terminating the request using exit statement. 但是您的catch块只是使用exit语句终止了请求。 Your Class should not be doing that. 您的班级不应这样做。

Imagine you deploy this on production and for some reason the DB Connection Fails. 假设您将其部署在生产环境中,并且由于某种原因数据库连接失败。 In that case User will simply see a white screen with Message "Database Connection Failed" which would not look professional at all. 在这种情况下,用户将仅看到带有“数据库连接失败”消息的白色屏幕,这看起来一点也不专业。

Instead your class should pass this information back to the index.php which called the method of this Class and let index.php handle the Error Message or Exception. 相反,您的类应该将此信息传递回index.php ,后者调用了该类的方法,并让index.php处理错误消息或异常。

So I would make following changes to your code: 因此,我将对您的代码进行以下更改:

  1. DBConnect Class should throw an Exception rather than terminating the execution of the program completely. DBConnect类应该抛出一个异常,而不是完全终止程序的执行。 Below is how the __contruct() should look. 下面是__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;
        }
    }

You will need to change the other methods accordingly. 您将需要相应地更改其他方法。

  1. In your index.php File, you should be looking to catch the above exception. index.php文件中,您应该寻找上述异常。 So you should move your code in a Try Catch Block to catch that exception. 因此,您应该将代码移到“尝试捕获”块中以捕获该异常。
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) 

So this will catch the Exception in case the DB Connection Fails as well as when the Insert Query Fails. 因此,这将在数据库连接失败以及插入查询失败时捕获到异常。 You can write the exception to the logs so that you can check them later and you can display any appropriate error message to user based on the exception caused. 您可以将异常写入日志,以便以后检查它们,并可以根据引起的异常向用户显示任何适当的错误消息。

You could read more on Exceptions in PHP Manual 您可以在PHP手册中阅读有关异常的更多信息

I think that You looking for : return true; 我认为您正在寻找: return true; or return 1; return 1; After successful insertion of record or query execution. 成功插入记录或查询后。

            $this->db->update('table_name',$Array_to_insert);                 
            $last_id = $this->db->insert_id();
            if($this->db->affected_rows() == 1){ 
              return TRUE;
            }
            else { 
              return FALSE;
            }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM