Problem:
Finding best practice for error handling using PDO. The options I have found on websites, SO, books, etc.
A great number of websites say you should echo your error messages in your catch block.
A large number of users on SO say that you should never echo error messages due to security risks.
Others are recommending logging it to a log file outside the document root.
Some use error handling to log it to a SQL table.
With a multitude of options, it gets quite easy to drown into what option you should be using. Of course you could use a MVC framework and let it handle error logging for you, but how would it look like if you are not using MVC.
As I have understood it error handling should like the following in development environment:
display_errors = On
display_startup_errors = On
error_reporting = -1
log_errors = On
Or if no access is available to the php.ini file:
error_reporting(-1);
ini_set("display_errors", 1);
And in production environment:
display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL
log_errors = On
Or if no access is available to the php.ini file:
error_reporting(0);
To take an example of a database connection in production environment.
Code:
<?php
// Error handling
error_reporting(0);
// Get credentials from outside document root
require_once('../settings.php');
// Tests connection to database
try {
$dbh = new PDO(
sprintf(
'mysql:host=%s;dbname=%s;port=%s;charset=%s',
$settings['host'],
$settings['name'],
$settings['port'],
$settings['charset']
),
$settings['username'],
$settings['password']
);
// Prevents emulated prepares and activates error handling
// PDO::ERRMODE_EXCEPTION
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
// Catches errors raised by PDO
catch (PDOException $e) {
// Prints error messages to file
file_put_contents('/home/ubuntu/errors.log', 'Error: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
// Shows generic error message to user
header('Location: 404.php');
exit;
}
?>
Question:
What is the best practice for handling errors in general in PHP?
What is the best practice for handling errors in the catch-block?
That's a very good question, but there is one wrong premise at the very beginning: you are taking error reporting for PDO separated from site-wide error reporting. Which makes very little sense: PDO errors in every way are the same as other errors - filesystem errors, HTTP errors, and so on. Thus, there is no reason in establishing PDO-only error reporting. All you need is to properly set site-wide error reporting.
There is also one wrong assumption regarding php.ini inaccessibility: you can always set any configuration directive using ini_set() function. Thus, here is not a single reason in setting error_reporting to disastrous level of 0.
To answer the rest of your questions all you need is a little common sense.
A great number of websites say you should echo your error messages in your catch block.
A large number of users on SO say that you should never echo error messages due to security risks.
What you think yourself? Does it any good showing system error messages to user? Does it any good showing system internals to a malicious user?
Others are recommending logging it to a log file outside the document root.
Do you have any objections for this?
Some use error handling to log it to a SQL table.
Don't you think it's quite contradicting idea - to log database errors into database?
What is the best practice for handling errors in general in PHP?
You have shown it already: display in dev and log in prod. All is controlled site-wide through few simple configuration options.
What is the best practice for handling errors in the catch-block?
NOT to use try-catch block for error reporting at all. You aren't going to write a catch block with a friendly error message for the every query in your app, as it's suggested in the other answer, are you?
Thus your code have to be
<?php
// Error handling
error_reporting(-1);
ini_set('display_errors',0);
ini_set('log_errors',1);
// Get credentials from outside document root
require_once('../settings.php');
// Tests connection to database
$dbh = new PDO(
sprintf(
'mysql:host=%s;dbname=%s;port=%s;charset=%s',
$settings['host'],
$settings['name'],
$settings['port'],
$settings['charset']
),
$settings['username'],
$settings['password']
);
// Prevents emulated prepares and activates error handling
// PDO::ERRMODE_EXCEPTION
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Now to the question you voiced in the comment.
A custom error screen is a very different matter and your code is especially bad with it. Neither it should be a 404 error nor an HTTP redirect have to be used (thats very bad for SEO).
To create a custom error page you have to use either your web-server features (preferred) or an error handler in PHP script.
When encountering a fatal error (and uncaught exception is one), PHP responds not with 200 OK HTTP status but with 5xx status. And every web-server can catch this status and show an according error page. E.g. for Apache it would be
ErrorDocument 503 server_error.html
where you can write whatever excuses you want.
Or you can set up a custom error handler in PHP which would handle all PHP errors as well, an example can be seen in the article I wrote on the matter: The (im)proper use of try..catch.
Related
in this case I accidentally made a wrong database username or password, my goal here is how to generate an error in the form of JSON data and open in the form of a PHP warning or error like my picture
// Here's my PHP Code
if (!empty($_POST)){
$test_conn = new mysqli('localhost' , $_POST['db_user'] , $_POST['db_pass']);
$conn = new mysqli('localhost' , $_POST['db_user'] , $_POST['db_pass'] , $_POST['db_name']);
if ($test_conn->connect_error){
$response = array('status' => 0 , 'message' => "Failed Connect to Databases");
print_r(json_encode($response));
}else{
// The Code When Username and Password is Correct
}
}
here I know that the username or password is wrong, but I am confused how to only display the json data in the image at the bottom and not display the php warning
If you are sure that this is what you want, just disable errors by adding the following at the top of your script:
error_reporting(0);
if you want to hide errors for a given code, use the following:
// Disable errors and get current error reporting level
$err = error_reporting(0);
/* here goes you buggy code */
// Set the default error reporting level
error_reporting($err);
You have to suppress the php error reporting in order to use your own check of connect_error. The php documentation on mysqli::$connect_error suggests to do this with the # error control operator like this:
$test_conn = #new mysqli( ... )
This will only suppress errors caused by a faulty instantiation of the mysqli object. It should be clear that you then have to handle these errors yourself (as you already do). All other errors still could cause your php script to stop and not to return any JSON string to the AJAX function that called the script.
As #Victor correctly pointed out in his answer you could disable all errors for the script (or parts of it) by setting error_reporting(0) at the beginning at the script. In that case you wouldn't have to check other possible errors, e.g. if the db credentials in the $_POST array are not set or empty.
As #Ben mentioned in his comments you could also make mysqli throw exceptions to avoid fatal errors by setting mysqli_report(MYSQLI_REPORT_STRICT). This would also be a feasible solution for your problem.
As a general consideration you should make these settings in your php.ini:
display_errors = Off
error_log = syslog
This prevents error message from being exposed to the www (security) while making them available for developers in /var/log/syslog (maintainability).
Problem:
Finding best practice for error handling using PDO. The options I have found on websites, SO, books, etc.
A great number of websites say you should echo your error messages in your catch block.
A large number of users on SO say that you should never echo error messages due to security risks.
Others are recommending logging it to a log file outside the document root.
Some use error handling to log it to a SQL table.
With a multitude of options, it gets quite easy to drown into what option you should be using. Of course you could use a MVC framework and let it handle error logging for you, but how would it look like if you are not using MVC.
As I have understood it error handling should like the following in development environment:
display_errors = On
display_startup_errors = On
error_reporting = -1
log_errors = On
Or if no access is available to the php.ini file:
error_reporting(-1);
ini_set("display_errors", 1);
And in production environment:
display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL
log_errors = On
Or if no access is available to the php.ini file:
error_reporting(0);
To take an example of a database connection in production environment.
Code:
<?php
// Error handling
error_reporting(0);
// Get credentials from outside document root
require_once('../settings.php');
// Tests connection to database
try {
$dbh = new PDO(
sprintf(
'mysql:host=%s;dbname=%s;port=%s;charset=%s',
$settings['host'],
$settings['name'],
$settings['port'],
$settings['charset']
),
$settings['username'],
$settings['password']
);
// Prevents emulated prepares and activates error handling
// PDO::ERRMODE_EXCEPTION
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
// Catches errors raised by PDO
catch (PDOException $e) {
// Prints error messages to file
file_put_contents('/home/ubuntu/errors.log', 'Error: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
// Shows generic error message to user
header('Location: 404.php');
exit;
}
?>
Question:
What is the best practice for handling errors in general in PHP?
What is the best practice for handling errors in the catch-block?
That's a very good question, but there is one wrong premise at the very beginning: you are taking error reporting for PDO separated from site-wide error reporting. Which makes very little sense: PDO errors in every way are the same as other errors - filesystem errors, HTTP errors, and so on. Thus, there is no reason in establishing PDO-only error reporting. All you need is to properly set site-wide error reporting.
There is also one wrong assumption regarding php.ini inaccessibility: you can always set any configuration directive using ini_set() function. Thus, here is not a single reason in setting error_reporting to disastrous level of 0.
To answer the rest of your questions all you need is a little common sense.
A great number of websites say you should echo your error messages in your catch block.
A large number of users on SO say that you should never echo error messages due to security risks.
What you think yourself? Does it any good showing system error messages to user? Does it any good showing system internals to a malicious user?
Others are recommending logging it to a log file outside the document root.
Do you have any objections for this?
Some use error handling to log it to a SQL table.
Don't you think it's quite contradicting idea - to log database errors into database?
What is the best practice for handling errors in general in PHP?
You have shown it already: display in dev and log in prod. All is controlled site-wide through few simple configuration options.
What is the best practice for handling errors in the catch-block?
NOT to use try-catch block for error reporting at all. You aren't going to write a catch block with a friendly error message for the every query in your app, as it's suggested in the other answer, are you?
Thus your code have to be
<?php
// Error handling
error_reporting(-1);
ini_set('display_errors',0);
ini_set('log_errors',1);
// Get credentials from outside document root
require_once('../settings.php');
// Tests connection to database
$dbh = new PDO(
sprintf(
'mysql:host=%s;dbname=%s;port=%s;charset=%s',
$settings['host'],
$settings['name'],
$settings['port'],
$settings['charset']
),
$settings['username'],
$settings['password']
);
// Prevents emulated prepares and activates error handling
// PDO::ERRMODE_EXCEPTION
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Now to the question you voiced in the comment.
A custom error screen is a very different matter and your code is especially bad with it. Neither it should be a 404 error nor an HTTP redirect have to be used (thats very bad for SEO).
To create a custom error page you have to use either your web-server features (preferred) or an error handler in PHP script.
When encountering a fatal error (and uncaught exception is one), PHP responds not with 200 OK HTTP status but with 5xx status. And every web-server can catch this status and show an according error page. E.g. for Apache it would be
ErrorDocument 503 server_error.html
where you can write whatever excuses you want.
Or you can set up a custom error handler in PHP which would handle all PHP errors as well, an example can be seen in the article I wrote on the matter: The (im)proper use of try..catch.
Problem:
Finding best practice for error handling using PDO. The options I have found on websites, SO, books, etc.
A great number of websites say you should echo your error messages in your catch block.
A large number of users on SO say that you should never echo error messages due to security risks.
Others are recommending logging it to a log file outside the document root.
Some use error handling to log it to a SQL table.
With a multitude of options, it gets quite easy to drown into what option you should be using. Of course you could use a MVC framework and let it handle error logging for you, but how would it look like if you are not using MVC.
As I have understood it error handling should like the following in development environment:
display_errors = On
display_startup_errors = On
error_reporting = -1
log_errors = On
Or if no access is available to the php.ini file:
error_reporting(-1);
ini_set("display_errors", 1);
And in production environment:
display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL
log_errors = On
Or if no access is available to the php.ini file:
error_reporting(0);
To take an example of a database connection in production environment.
Code:
<?php
// Error handling
error_reporting(0);
// Get credentials from outside document root
require_once('../settings.php');
// Tests connection to database
try {
$dbh = new PDO(
sprintf(
'mysql:host=%s;dbname=%s;port=%s;charset=%s',
$settings['host'],
$settings['name'],
$settings['port'],
$settings['charset']
),
$settings['username'],
$settings['password']
);
// Prevents emulated prepares and activates error handling
// PDO::ERRMODE_EXCEPTION
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
// Catches errors raised by PDO
catch (PDOException $e) {
// Prints error messages to file
file_put_contents('/home/ubuntu/errors.log', 'Error: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
// Shows generic error message to user
header('Location: 404.php');
exit;
}
?>
Question:
What is the best practice for handling errors in general in PHP?
What is the best practice for handling errors in the catch-block?
That's a very good question, but there is one wrong premise at the very beginning: you are taking error reporting for PDO separated from site-wide error reporting. Which makes very little sense: PDO errors in every way are the same as other errors - filesystem errors, HTTP errors, and so on. Thus, there is no reason in establishing PDO-only error reporting. All you need is to properly set site-wide error reporting.
There is also one wrong assumption regarding php.ini inaccessibility: you can always set any configuration directive using ini_set() function. Thus, here is not a single reason in setting error_reporting to disastrous level of 0.
To answer the rest of your questions all you need is a little common sense.
A great number of websites say you should echo your error messages in your catch block.
A large number of users on SO say that you should never echo error messages due to security risks.
What you think yourself? Does it any good showing system error messages to user? Does it any good showing system internals to a malicious user?
Others are recommending logging it to a log file outside the document root.
Do you have any objections for this?
Some use error handling to log it to a SQL table.
Don't you think it's quite contradicting idea - to log database errors into database?
What is the best practice for handling errors in general in PHP?
You have shown it already: display in dev and log in prod. All is controlled site-wide through few simple configuration options.
What is the best practice for handling errors in the catch-block?
NOT to use try-catch block for error reporting at all. You aren't going to write a catch block with a friendly error message for the every query in your app, as it's suggested in the other answer, are you?
Thus your code have to be
<?php
// Error handling
error_reporting(-1);
ini_set('display_errors',0);
ini_set('log_errors',1);
// Get credentials from outside document root
require_once('../settings.php');
// Tests connection to database
$dbh = new PDO(
sprintf(
'mysql:host=%s;dbname=%s;port=%s;charset=%s',
$settings['host'],
$settings['name'],
$settings['port'],
$settings['charset']
),
$settings['username'],
$settings['password']
);
// Prevents emulated prepares and activates error handling
// PDO::ERRMODE_EXCEPTION
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Now to the question you voiced in the comment.
A custom error screen is a very different matter and your code is especially bad with it. Neither it should be a 404 error nor an HTTP redirect have to be used (thats very bad for SEO).
To create a custom error page you have to use either your web-server features (preferred) or an error handler in PHP script.
When encountering a fatal error (and uncaught exception is one), PHP responds not with 200 OK HTTP status but with 5xx status. And every web-server can catch this status and show an according error page. E.g. for Apache it would be
ErrorDocument 503 server_error.html
where you can write whatever excuses you want.
Or you can set up a custom error handler in PHP which would handle all PHP errors as well, an example can be seen in the article I wrote on the matter: The (im)proper use of try..catch.
I'm attempting to upgrade my website to the newest, or at least a newer, version of PHP. Through out my site I receive Internal Server Error messages. Some are consistent and occur every time you access a page. Others are intermittent even though the same actions were taken. I am trying to solve at least one of the errors in hopes of gaining a foothold in solving all the rest.
Code that consistently produces the Internal Server Error:
try {
global $dbCon;
$stmt = $dbCon->prepare("SELECT pdf_template, ai_template, id_template, img_template FROM products WHERE sku=:s ");
$stmt->execute(array(':s' => $sku)); //Failure occurs on this line
$result = $stmt->fetch(PDO::FETCH_ASSOC); //This is never reached
//$stmt->bindValue(':sku',$sku,PDO::PARAM_STR);//Attempted alternate form of binding
//$stmt->execute(); //Alternate binding still failed here
} catch (PDOException $e) {
$logger->warn("Database call failed, was unable to gather product templates", "pricing modal", "sku: $sku");
}
As you can see by my comment, the line $stmt->execute(array(':s' => $sku)); is consistently the culprit. If it is commented out, page still loads. More specifically, if I put $stmt->execute(); the statement executes and the page still loads (minus DB required content of course). So it seems that during PHP's attempt to bind the variables to the prepared statement there is a failure. This also applies to bindValue(). Anytime a value is bound previously execute fails.
I have tried many ways to get some type of output in the logs. For example at the top of the page
error_reporting(E_ALL);
ini_set( 'display_errors','1');
ini_set("log_errors", 1);
ini_set("error_log", "/tmp/php-error.log");
error_log( "Hello, errors!" );
In the .htaccess:
php_flag log_errors on
php_value error_log /tmp/php-error.log
I have tried various permutations of the previous code trying to produce an error in the log file. Yes, some of it is redundant, I was getting desperate for an answer. Yes, 'Hello, errors!" does appear in the log file.
The cause of all of this: Website works wonderfully on PHP 5.3. It is the version it was developed in. (I know, should of developed it on the newer version. I have logistic reasons that were previously out of my control) When I bump the version up to 5.4 or 5.5 I get the internal server error. Can someone provide some insight and deeper knowledge about this topic. Thank you very much.
EDIT: $dbCon declaration:
try{
$dbCon = new PDO('mysql:host=mysql.example.com;dbname=db_sandbox',$db_user,$db_password, array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
));
} catch( PDOException $e ) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
#rjdown I did that before, and I just did it again with an actual fix showing up. It was to remove ob_start() because headers were not being sent in the correct order. That fixed that page.
Now I'm still getting Internal server error somewhere else. Different error now. Involving glibc error that is specific to my server and beyond the scope of this particular question.
I'm moving a php application to a new web server.
In the origin server, the following code is working, but it is not in the new server.
$request=$connexion->prepare("SELECT * FROM access_control ");
$request->execute();
$request2=$connexion->prepare("SELECT * FROM tplmail ");
$request2->execute();`
The first request always works. I tried to reverse the two requests, but the script always stop at the second execute. In the others scripts, there is the same problem, I can't do two executes in the same page.
Your problem #1 is lack of error reporting. Without seeing an error message you will be unable to do anything
To be able to see database errors, one have to set PDO errmode to exceptions. Exceptions are better than regular errors in many ways: they always contains a stack trace, they can be caught using try..catch or handled using dedicated error handler. And even unhandled, they act as regular PHP errors providing all the important information, following site-wide error reporting settings.
Note that setting this mode as a connection option will let PDO throw exceptions on connection errors too, which is very important.
So, here is an example for creating a PDO connection right way:
$dsn = "mysql:host=$host;dbname=$db;charset=utf8";
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
// other options
);
$pdo = new PDO($dsn, $user, $pass, $opt);
Connecting this way, you will be always notified of all database errors, occurred during query execution. Note that you have to be able to see PHP errors in general. On a live site you have to peek into error logs, so, settings have to be
error_reporting(E_ALL);
ini_set('display_errors',0);
ini_set('log_errors',1);
while on a local development server it's ok to make errors on screen:
error_reporting(E_ALL);
ini_set('display_errors',1);
and of course you should never ever use error suppression operator (#) in front of your PDO statements.
Also, due to many bad examples telling you to wrap every PDO statement into try..catch block, I have to make a distinct note:
DO NOT use try..catch operator just to echo an error message. Uncaught exception is already excellent for this purpose, as it will act just the same way as other PHP errors - so, you can define the behavior using site-wide settings - so, you will have your error message without this useless code. While unconditionally echoed error message may reveal some sensitive information to a potential attacker, yet confuse a honest visitor.
A custom exception handler could be added later, but not required. Especially for new users, it is recommended to use unhandled exceptions, as they are extremely informative, helpful and secure.
Use try..catch only if you are going to handle the error itself - say, to rollback a transaction.
Your problem #2 is a buffering state which prevent second query from execution.
Adding
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => TRUE,
to the init array should solve the problem
Or you can just fetch all the data from the first query before firing the second