When using PHP's mysqli extension for database operations, we often use prepared statements to improve security and performance. At the same time, developers often want to accurately capture possible errors such as SQL syntax errors during execution. But you may encounter such a confusing problem:
So, what's going on? This article will conduct in-depth analysis of this problem and provide practical solutions.
See the following sample code:
$mysqli = new mysqli("localhost", "user", "password", "testdb");
// Syntax error:One missing FROM
$sql = "SELECT id name users WHERE id = ?";
$stmt = $mysqli->prepare($sql);
if (!$stmt) {
echo "Prepare failed: " . $mysqli->error; // The correct way to do it
} else {
$stmt->bind_param("i", $id);
$id = 1;
$stmt->execute();
if ($stmt->error) {
echo "Execute error: " . $stmt->error; // 不会捕捉到Syntax error
}
$stmt->close();
}
$mysqli->close();
Prepare failed: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version...
As you can see, SQL syntax errors do not enter $stmt->error at all , but are caught by $mysqli->error in the prepare() stage.
We need to understand the division of labor between mysqli and mysqli_stmt in PHP:
mysqli::prepare() is a method called by the database connection object. If SQL has syntax errors, the stmt object will not be generated at all , so $stmt is false .
mysqli_stmt::$error only has a value after the statement is successfully prepared and a runtime error occurs (such as the binding variable type does not match during execution, foreign key constraints fail, etc.).
So, SQL syntax errors won't and cannot be caught with $stmt->error because it won't even create a stmt object .
in other words:
SQL syntax errors occur in the prepare() stage and must be judged by the return value of $mysqli->error or mysqli::prepare() , rather than waiting for $stmt->execute() .
Rewrite the above code and adopt more secure error handling logic:
$mysqli = new mysqli("localhost", "user", "password", "testdb");
$sql = "SELECT id, name FROM users WHERE id = ?"; // Correct syntax
$stmt = $mysqli->prepare($sql);
if (!$stmt) {
// 检查Syntax error
die("SQL prepare failed: " . $mysqli->error);
}
$stmt->bind_param("i", $id);
$id = 1;
if (!$stmt->execute()) {
// Check for runtime errors
die("Execute failed: " . $stmt->error);
}
$result = $stmt->get_result();
$data = $result->fetch_assoc();
echo "User: " . $data['name'];
$stmt->close();
$mysqli->close();
If you are using the AJAX interface to submit SQL parameters, such as accessing an address like this:
https://gitbox.net/api/get_user.php?id=1
Then you splice the user input into SQL (dangerous!):
$id = $_GET['id'];
$sql = "SELECT * FROM users WHERE id = $id"; // Potential SQL Injection risk
This writing method is easy to write SQL incorrectly during splicing, and prepare() will not be used, and errors are more difficult to locate. Therefore, the following writing method is recommended:
$sql = "SELECT * FROM users WHERE id = ?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("i", $_GET['id']);
This not only avoids SQL injection, but also makes error checking clear and centralized.
SQL syntax errors can only be found in the prepare() stage and cannot be obtained through $stmt->error .
Be sure to check the return value of prepare() and use $mysqli->error to output the error message.
It is recommended to use preprocessing statements to prevent injection, and it is easier to debug and catch errors.
Only by understanding the division of responsibilities between mysqli and mysqli_stmt can we write more robust and secure database interaction code.