Error handling - how to catch? - php

I am trying to understand this: If there are errors in the database like FK issues, Missing tables/columns, or even if the database is dead -> Will this crash the application? I have my website in php. What about application and network related errors? Can these cases be caught for and have a work around without users seeing a non functionaning site or site down message?

In general you must check every single bit of your application, from database connectivity to user input using php. That link helped me some time ago http://www.nyphp.org/PHundamentals/7_PHP-Error-Handling It introduces you to try/catch error handling.

There are several ways to detect errors and handle them in PHP.
Exceptions, and Try-Catch statements.
Here's examples of both.
How you catch database errors will depend on what kind of database it is. If you're using MySQL, then PHP lets you catch query errors like this. Here's the doc on die and mysql_error().
mysql_query( querystuff ) or die( mysql_error() );

Related

Best practices for updating from mysql to PDO

I'm updating a code base from mysql to pdo and this is the first time I've done a project like this so I've been doing research on best practices and would like some input. Here is the old code:
$link = #mysql_connect('localhost', "xxx", "xxx")
or die('Could not connect: ' . mysql_error());
mysql_select_db("xxx") or die('Could not select database');
In my code I'm putting all the login credentials into a separate file and using the ip address, username and password to connect as opposed to localhost.
try {
$pdo = new PDO($dsn, $user, $password);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e){
log_error("Failed to run query", $e->getMessage(), $e->getCode(), array('exception' => $e));
die('Could not connect!');
Two questions, is this a good alternative to using the die method deal with errors and log to the client and also is this the correct way to connect? Is there an advantage to connecting using localhost vs the server IP address? Thanks for the help!
Is this a good alternative to using the die method?
What you're doing is reasonable as part of a migration - it should behave the same way it did before. You might consider, however, not catching that PDOException and allowing it to be thrown all the way up to your global error handler. That's nicer because it's less code, and you're not catching an exception just to die. But before making that change, you should have an idea of the way it will behave in your production systems (will you see the error in your logs)?
Is this the correct way to connect?
Yes, it seems like you're using PDO correctly.
Is there an advantage to connecting using localhost vs the server IP address?
You mean in production? Best practice would be to run your database on a separate server - in which case localhost would obviously not work. If the load is light and you are running the database and PHP server on the same box for now, then it shouldn't matter either way.
Good questions, and I already have all the answers for you (and even answers to questions you didn't ask yet), just follow my article, How to connect to MySQL using PDO.
To answer your questions more directly:
is this a good alternative to using the die method deal with errors
By all means - no.
To be honest, your current approach is not much better than the old one. The code here is inflexible, you have to edit it manually to change the behavior. It would be much better if your code would only throw an error, whereas its processing would be defined elsewhere and easily configurable.
Let alone the die() is still there. Trust me, a site that tells you 'Could not connect!' on a white screen looks awfully unprofessional. You should never ever use die like that.
#mkasberg is right, generally, you don't catch an Exception but let it bubble up to where it will be appropriate to handle it. However, PDO connection is a special case as the stack trace in case of error would contain the db credentials which you likely don't want to show to anyone. To prevent this, I propose to throw a brand new exception that would contain the same error information but no stack trace.
is this the correct way to connect?
Apart from what was said above, without seeing the DSN we cannot tell for sure.
Is there an advantage to connecting using localhost vs the server IP address?
Generally, a hostname is preferred, like with any other service. the IP address could change but thanks to DNS system the domain name would always point at the correct address. However, localhost is a special case, and judging by many questions here on Stack Overflow I would rather recommend to use the IP address, as it could save you a headache or two, like a too big timeout when DNS is misconfigured.

PHP MySQL Error logging and handling - best practice

I'm building a site using PHP which allows users to add in a lot of data to various tables in a MYSQL database. This requires a lot of inserting, updating and dropping of tables in my datatbase, sometimes running several commands in one script.
I'm concerned about catching potential errors occurring when live (I've tested, tested and tested but still want a back up plan).
I've searched everywhere for a solution but cannot find one that would satisfy my needs so wondered if anyone here had any practices they use or advice they can give me.
What I want to happen:
If an error occurs connecting to my database (for instance) I want to display a page or alert window with a "sorry we've had a problem" message with a button to log the error. When a user clicks the button I want to be able to log a mysql_error() to the database with a description of the failed command/function and page name along with time/date stamp which I can track.
Is this something anyone has done before or can offer an alternative? Or is there a built in function that does exactly this which I have missed?
Any advice would be much appreciated.
If you fail connecting to the DB, you won't be able to log the error to the db. The bad connection scenario aside, you should use a php mysql library that supports exceptions (like PDO) and use try-catch blocks to catch error states you want to log.
You'll probably want to just write to the apache error log on DB connection failure (can be done in a try-catch block).

With PHP and mysqli, is it possible to catch all mysqli errors in one place across all PHP scripts?

Is it possible to catch all errors for mysqli calls in one place with one statement or do I have to check each mysqli call individually for an error?
I want to do something along the lines of:
if(mysqli_error_occurs_anywhere_in_web_app) {
die('<html><head></head><body>database error</body></html>');
}
basically if a mysqli error occurs anywhere I want to output an html database error document. is this possible?
You could alternately wrap all your queries on your own query function, instead of calling mysqli_query anywhere directly. For instance, in your own DB object. That way, if you ever have a need to switch DB implementations, you simply have to switch to a new DB object with a slightly different implementation of your query functions, instead of search/replacing gobs of calls to mysqli_query directly. And it also has the benefit of making error handing really easy and centralized.
The first thing you need to ask yourself is whether you want to deal with all database errors in the same way. If you can't connect to your db, that's a serious error and may indicate your db server is down. In that case you may want some kind of urgent alert to be sent to you (if you're not already monitoring your DB another way). If a query fails due to an SQL syntax error it's probably a sign that you're not escaping input data or there is a bug in your code somewhere. In this case you probably want to log as much info as you can so you can debug/sort the problem later.
So, that aside, the first thing you probably need is to wrap your mysqli functions so that you can trap the various errors and deal with them how you need (either by writing your own DB class, or using your own functions) - the PHP docs give examples about how you might start to do this (mysqli docs). Or you might look into PDO which AFAIAA has more useful error handling (a mixture of exceptions and return values).
Then you will need one single point in the code to handle this. If you have some kind of front controller you may be able to put it there. Or you may be able to write your own custom exception handler to achieve what you need (set_exception_handler).
The quickest and dirtiest solution would be to write your own custom error handler to catch and parse all errors and act accordingly (possibly redirect to a db error page having logged any info appropriately). But I did say this was the dirtiest solution right?
You could try setting a global exception handler and checking to see if the caught exception is of the proper class.

exceptions in php... why nobody uses them?

I'm very new to php and while I was looking for examples of how to use sockets I noticed that none of them included exception handling code.
First I thought that maybe php didn't have exceptions... but google told me otherwise. There are tons of articles praising the use of exceptions in php (I come from Java & C#, I'm a converted) but then, in the real examples, no one seems to care about trys/catches.
Is it due to the fact that php didn't have exceptions in previous versions?
Example (pseudocode):
$fp = fsockopen($allTheNeededParams);
if(!$fp){
//error handling
}
fwrite($fp, $out);//<-what if something goes wrong here? the socket is never closed?
fclose($fp);
In other languages, the moment you deal with sockets you see try/catch all over the place. Why not in php?
Two examples from StackOverflow:
Socket question in Java (with exception handling)
Socket question in PHP (no exception handling)
Thanks for your time!
PHP has an apocalypse-themed approach to error handling: if anything goes wrong, the script just ends and any resources it was using (database connections, files, sockets, memory) is freed by the runtime. This makes it less critical to handle such issues than it is in Java or C#, where server code runs continuously — in PHP, an unhandled error condition means a single user is inconvenienced, in Java or C# it might mean a resource leak that ends up bringing the server down for everyone.
And, of course, there's the fact that PHP added exceptions along the way after a huge part of its library of functions was already set in stone, meaning that all those functions use return codes and error reporting instead of exceptions. Replacing errors with exceptions cannot be done at the library level (it would break too much existing code) and at the code level it is an arduous task that involves a lot of boilerplate to detect the error while silencing it, and throw an exception.
PHP was not built with exceptions in mind in the first place.
You don't use exceptions for the sake of exceptions. There must be supporting -and object oriented- code. The system needs to be built with exceptions in mind as a whole. And you must know what they do and what they do not.

PHP - recording errors

What is the best way to record errors experienced by the user?
My initial thought was to make a function that recorded the error with a unique number and maybe a dump of the variables into a record on the database.
Is there a better approach? Should I use a text file log instead?
How about overriding the default PHP errorhandler?
This site should give some basic information: http://www.php.net/manual/en/function.set-error-handler.php and the first comment on http://www.php.net/manual/en/function.set-exception-handler.php
You might also want to store database errors, perhaps some kind of custom function that allows you to use code like:
<?php
$objQueryResult = mysql_query("query here") or some_kind_of_function_here();
?>
You might want to store the recorded errors in a file, which is outside your public html root folder, to make sure people can't access it by accident.
I would also assume, you'd want to store a complete stacktrace in such a file, because then you can actually debug the problem.
When overriding the default errorhandlers, please note you don't forget to send a nice message to the user (and exit the script, when needed).
I would recommend storing:
$_POST
$_GET
A complete dump of
debug_print_backtrace()
Possibly the SQL that triggered this?
I would suggest you to use debug_print_backtrace() to make sure you get a summary of data. The debug_backtrace() function gives about the same information, but it can sometimes just give you too much information.
The code you could use to catch backtraces:
<?php
ob_start();
debug_print_backtrace();
$trace = ob_get_contents();
ob_end_clean();
?>
To store this, you could use a plain text output, if you don't get too much errors, otherwise perhaps use something like sqlite? - Just don't use the same SQL connection to store the errors, as that might trigger more problems, if you're having webserver to SQL connection errors.
Well, at least writing to text files on the local system should be less error prone, thus allowing you to catch DB errors too :)
I would prefer to write a decent dump of the current state to a simple log file. In addition to your "own" state (i.e. your application's variables and objects), you might consider doing a phpinfo() to get inspiration as to which environment and request variables to include.
PEAR::Log is handy for this kind of logging. e.g.
$logger->alert("your message");
$logger->warning("your message");
$logger->notice("your message");
etc.
You can log to a file or to a database, I wrote a PDO enabled sqlite extension , pretty simple.
These are handy to put into exception handling code too.
PEAR::Log
Records: id, logtime, identity, severity 1-7( ie "Alert"), and your message.
I think #Icheb's answer covers it all.
I have tried something new this year in a project that I thought I'd share.
For a PHP based content aggregation / distribution service, an application that runs quietly in the background on some server and you tend to forget, we needed an error reporting system that makes sure we notice errors.
Every error that occurs has an Error ID that is specified in the code:
$success = mysql_query(this_and_that);
if (!$success) log_error ("Failed Query: ".mysql_error(), "MYSQL_123");
Errors get logged in a file, but more importantly sent out by mail to the administrator, together with a full backtrace and variable dump.
To avoid flooding with mails - the service has tens of thousands of users on a good day - error mails get sent out only once every x hours for each error code. When an error of the same code occurs twice within that timespan, no additional mail will be sent. It means that every kind of error gets recorded, but you don't get killed by error messages when it's something that happens to hundreds or thousands of users.
This is fairly easy to implement; the art is getting the error IDs right. You can, for example, give every failed mySQL query in your system the same generic "MYSQL" Error ID. In most cases, that will be too generic and block too much. If you give each mySQL query a unique error ID, you might get flowed with mails and the filtering effect is gone. But wWhen grouped intelligently, this can be a very good setup.
From the usability point of view, the user should not Ever experience errors.
Depending on the error you should make different strategies:
non catchable errors or difficult to catch from PHP, read the logs for each application
Apache
MySQL and DB errors, transactions
prepare php with "site being updated" or error controllers for emergencies.
PHP errors
these should be detected through Exceptions
silenced but not forgotten, don't try to fix them on the fly
log them and treat them
interface errors
an advice: allow user to submit suggestions or bugs
I know this does't cover all, is only an addendum to the others have suggested.

Categories