I'm doing mysql queries with PHP5 and PDO.
I'm trying to handle exceptions from queries using try/catch. But if, for example, I have a syntax error like this :
try{
$sql = 'IggggNSERT INTO t_table (ID, MONTH) VALUES (:ID, :MONTH)';
$r = $conn->prepare($sql);
$r->bindValue(':ID', $id);
$r->bindValue(':MONTH', $month);
$r->execute();
return $r;
}
catch (Exception $e) {
die('Error');
}
I get this fatal error :
PHP Fatal error: Call to a member function bindValue() on a non-object
But no exception is raised and my catch block is not executed.
How could I handle this so I could rollback previous queries?
PDO will only throw an exception if the problem happens from within PDO. The error that you're getting is in reference to you accessing $r->bindValue despite $r failing to initialize.
In normal operation, you shouldn't ever get any syntax errors with your SQL.
You can however try setting the following line in your database file:
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
As far as I understand from PHP.NET, prepare() throws an exception if this line is set, which should set off the catch statement.
PHP.NET PDO::prepare
If the database server successfully prepares the statement, PDO::prepare() returns a PDOStatement object. If the database server cannot successfully prepare the statement, PDO::prepare() returns FALSE or emits PDOException (depending on error handling).
Related
Get info passed by POST method, and trim all space in the string, then start a new pdo instance, connect mysql, and insert info passed by POST into table.
$title = trim($_POST["title"]);
$content = trim($_POST["content"]);
$dsn = "mysql:host=localhost;dbname=blog";
$con = new PDO($dsn,"root","xxxx");
$title = $con->quote($title);
$content = $con->quote($content);
try
{
$sql = "insert into tmp (`title`,`content`) values('$title','$content')";
$stmt = $con->prepare($sql);
$stmt->execute();
}
catch(PDOException $e)
{
echo $e->getMessage();
}
The above is my PHP code to make the job done,the most import command is
insert into tmp (`title`,`content`) values('$title','$content')";
No error info is shown by running the above PHP code, and no error exists in /var/log/mysql/error.log, but info has not been inserted into the database.
I changed the
insert into tmp (`title`,`content`) values('$title','$content')";
into
insert into tmp (`title`,`content`) values($title,$content)";
The info passed by POST can be inserted into mysql now, the issue that confuses me is that:
echo $e->getMessage(); take no effect at all.
no error info in /var/log/mysql/error.log
How can I catch these errors?
The exception you are trying to catch will never be thrown, because you need to tell PDO how you want it to handle errors.
$con = new PDO($dsn,"root","xxxx");
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Otherwise, the default PDO::ERRMODE_SILENT will be used:
This is the default mode. PDO will simply set the error code for you to inspect using the PDO::errorCode() and PDO::errorInfo() methods on both the statement and database objects; if the error resulted from a call on a statement object, you would invoke the PDOStatement::errorCode() or PDOStatement::errorInfo() method on that object. If the error resulted from a call on the database object, you would invoke those methods on the database object instead.
Tangentially, you should be using prepared statements. You are using a prepare() call, but you are not parametrizing the query and binding the variables as you should. Using quote() is not secure enough.
2020 Update:
Interestingly, starting with PHP 8, the default behaviour for PDO will change and will throw exceptions by default. The change was voted on this RFC, which mentions:
The current default error mode for PDO is silent. This means that when an SQL error occurs, no errors or warnings may be emitted and no exceptions thrown unless the developer implements their own explicit error handling.
This causes issues for new developers because the only errors they often see from PDO code are knock-on errors such as “call to fetch() on non-object” - there's no indication that the SQL query (or other action) failed or why.
When PHP 8 is released on November 2020, the default error mode will be PDO::ERRMODE_EXCEPTION.
after move all rowCount() Functions return fatal error
Fatal error: Call to a member function rowCount() on a non-object
i use this function like this :
$co = $pdo->query("SELECT * FROM `tbl_users`");
$pages->items_total = $co->rowCount();
This means something went wrong while executing the query. Perhaps something went wrong with the update and MySQL isn't running anymore? Verify this, make sure MySQL is running.
Also, you can try to run the same query in PhpMyAdmin to see if that works. If it does, you're sure this is a problem with PDO. If it doesn't, something must be wrong with the MySQL server.
But perhaps the easiest way to debug is to do something like this:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
With this, PDO will throw an exception when the query fails. Then put the query in a try ... catch block:
try {
$co = $pdo->query("SELECT * FROM `tbl_users`");
$pages->items_total = $co->rowCount();
} catch (PDOException $e) {
echo $e->getMessage();
}
This will give you more debug info. When the query fails, the exception will be caught by the catch block, and the message will be outputted. This message usually tells you where the problem is.
In my Symfony 1.4 project in one of my class.php file I used the following codes to execute query and fetch object.
$statement = Doctrine_Manager::connection()->execute($query);
$resultset = $statement->fetchAll(PDO::FETCH_OBJ);
I tried to use try-catch block to catch any run-time exceptions. I can easily do that for the first line like
try {
$statement = Doctrine_Manager::connection()->execute($query);
}
catch (Exception $exc) {
echo "custom error message";
}
But, I this dosen't work for the second line. It always show the following error when I run the page
Fatal error: Call to a member function fetchAll() on a non-object in
\lib\model\doctrine\DeductionInfo.class.php on line 104
How can I resolve this?
Of course it seems to be an invalid query or something like that, resulting in a non-object in your var $statement. Debug or var_dump your $statement var at first.
Doctrine btw is on top of PDO. By default a PDO construct throws an exception on error. But you have to set error handling for quering to exception (http://php.net/manual/en/pdo.error-handling.php) if you want to use try-catch statements. I don't know exactly the way Doctrine 1 handles this.
Every once in a while I get an error such as the following with PDO:
Error!: SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
Is there any way to get a more specific error, such as a line number, filename, the parameter that is missing, etc., instead of a vague message?
Firstly, ensure that you have PDO set to throw exceptions on error:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Now, ensure that every PDO operation/set of operations is enclosed a try/catch block, something like this:
try {
$stmt = $pdo->prepare("SELECT * FROM Whatever");
// ...yada yada yada, your PDO code goes here
} catch (PDOException $e) {
// This will echo the error message along with the file/line no on which the
// exception was thrown. You could e.g. log the string to a file instead.
echo $e->getMessage().' in '.$e->getFile().' on line '.$e->getLine();
}
All exceptions extend from the base Exception class, and so inherit it's methods and the information it carries about errors.
As a side note, if using PDO with MySQL, ensure that you disable emulated prepared statements. See here for more info on how to do this and why you should.
What you can do is register a global error handler and a global exception handler. Those functions receive filename, linenumber and error message. In those functions, echo the data to the screen and die.
This question already has answers here:
What to do with mysqli problems? Errors like mysqli_fetch_array(): Argument #1 must be of type mysqli_result and such
(2 answers)
Closed 5 years ago.
I'm trying to get my head around MySQli and I'm confused by the error reporting.
I am using the return value of the MySQLi 'prepare' statement to detect errors when executing SQL, like this:
$stmt_test = $mysqliDatabaseConnection->stmt_init();
if($stmt_test->prepare("INSERT INTO testtable VALUES (23,44,56)"))
{
$stmt_test->execute();
$stmt_test->close();
}
else echo("Statement failed: ". $stmt_test->error . "<br>");
But, is the return value of the prepare statement only detecting if there is an error in the preperation of the SQL statement and not detecting execution errors? If so should I therefore change my execute line to flag errors as well like this:
if($stmt_test->execute()) $errorflag=true;
And then just to be safe should I also do the following after the statement has executed:
if($stmt_test->errno) {$errorflag=true;}
...Or was I OK to start with and the return value on the MySQLi prepare' statement captures all errors associated with the complete execution of the query it defines?
Thanks
C
Each method of mysqli can fail. Luckily, nowadays mysqli can report every problem to you, all you need is ask. Simply add this single line to the connection code,
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
And after that every error will reveal itself. No need to test any return values ever, just write your statements right away:
$stmt = $mysqli->prepare("INSERT INTO testtable VALUES (?,?,?)");
$stmt->bind_param('iii', $x, $y, $z);
$stmt->execute();
When the error occurs at any step, it will throw a usual PHP Exception that can be handled or just reported the same way as any other PHP error. Just make sure you configured PHP error reporting properly, i.e. on the dev server errors are displayed on-screen and on the production server errors are never displayed but logged instead.
Completeness
You need to check both $mysqli and $statement. If they are false, you need to output $mysqli->error or $statement->error respectively.
Efficiency
For simple scripts that may terminate, I use simple one-liners that trigger a PHP error with the message. For a more complex application, an error warning system should be activated instead, for example by throwing an exception.
Usage example 1: Simple script
# This is in a simple command line script
$mysqli = new mysqli('localhost', 'buzUser', 'buzPassword');
$q = "UPDATE foo SET bar=1";
($statement = $mysqli->prepare($q)) or trigger_error($mysqli->error, E_USER_ERROR);
$statement->execute() or trigger_error($statement->error, E_USER_ERROR);
Usage example 2: Application
# This is part of an application
class FuzDatabaseException extends Exception {
}
class Foo {
public $mysqli;
public function __construct(mysqli $mysqli) {
$this->mysqli = $mysqli;
}
public function updateBar() {
$q = "UPDATE foo SET bar=1";
$statement = $this->mysqli->prepare($q);
if (!$statement) {
throw new FuzDatabaseException($mysqli->error);
}
if (!$statement->execute()) {
throw new FuzDatabaseException($statement->error);
}
}
}
$foo = new Foo(new mysqli('localhost','buzUser','buzPassword'));
try {
$foo->updateBar();
} catch (FuzDatabaseException $e)
$msg = $e->getMessage();
// Now send warning emails, write log
}
Not sure if this answers your question or not. Sorry if not
To get the error reported from the mysql database about your query you need to use your connection object as the focus.
so:
echo $mysqliDatabaseConnection->error
would echo the error being sent from mysql about your query.
Hope that helps