I have a decent understanding of PHP errors (I'm not using or die() as much as I used to) but I still don't fully understand how to deliver the fatal error messages to the user in a way that isn't plain text in the upper left hand corner.
Say I have this code:
try {
$conn = new PDO("mysql:host=host; dbname=userDB", $username, $password);
$stmt = $conn->prepare("UPDATE employee SET password = :newpass WHERE password = :tempPass");
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt->execute(array('tempPass' => $tempPass, 'newpass' => $newpassword));
echo'success!<br>';
echo"<a href='main_login.php'>Back</a>";
}
catch(PDOException $e) {
echo 'ERROR: '. $e->getMessage();
}
That's all well and good, but whether it's successful or not, it's an ugly message of affirmation.
Should I be redirecting my users to a different page to deliver this message?
If so, how should I store/transport the messages to the individual page? I don't want to have to create user_success.php, user_failure.php, user_epic_failure.php, every_other_case.php. It's not efficient and it limits what I can do.
I've heard that storing these messages into a session error variable is a good way to do this but is it the best way to do this? Should there be a dedicated error page and dedicated success page that just serve as templates to which I pass my messages?
I just want pretty error messages. Is that so much to ask?
never display system error message to the user, this could give a potential hacker information about your system. have a generic error page that you redirect to from the catch clause if a fatal error occurs.
for all other errors that don't cause a fatal error and stop the code executing, just continue executing your code and display an error message on top of your page if necessary.
Related
I have had a few nerve racking days trying to get a good error handling system in place within my site.
My error handling system is only focusing on unexpected errors e.g. mysqli errors
My site runs many mysqli queries meaning there is potential for errors to occur.
There is 3 parts to my system, and every one I am unsure on its place in best practices as well as efficiency.
Step 1 : catching the error
$query = "
SELECT * FROM `users_account_activations` WHERE `user_ip` =?
";
$statement = $databaseHandler->mysqli->prepare($query);
$statement->bind_param('s', $userIp);
$statement->execute();
$statement->store_result();
//record error, if any
$databaseHandler->mysqli->error ? error = true : error = false;
Is this a good way of catching the presents of an error somewhere in a prepared statement?
Will looking for errors at the end of the query not catch a error say in the prepare stage? or when the prepare stage fails all other fails (like falling dominoes)
Step 2 : recording the error
error_log("Could not process query...", 3, 'log/default.log');
Is this a suitible way of recording a error? as aposed to the systems that opens a file steam?
Step 3 : handling the after math
Now that there is a error I need to decide on how to move forward, my system intails exiting the script and going to a standard error page saying "opps! something went wrong".
header('location: errorpage.php'); exit();
is changing the header a good way of doing this? I am aware of the limitation of header regarding when you can use it.
Is there a better way for handing errors, this system is intended for unexpected errors. Expected errors are took care of and displayed to the users a different way.
Yes, you are right with your doubts - all the three steps are wrong.
First, for some very strange reason you are not recording the error message itself. How it is supposed to fix the error without error message? What's the use of logging something like "Could not process query..."?
Next, you have to check the result of every operation - so, prepare have to be checked too.
Next, it will be hard to spot the error without knowing where it happened. Some debug backtrace have to be included in the error message.
Next, there shouldn't be a Location header but just Status:500. So, instead of redirecting to error page, just include it.
Finally, all the aforementioned tasks have to be performed in a single place, namely - in the function registered as a custom error handler
So, the scenario have to be like this
in your bootstrap file create a code like this
set_error_handler("myErrorHandler");
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
error_log("$errstr in $errfile:$errline");
header('HTTP/1.1 500 Internal Server Error', TRUE, 500);
readfile("500.html");
exit;
}
then, make your mysqli code like this
$stmt = $mysqli->prepare("qwefq") or trigger_error($mysqli->error);
and have all your errors logged
How would I go about getting PDO statements to generate a safe error message? I don't want the user to see the error message. I want them to get directed to a page that says a clean message, "Whoops something unexpected happened!". I would also like to log the errors in a database to review and catch errors others are generating.
I'm using PHP and MySQL.
I found that when you make your connection you can set your error handling like this.
$dbh = new PDO($dsn, $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Anyone do anything like this before?
So this is just a suggestion as I have never tried this but after thinking about it a bit I think it would be an interesting option to explore. As I am fairly new to PHP & PDO I'm sure there are other and better ways.
Perhaps you could try using the try function of PHP and then instead of echo'ing (if failed) the PDOException you could run another function that prints it to a text file. Something like.
<?php
try {
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
foreach($dbh->query('SELECT * from FOO') as $row) {
print_r($row);
}
$dbh = null;
} catch (PDOException $e) {
$strFileName = 'whatever.txt';
if(!is_writable($strFileName))
die('Change permisions to ' . $strFileName);
$handle = fopen($strFileName, 'a+');
fwrite($handle, "\r" . $e->getMessage() . "\r");
fclose($handle);
}
?>
This way you would avoid a DB connection (which is the problem I guess) but still save the error.
You would perhaps want to omit the echo'd text after die within the if statement.
I think it is better to write your logs to a file, instead of a database. Especially since you want to log PDO errors, which indicate something is wrong with your database connection.
You can show the user a nice error page by catching your errors. You can redirect your users to your error page then, in case something went wrong.
You have to understand that PDO do not generate a "safe" or "unsafe" error message. It does generate an error message. That's all. The rest is is the responsibility of site-wide PHP settings.
PDO is not the only source of errors. Why care of PDO errors only? Why not to handle ALL errors the same way?
Want errors logged? It's a matter of one PHP ini setting.
Want errors not to be displayed? It's a matter of one PHP ini setting.
Want generic error page to be shown? It's a matter of simple function that will handle all errors at once.
Everything can be done proper and straight way, without wrapping every statement into try catch. Without writing into log manually. Without even single additional line of code.
You need to set up PHP error handling, not PDO.
And of course, it makes absolutely no sense in trying to store a database error in the same database that failed you right now. Errors have to go into error log on a live server and on screen - on a local development PC.
Anyone do anything like this before?
Sure. Every single one of 1000000s sites in the world. The way described above.
I'm fairly new to PDO. I have a try and catch which catches and displays errors when something doesnt exist i.e a table.
However, how can i show the error message/cause for sql failed commands.
For example below i was trying to insert the word "enabled" into a tiny int column - however, only showed me a blank screen - had to debug myself. How can i show SQL failed error messages?
$db = new PDO('mysql:host='.$dateBaseHost.';dbname='.$dateBaseName, $dateBaseUsername, $dateBasePassword);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// set/get variables
$id = (isset($_GET['id']) === true) ? $_GET['id'] : die("ID not set") ; // ? : shorthand if else
$action = (isset($_GET['action']) === true) ? $_GET['action'] : die("Action not set") ; // ? : shorthand if else
// query
$query = $db->prepare(" UPDATE `telephoneCountries` SET `enabled`= :action WHERE `id` = :id ");
// bind parameters - avoids SQL injection
$query->bindValue(':id', $id);
$query->bindValue(':action', $action);
// try... if not catch exception
try {
// run the query
$query->execute();
}
catch (PDOException $e){
//sendErrorMail($e->getMessage(), $e->getFile(), $e->getLine());
echo $e->getMessage();
echo $e->getFile();
echo $e->getLine();
}
i was trying to insert the word "enabled" into a tiny int column
it's fairly OK to mysql. 0 will be inserted.
how can i show the error message/cause for sql failed commands.
for the real errors you have to just setup PHP to display them
ini_set('display_errors',1);
so - you'll be able to see every uncaught exception.
Also, if you are only going to display an error message, but not handle the error itself, just don't use try..catch at all. PHP will do all the job already. That's the point.
Most people do confuse error reporting with error handling. The latter shouldn't be used for the former. When dealing with error messages, your only goal is to make PHP to raise them, and to set up the proper destination:
on a development server an error message have to be show on-screen
on a live sever it shouldn't be shown, but logged instead.
without all these try-catch blocks you'll be able to control error messages (including non-exceptions) by means of a couple ini settings or single error handler function (which I mentioned to you in the other answer).
use try..catch only if you are going to handle the error itself - say, to connect to another server for example.
So, to answer your question more verbosely:
Set PDO in exception mode. Done already.
Remove all try..catch blocks that deals with error messages only.
Setup PHP to show errors on a development server using ini directive above.
On a live server it is strongly recommended to log errors instead of emailing them. But if you still want it this way - use single custom exception handler function to send emails instead of hundreds try..catch blocks
What is the "proper" way to deal with errors when manipulating a sql database with php?
What Im currently doing looks like this:
$connection = new mysqli('hostname', 'user', 'pass', 'database');
if ($connection->connect_errno) {
reportError("DB_CONNECTION_ERROR", $connection->connect_errno, $connection->connect_error);
displayError("DB_CONNECTION_ERROR");
}
$stmt = $connection->stmt_init();
$q = "query";
$stmt->prepare($q);
$stmt->bind_param('s', $username);
$stmt->execute();
reportError() is part of an error handling file I wrote and logs the error in a database
displayError() is part of the same file and tells the page what to display (as opposed to displaying the actual error).
However Im not sure of how to check for other errors, such as whether a statement was successfully prepared or whether a query was successful. Any recommendations appreciated!
Don't you find it quite odd to write database connection errors... into database?
I see also no point in having custom displayError() function. It should be generic _503() function, sending corresponding header along with general excuses.
I see no point in having custom logError() function either. PHP quite capable to log errors itself. trigger_error() serves me best.
Im not sure of how to check for other errors, such as whether a statement was successfully prepared
Ah, this one. Exceptions.
Mysqli should throw an exception if something went wrong. See mysqli_sql_exception for more details.
In your client code, you can then wrap your code in try/catch blocks:
try {
} catch (Exception $e) {
}
Sometimes, there are exceptions that can't be solved within a try/catch block, for example, the database server is down, and a site that is heavily reliant on the database would not be able to function anyway.
For those very critical problems, you can allow the exception to bubble upwards. You should then set an exception handler at the beginning of your script to catch those exceptions, notify the administrator and do some logging, then display an 500 error page to the user.
I am working on my first major PHP/MySQL application. I use the Exception handling mechanism to handle possible DB errors. On some pages, I use several queries to obtain the relevant data from the database. The part of the page issuesn those queries is within one try-catch block and I write a customized error message in the catch block.
My problem: the queries are within different blocks on my page, and when a DB exception is thrown, processing immediately goes to the catch block and makes it not really possible to render the page in valid XHTML because in the catch block it is not known which XHTML tags should be closed.
I was thinking about redirecting to a custom error page showing the error mesage but this appears to be discouraged by some people. I think this should be a pretty trivial issue but wonder what is the recommended practice.
Hope for some hints!
1) Change the default error handler. Log them in a database
2) use output buffering
3) last line of your Catch{} block, have it do a header("location: error.html") redirect to a generic error handler.
You should use ob_start() to start buffering the output, and then you have finished to render all the HTML, use ob_flush() to send the HTML code back to the user.
If an error occured, you can generate a special page by calling ob_clean() to clean the buffer and then display your error page.
Exemple :
ob_start();
echo "My title";
try{
$myDB = Database::getInstance();
$userName = $myDB->query("SELECT name FROM user"); // send an exception
echo "Welcome ".$userName;
} catch (Exception $e) {
ob_clean();
echo "Error, please try again";
}
ob_flush();
I'm shure that DB query error is mostly debug enviroment issue or code error. I also prefer to validate and escape values in DB query before running it and show validation result, when it failed.
So, if DB exception even appeared, i log it (using simple error_log, including full request data, get, post, url, referrer) and show 500 error page without any redirect. I think, that redirect is a bad practice - you can't refresh page and repeat error, visitors and QA can't send you invalid page link.
I used the ob_Start(), ob_flush() and ob_clean() method and it does what I excepted so I keep using this.
I will wonder whether this is considered as good practice, IMHO generating invalid XHTML should always be avoided.
Of course an error in the query is a bug and one can argue whether this should be handled in the production code. But my guess is that in the future a lot of maintenance will be done and errors will be inevitable. And they should be presented as nice as possible and surely not in the form of a white blank screen...