Using the die() function excessively - php

Is it bad programming practice to use the die(); function excessively when validating data in PHP?
I am building a class where I have used that function more than a dozen times, so that if the validation test fails the entire script dies. Is that good practice, is there a better way I should be doing it? Does this practice vary between languages, are there any programming-wide conventions or best-practices to learn from?
Here's an example:
if($error = $this->checkDate($start)){
echo "START: ".$error."\r\n";
die();
}
if($error = $this->checkDate($end)){
echo "END: ".$error."\r\n";
die();
}
if($start>$end){
$error = "The start date must come <i>after</i> the end date!";
echo $error;
die();
}
if(($end-$start)<(3*24*3600) || ($end-$start)>(3*30*24*3600)){
$error = "The period must be at <i>least</i> 3 days long, and at <i>most</i> 3 months long. This date spans about ".round(($end-$start)/(3600*24*30))." months.";
echo $error;
die();
}
etc, etc, etc...
PS - How is "best-practice" not a tag already??

If you are building a bigger system you probably want more output even if it fails, like templating and such. The way you terminate here would make that hard to accomplish in a clean way.
If your application is intended to be really small, so you would not need to do anything after this validation, you are probably good, but then again you should always build code that is easily extendable in case you need to do so later.
If it were up to me, I would probably throw an exception instead and then handle the exception apropriatly at a higher nesting level.
But then again you will need to make the call yourself based on what your actual intent with this application is. Maybe it is appropriate, but probably not.

There are actually two critical flaws in your approach:
as a matter of fact, there should be not a single die() statement in the production code.
also, no class method should output a word.
Speaking of form validation - your idea of it makes user experience hard and outdated. A good web-site will always show on arror
a form itself
all the entered data
all the errors at once, to let user fix them all, not submit the form again and again until they get to the last error.

Related

How should I approach error handling in PHP? Specifically user input

I've been using PHP for quite a long time now, and I do enjoy it. However, it has come to my attention that my error handling is not up to scratch and for the new project I am working on, I want to adopt a proper error-handling method.
I'm wondering how to handle user input specifically, but also more generally any errors.
I have a case as below as an example:
function check_email($email){
if(empty($email)){
$error='You must enter an email address';
error_log($error);
header('Location: page.php?error='.$error);
exit();
}
if( *doesn't match regex* ){
$error='Not a valid email format';
error_log($error);
header('Location: page.php?error='.$error);
exit();
}
}
I want to both be able to revert to the user with the error message, and also log it in the error_log document.
The above method works fine, but it is super messy code, or at least it feels messy. Any ideas how I can clean this up? I want to be efficient with it because easy-to-write error catchers mean I will write more of them instead of being lazy
Edit: yes, I could wrap that in a function of it's own
function er($error){
error_log($error);
header ('Location:...);
}
Surely there is a more elegant, native solution though?
I have utilised comments below to come up with two individual functions for soft errors and returning user errors
For user errors:
function return_error($msg){
$_SESSION['error']=$msg;
header("location:javascript://history.go(-1)");
exit;
}
For soft errors / unusual behaviour (make_file() function just makes a file if not exist)
function soft_error($e){
$trace=debug_backtrace(-1);
if(isset($trace,$trace[0],$trace[0]['file'],$trace[0]['line'])){
$file=BASE_DIRECTORY.'logs/soft_error.log';
make_file($file);
$log=fopen($file,'a');
fwrite($log,'['.date('Y-m-d H:i:s').'] File: '.$trace[0]['file'].' - Line: '.$trace[0]['line'].' - Error: '.$e.PHP_EOL);
fclose($log);
}
}
For hard errors, there is error_log() or they will be logged automatically based on server settings, so that is fine

PHP exit, return & proper programming standards

Is it ok to include a break or exit command to prevent further code from executing or is this bad programming?
function index()
{
$error = NULL;
if ($_POST){
// validate form
if ($form_validated) {
echo 'this content only';
exit; // or return IS THIS BAD???
} else {
$error = 'form failed';
}
}
echo 'normal page on initial load';
if ($error) { echo '<br />'.$error; }
}
It is OK to prevent further code from executing using exit.
Having said that, whether this is the best way to do it in this particular example is debatable. It is typical to use exit when issuing redirects:
header('Location: /foo');
exit;
In your case, there doesn't seem to be an immediate need to stop the program execution in mid run. You should rather structure your program flow so it always completes, but with different results. It is hard to follow program logic which may terminate somewhere in the middle, so a more logical flow that returns from functions or branches using if..else is usually preferable.
For the example you give:
function index()
{
...
if ($form_validated) {
echo 'this content only';
exit; // or return IS THIS BAD???
} else {
...
}
This is normally called early exit or early return (return is more common). This can be very okay, some people say that early returns make code hard to understand but I'd say it depends on a lot more if a function can be easily read and understood or not.
So the person who decides here whether it is bad or not is you. You need to find some criteria on your own where you draw the line. For example if a function is long (more than 12 lines of code) and contains many of these early returns or even exits, this will make the code more complicated.
Generally early returns can make a functions code less complex which can heavily reduce the number of bugs.
So probably the complexity is a good criteria here.
Additionally I suggest you use exit very carefully. It does much at once and you should normally not need it within your program flow. Especially if you're writing business logic.

PHP exit() vs if - else statement

Is it a good or bad practice to authenticate and then just exit() the function or to wrap the whole result of the authentication in an if statement? Example
function foo($uid)
{
$allowed = $auth->checkIfAllowed($uid);
if ($allowed == false) exit();
//continue with senstive code here
}
}
OR
function foo($uid)
{
$allowed = $auth->checkIfAllowed($uid);
if ($allowed == true)
{
// do sensitive stuff
}
}
I would like to take this opportunity to talk about exit; (as others have stated both work, the second is more explicit then the first, and give you the opportunity to send a nice error message to the user). My main beef (I have several with exit;) is that people should stop using it in libraries, i.e. code that can/will be used in other projects... You know how irritating it is to debug those? Throw exceptions, trigger fatal errors, but give me something with a description.
/rant
Your examples are equivalent.
However, it's not usually useful to the end user to just exit the script abruptly. Instead, send your user a useful error message printed in HTML rather than the plain text you would get from a die() call, for example.
function foo($uid)
{
$allowed = $auth->checkIfAllowed($uid);
if ($allowed == false)
{
$errormsg = "You are not allowed to view this page";
}
else
{
//continue with senstive code here
}
}
Later, print the error in HTML, rather than just aborting the script:
<div class='error'><?php echo $errormsg; ?></error>
Either or. I don't think it'll make a difference. It relatively the exact same thing. In programming there are many ways to program things, never on right way in most instances.
They are absolutely the same. The indentation and coding style is the only difference. In both cases the sensitive code won't execute unless the authentication is done successfully.
It's usually better to be expressive in your code though, so I'd recommend the second method.

How to gracefully die?

So I've just read Why to never use 'or die'.
I am more confused then ever. I am validating a complicated form and I go though many nested levels of if statements and what not and I am passing a variable to the form which is called $status which can only be 'new' or 'edit'. Then when the user submits the form to be validated again the form passes along the $status value as a hidden field ($_POST). I want to make sure that the user cannot accidentally change this so I want to catch the error should something other than 'new' or 'edit' pass though. (Although I would like to completely eliminate the possibility of the user affecting this variable in an ideal world.)
So I figured that I would use DIE() in an if statement
<nested ifs>
Select ($status){
Case 'edit':
break;
Case 'new':
break;
default:
//using example from article
trigger_error("An error that should not occur has occurred", E_USER_ERROR);
break;
}
</nested ifs>
I don't really understand how this is cleaner than die()? Essentially I would like to call another function which displays the user some options of what they can do at this juncture to fix the error, but I want the code to absolutely stop running as I don't want an if statement further down to continue parsing anything and generating an error when it finds something other than 'new' or 'edit'.
I'm not sure how clear I am so please feel free to ask me to elaborate on any unclear points.
(or better yet, can a hidden user field get hacked? How to prevent? :P)
trigger_error() triggers an error which is handled by an error handler.
With trigger_error() you can gracefully handle errors, for example:
set_error_handler('ErrorHandler');
function ErrorHandler($errno, $errmsg, $filename, $linenum, $vars)
{
print '<pre style="line-height: 2em;">';
printf("==> Error in `%s' line %s: %s\n\n", $filename, $linenum, $errmsg);
debug_print_backtrace();
print '</pre>';
exit($errno);
}
This is a simple example, but our company website displays a friendly error page and sends me an email that I'm an idiot and messed up somewhere :-)
The advantage over die() or exit() should be clear :-)
exit() can still be used when you need to exit. For example when you generate a template, output that, and want code execution to stop. Or when you send a header('Location: ...'); header and want to make sure the execution stops ... Just don't use it for handling unexpected situations (i.e. errors).
trigger_error() also gives you a better degree of control. You can send E_USER_NOTICE when you want execution to stop but display a notice, and E_USER_ERROR when you want execution to stop.
In addition, you can write more complex error handler functions where some IP's see a error, and the rest do not ... Kindda useful for development.
Be a but careful with overly complicated error handlers though, what happens is an error occurs inside an error handler ... ? You may have seen Inception :)
The article you linked to explains why you shouldn't use or die, as in:
$result = mysql_query($query) or die('A MySQL query occurred: ' . mysql_error());
Obviously this is a bad idea, as it could output sensitive information about your MySQL structure to a malicious user.
However, I think there is nothing wrong (and I think the writer of the article would agree with me) to use die in the way you are using it, although presenting the user with a list of options would, indeed, be the preferred way to handle this.

php OOP Exceptions or die()?

I am developing some project. And I want to control different errors. I know that in all popular frameworks and php projects there are different Exceptions. But I think that is not required work. If the error is occured we can make die() with our message.
1. What are the main pluses of Exceptions?
2. Can I control my errors with die()?
Thank you.
Well, you could use die(). But that makes all errors fatal. Meaning that you cannot try to recover from the error at all. In some cases that's fine to do.
But in most cases, you may want the ability to "clean up" after the error, or to try another method. This is where exceptions come in handy... They let you chose where and if you want to handle the error. They let you try to gracefully recover from the errors.
For example, let's say you have a method which downloads a file from a remote server: downloadFromRemoteServer($address);
If you use die(), if the download fails, the script terminates. End of story.
But if you use exceptions, you could try another server or even try a different method (HTTP vs FTP, etc):
try {
$file = downloadFromRemoteServer('http://example.com/foo');
} catch (DownloadFailedException $e) {
try {
$file = downloadFromRemoteServer('http://secondtry.example.com/foo');
} catch (DownloadFailedException $e2) {
die('Could not download file');
}
}
return $file;
But remember that Exceptions are useful only for exceptional circumstances. They are not meant to be used for any possible error. For example, if a user doesn't verify their email address correctly, that's not exceptional. But if you can't connect to the database server, or have a conflict in the DB, that would be an exception circumstance...
Alexander,
die() and Exceptions accomplish different things.
the "die" language construct just halts the execution of a script and possibly outputs the parameters if it has been called like a function.
On the other hand, exceptions are more advanced structures that are used in OOP contexts to give the developer more flexibility as to whether a script needs to be stopped and if so, in what manner, what output to be shown to the user etc.
Exceptions are a little bit more complex than this so you should perhaps document yourself with some OOP first or for that matter read about zend framework and you'll get a grasp of what Exceptions are.
For simple stuff though, you can always use exit (or die, which is the same thing).
I hope this helps,
Slavic
1 What are the main pluses of Exceptions?
The main advantages are:
failing functions don't have to pollute their return with error conditions
typed exceptions can be handled at appropriate levels in the code, you decide which portion of the code can handle which errors
you can store a lot more information about the error condition in the exception itself, making handling it, and possibly recovering from it, easier.
2 Can I control my errors with die()?
I'd hardly call it control, I'd call it giving up on actually handling an error. At no point in my projects is a die() actually user-friendly, and all those die('...some error condition...'); examples of PHP code are IMHO only suited for projects in development. In production, you'll want your users to be able to continue their tasks / programs in the easiest way possible, so a 'try again' (if error condition is not likely to be met again), 'sorry that doesn't work' / other kinds of messages, forms / pages are all more desirable then die().

Categories