I use PDO over my webapp. I use this simple code to ensure that the query is executed successfully & handle the error if it fails
$stmt = // MySQL query;
if($stmt->execute()){
// Do something
} else {
// Handle the error
echo 'some error';
}
It doesn't work because any PDO uncaught exception e.g (duplicate entry primary key) is a fatal error so the PHP script stop execution. I know TRY/CATCH solve this case but i've tons of queries, It'd take long time to use try/catch on each query.
My Question
Is there any way to make PDO exceptions be caught by default to be generalize over my webapp ?
I found the best practice to handle PDO uncaught exception without using try/catch after reading this
What-is-SetAttribute-PDO-ATTR_ERRMODE ?
1 - SET attribute PDO::ATTR_ERRMODE ----- > PDO::ERRMODE_WARNING
PDO::ERRMODE_WARNING // issue warning and continue executing the script
2 - Check error log file of your apache to determine the error
IMP NOTE :
Do this practice only if you already handle errors through your code e.g (storing the php file name and line of the error in database).
You can handle warning by using function error_reporting()
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.
I'm tweaking a legacy database class written for PHP/5.2 that was designed to connect to MySQL and hide all errors. I've configured the PDO instance to throw exceptions:
new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION))
Now I need to adjust my code accordingly to handle the case where functions can throw an exception where they wouldn't before so I head to the manual.
In some cases the manual is explicit, e.g. 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).
In other cases it's kind of vague, e.g. PDO::commit:
Returns TRUE on success or FALSE on failure. Throws a PDOException
if there is no active transaction.
(Can it fail for some other reason and simply return false?)
And there're cases when exceptions are not even mentioned, e.g. PDO::bindValue:
Returns TRUE on success or FALSE on failure.
... even though it's clear to verify that it does throw PDOException on error (at least, on certain errors).
Do I still need to check the return value of methods that return false on error when the manual doesn't say otherwise?
No, when you set PDO::ERRMODE_EXCEPTION there will be always exception for any errors
When you have exceptions enabled and there is an error happening in your code, the code directly stops executing from that function, so it wont return anything.
So to be blund, you don't need to check the return values but if you don't you cannot error anything specific and you would rely fully on PDO to error correctly.
When I created my database system, I take advantage of both if I see an error upcoming, I throw it myself instead. For example $pdo->prepare('') is very much valid but will error upon binding.
Then there are other functions such as fetch that wont error if there are no results in the database, not checking the results from that would be silly.
Now for committing to fail, I believe there is 1 scenario that would cause it to return false without throwing an exception and that is when the connection to the server drops after connecting to the database and before calling PDO::commit, quite good to know if you have a remote database server.
So to answer your question, yes it can fail without throwing an exception, but its timing has to be very specific even more so if you have a local database.
Try this one
try {
$db = new PDO("mysql:host=localhost;dbname=dbname", "username", "password");
}catch( PDOException $Exception ) { $Exception->getMessage( ) ; }
I have seen this question asked before on SO, and none of the answers seem to be complete. So please...
I have code using PDO and PDOStatement. It was originally written to work without exceptions, and I'm converting it to work with.
My simple questions are:
Are there any circumstances in which it is useful or necessary to continue to check the return value of functions for FALSE ( when this means "failure" ), or can I simply execute the method and assume that all kinds of failure will trigger an exception? I saw an example in an answer where someone was recommended to use BOTH try-catch AND to test the return value for FALSE - which, it is IS actually necessary, makes for some very ugly code.
Is there a proper list of which methods may, and which can never, throw an exception? I have seen answers which say "if you find we haven't documented an exception we throw, raise a bug", but that's not altogether helpful. I have seen statements that "the manual page says when an exception can be thrown", but the PDO::query and PDOStatement::execute pages make no mention of exceptions - which surely can't be true ... can it? Essentially I'd like to know whether prepare, bind[things], fetch[all], execute and a few others may or will never, throw stuff.
I don't feel I'm asking the earth, and if I have to I could look at the code, but surely the manual documentation on this should be rock solid.
[edit to add an example]
I now find myself with code blocks like this - I would like to simplify it by removing the test of the return value, but I cannot convince myself that it is correct. Other blocks use execute() and so on.
try {
/* I do not know whether beginTransaction throws an exception when it would otherwise return FALSE.
* If it does then checking the return value is spurious, and the code cam be simplified.
*/
if (FALSE == $customerDb->beginTransaction()) {
Log::add("Database begin transaction failed.",
Log::ERROR);
throw new Exception("Failed to begin a transaction.");
}
} catch (PDOException $e) {
/* The documentation does not mention the possibility of
* beginTransaction() throwing any exception,
* even when we have configured all the other functions to do so.
*/
Log::add("Database begin transaction threw an exception: " . $e->getMessage(),
Log::ERROR);
throw new Exception("Begin transaction threw an exception.");
}
There is three error handling strategies, ERRMODE_SILENT (the default one), ERRMODE_WARNING and ERRMODE_EXCEPTION. Only the last one make PDO throw exceptions if errors occurs, so except if you tell PDO explicitly to run in exception mode with:
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
It will not throw any exception except for PDO:__construct() which will throw an exception if the connection fails, whatever the value of PDO::ATTR_ERRMODE.
From the doc:
PDO::__construct() will always throw a PDOException if the connection
fails regardless of which PDO::ATTR_ERRMODE is currently set. Uncaught
Exceptions are fatal.
I suggest you to read the documentation - it's pretty clear how PDO handle errors.
Update
In your code sample, the exception will never be catched as you typed your catch block exception to PDO_Exception and you're throwing an Exception - which is the lower exception type level. If you want to catch all exceptions type, cast your catch parameter to Exception - currently your catch block capture only PDOException.
That being said, let's focus on the confusion you have about exceptions. There is no mysterious exceptions being thrown when in ERRMODE_SILENT or ERRMODE_WARNING, except the one from the PDO controller - which is documented. People telling otherwise are probably working in a PDO environment they don't really know / control - like a framework who use PDO but throw its own exceptions for queries, or changing the ATTR_ERRMODE in specific cases. I suggest you to focus less on the discussion under docs (as sometimes there could be interesting stuffs in it, most of the time it's comments from confused people) and focus more on the docs itself.
Let's be clear about what happen with errors in PDO.
An error occurs. If it happens in the PDO controller, an exception will be thrown and all next steps will be ignored.
The error will be standardized according to the SQL-92 standard (see this link for all the return codes that exists). From the doc :
PDO standardizes on using SQL-92 SQLSTATE error code strings; individual PDO drivers are responsible for mapping their native codes to the appropriate SQLSTATE codes.
PDO check for the ATTR_ERMODE attribute to know how it should handle this error.
ERRMODE_SILENT (the default mode)
The error will not be reported, so you'll need to check for the return of the PDO functions for false and check the PDO::errorCode(), PDO::errorInfo() or PDOStatement::errorCode(), PDOStatement::errorInfo() depending of the object you're using to get the error details.
ERRMODE_WARNING
Same as ERRMODE_SILENT but an E_WARNING PHP error will be thrown. Could be usefull for developpment, but you still need to check the function returns for false.
ERRMODE_EXCEPTION
A PDO_Exception will be thrown. There will be no need to check the function return for false as when an exception is thrown, the next lines will be skipped and PHP will go to the catch block, or if there is not any catch block it will throw a PHP error. So implementation you suggest is redundant when running in ERRMODE_EXCEPTION.
So yes, the doc doesn't said that x function throw an exception because it will be totally redundant. The error handling page explain everything you need to know.
If you're still not convinced, I suggest to try it by yourself: play with ATTR_ERRMODE and some various PDO functions, and see by yourself.
During the process of my PHP learning I have been trying to read up on the best practices for error reporting and handling, but statements vary person to person and I have struggled to come up with a clear concise way of handling errors in my applications. I use exceptions on things that could go wrong, but for the most part it is hard for me to understand whether an exception should kill the application and display an error page or just be caught and silently dealt with.
Something that seems to elude me is, is there such thing as too much reporting? Every single time you call a function something could go horribly wrong meaning that if you were to confirm every single function call you would have to fill pages with if statements and work out what effect one failure may have on the rest. Is there a concise document or idea for error reporting that could clear this up for me? Are there best practices? What are the best examples of good error handling?
Currently I do the following:
Add important event results to an array to be logged and emailed to me if a fatal error was to occur
Display abstract/generic errors for fatal errors.
Use exceptions for cases that are likely to fail
Turn on error reporting in a development environment and off for live environment
Validate all user input data
Sanitizing invalid user input
Display concise, informative error messages to users without providing a platform for exploitation.
Exceptions are the only thing that you haven't understood IMHO: exceptions are meant to be out of your control, are meant to be caught be dealt with from outside the scope they are thrown in. The try block has a specific limit: it should contain related actions. For example take a database try catch block:
$array = array();
try {
// connect throws exception on fail
// query throws exception on fail
// fetch results into $array
} catch (...) {
$array[0]['default'] = 'me';
$array[0]['default2'] = ...;
...
}
as you can see I put every database related function inside the try block. If the connection fails the query and the fetching is not performed because they would have no sense without a connection. If the querying fails the fetching is skipped because there would be no sense in fetching no results. And if anything goes wrong, I have an empty $array to deal with: so I can, for example, populate it with default data.
Using exceptions like:
$array = array();
try {
if (!file_exists('file.php')) throw new Exception('file does not exists');
include('file.php');
} catch (Exception $e) {
trigger_error($e->getMessage());
}
makes no sense. It just a longer version of:
if (!file_exists('file.php')) trigger_error('file does not exists');
include('file.php');
When establishing a new PDO db handler, I've got to wrap everything into a try-catch to prevent an error message that would print all db access data to the user.
But how about all the other methods like exec(), for example? Must I wrap all of these into a try-catch block? At which point is the PHP documentation telling that an method throws an exception?
First of all, you can set how errors are dealt with by PDO, using the PDO::setAttribute method, to set the PDO::ATTR_ERRMODE (error reporting) option.
In particular, it is possible to configure PDO so it throws exceptions when there's an error, instead of reporting an "error" -- that's what I generally do.
Then, when a method can throw an exception, it should be indicated in it's documentation -- generaly, it's in the "Return value" section.
For instance, PDO::prepare can throw an exception -- depending on error reporting (see what I wrote just before) :
If the database server cannot
successfully prepare the statement,
PDO::prepare() returns FALSE or
emits PDOException (depending on
error handling).
As a sidenote : if you find a function / method that throws an exception, and it's not indicated in its documentation, it might be a good idea to create a bug report (see http://bugs.php.net/ ), so that problem is corrected ;-)
(Errors / mistakes / missing informations in the documentation are treated via the bug-tracker, like any other bug)
You can see if the method throws exceptions by looking at the manual.
If you look at the manual for __construct you'll see at the bottom under Errors/Exceptions that it throws an exception.