Fluoresce Posted October 22, 2013 Share Posted October 22, 2013 Whenever there's a PHP or MySQL error on my production site, I want the error to be logged in a file. I have found a file called error_log in my site's root folder containing previous PHP and MySQL errors, so error logging is already working. But I want to understand how and why it's working. I checked my php.ini file: error_reporting = E_ALL & ~E_NOTICE display_errors = On display_startup_errors = Off ; Log errors into a log file (server-specific log, stderr, or error_log (below)) ; As stated above, you're strongly advised to use error logging in place of ; error displaying on production web sites. log_errors = On; ; Set maximum length of log_errors. In error_log information about the source is ; added. The default is 1024 and 0 allows to not apply any maximum length at all. log_errors = On; ; Log errors to specified file. error_log = error_log; ; Log errors to syslog (Event Log on NT, not valid in Windows 95). error_log = error_log; Question 1 How can there be two each of log_errors = On and error_log = error_log? Question 2 Will errors be logged in the error_log file no matter what, or do I have to use die()/trigger_error() in my code? In other words, if my database is down, will all of these lines log errors? mysql_query("SELECT * FROM `table` WHERE date IS NULL"); mysql_query("SELECT * FROM `table` WHERE date IS NULL") or die(mysql_error()); mysql_query("SELECT * FROM `table` WHERE date IS NULL") or trigger_error(mysql_error()); Question 3 If I put E_USER_ERROR in trigger_error(), will only that type of errors be logged? Quote Link to comment Share on other sites More sharing options...
gristoi Posted October 22, 2013 Share Posted October 22, 2013 this should help you on the subject: http://php.net/manual/en/book.errorfunc.php Quote Link to comment Share on other sites More sharing options...
Ch0cu3r Posted October 22, 2013 Share Posted October 22, 2013 Question1 For some reason your host has this directive defined twice. All errors is logged to the file named error_log Question 2 If error reporting is off, then yes all errors will be logged. What types of errors are logged depends on the level you have set error_reporting to. Setting error reporting to E_ALL & ~E_NOTICE will log all errors except notices Question 3 No Quote Link to comment Share on other sites More sharing options...
Fluoresce Posted October 22, 2013 Author Share Posted October 22, 2013 this should help you on the subject: http://php.net/manual/en/book.errorfunc.php Thanks, but I've already checked that stuff out. It's quite confusing for me. Question 2 If error reporting is off, then yes all errors will be logged. What types of errors are logged depends on the level you have set error_reporting to. Setting error reporting to E_ALL & ~E_NOTICE will log all errors except notices Do you mean if error_reporting is turned on? Can you explain how to use the predefined constants (e.g., E_USER_ERROR), please? Quote Link to comment Share on other sites More sharing options...
Ch0cu3r Posted October 22, 2013 Share Posted October 22, 2013 Do you mean if error_reporting is turned on? Sorry I meant to say display_errors is off. If error_reporting is off then no errors will be logged. The E_USER_* error constants are used for reporting your own custom errors when using trigger_error. Again anything to do with errors and how to handle them is explained in the manual which gristoi linked to. Quote Link to comment Share on other sites More sharing options...
Fluoresce Posted October 22, 2013 Author Share Posted October 22, 2013 The E_USER_* error constants are used for reporting your own custom errors when using trigger_error. Again anything to do with errors and how to handle them is explained in the manual which gristoi linked to. What I don't understand is which constant I am supposed to use, and when. It doesn't tell you in the manual. I don't want my scripts to die and present half a page to users, so I know that I shouldn't use E_USER_ERROR. What, then, should I use if mysql_connect(), mysql_select_db() or mysql_query() fail? Should I use E_USER_WARNING, or should I leave the default E_USER_NOTICE? Does it really matter? For example, should I do this for MySQL queries? $query = mysql_query("Some query"); if(!$query) { echo "Message to user."; trigger_error("Error!", E_USER_WARNING); // Message to be logged } Quote Link to comment Share on other sites More sharing options...
Adam Posted October 22, 2013 Share Posted October 22, 2013 (edited) Sorry I meant to say display_errors is off. If error_reporting is off then no errors will be logged. Even when "display_errors" is on, errors will still be logged. What I don't understand is which constant I am supposed to use, and when. It doesn't tell you in the manual. It depends on the environment you're in Fluoresce. In a development or testing environment, you will want to log as much as possible to help with debugging. It's up to you if you have "display_errors" enabled or not, but personally I prefer to have them all logged into a file and tailf it so I can monitor them. As for the constants, you don't generally want anything in the production logs except stuff you really need to know about. During dev/testing you should clear the less important notices out before even releasing, so you should be okay with: // Report simple running errors error_reporting(E_ERROR | E_WARNING | E_PARSE);As for development, you want absolutely everything reported, so you want: // Report all PHP errors error_reporting(-1);You shouldn't really ever be getting E_USER_* errors in production. Edited October 22, 2013 by Adam Quote Link to comment Share on other sites More sharing options...
kicken Posted October 22, 2013 Share Posted October 22, 2013 (edited) What I don't understand is which constant I am supposed to use, and when. It doesn't tell you in the manual. You use whichever one you feel is appropriate for the situation. For example if the error is minor and doesn't cause any real problems (or not really an error, but inefficient or something) then E_USER_NOTICE would be appropriate. E_USER_WARNING would be for more serious errors that will prevent something from working properly, but is not bad enough to necessitate killing the script. For example if the DB connect fails, then you can't run any queries. The script itself could continue and handle the error by skipping the DB queries or generating an error page. E_USER_ERROR would be for something that is a legit show stopper and the script cannot possibly continue. Something on this level would probably be rare in the user context. I can't think of any particular example where one might use E_USER_ERROR. Note that trigger_error is not a replacement for proper checking of return values. It's just a convenient way to log a message when an error occurs. If you're trying to call mysqli_connect and it fails for instance, you'd still check the return value such as: $conn = mysqli_connect(...) or trigger_error('Failed to connect to MySQL', E_USER_WARNING); if (!$conn){ //abort or return or whatever to handle it } Edited October 22, 2013 by kicken Quote Link to comment Share on other sites More sharing options...
Fluoresce Posted October 23, 2013 Author Share Posted October 23, 2013 Here are the php.ini settings for my production site: error_reporting = E_ALL display_errors = Off log_errors = On error_log = error_log I've just done a bit of newbie experimentation. An error is logged if mysql_connect() fails even without trigger_error(). In other words, for logging, the trigger_error() part of the following code is not necessary. $conn = mysqli_connect(...) or trigger_error('Failed to connect to MySQL', E_USER_WARNING); If you use the code above, two warnings will be logged, one by the system and one by your use of trigger_error(). Am I mistaken? I guess this means that trigger_error() is to be used when errors aren't automatically thrown, and whatever error constant you use depends on what you think is appropriate. Is that correct? Quote Link to comment Share on other sites More sharing options...
Adam Posted October 23, 2013 Share Posted October 23, 2013 I guess this means that trigger_error() is to be used when errors aren't automatically thrown, and whatever error constant you use depends on what you think is appropriate. Is that correct? Correct. I wouldn't ever trigger another error in that situation because you know one has already been triggered. I don't really agree with the PHP docs for having that example. As I edited my last post to say, you shouldn't ever really be encountering user triggered errors in your production environment, because they imply bad configuration, bad connection or something dev wise has not gone right. PHP will automatically trigger warnings appropriately and bomb out in most situations though. Nothing should make it to a production environment if it's triggering user errors. Quote Link to comment Share on other sites More sharing options...
Fluoresce Posted October 23, 2013 Author Share Posted October 23, 2013 (edited) Okay, I'm confused now. I don't know how I should be handling possible future mysql_connect() errors. Here's what I've just discovered ... If I use the following code and the connection fails, the user is presented with a MySQL error message (even though display_errors is turned off), the script dies (so the user only gets half a page), and 4 warnings are logged (1 for the failure to connect, 2 for the failure to select the database, and 1 for the failure of the MySQL query). $con = mysql_connect("localhost", "", ""); // Rest of code On the other hand, if I use the following code and the connection fails, the user is presented with a custom message, the script doesn't die (so the user gets a full page), and 1 warning is logged (for the failure to connect). $conn = mysql_connect("localhost", "", ""); if(!$conn) { echo "<p>Custom error message for user.</p>"; } else { // Rest of code } I haven't had to use trigger_error() at all. Is that the best way to deal with possible future connection failures? I ask because even the PHPFreaks website says to use this: mysql_connect("localhost", "", "") or trigger_error("Connection failed! " . mysql_error()); // Rest of code If the second bit of code is the best way to deal with future connection problems, my question is, should I use the same if/else logic for mysql_select_db() and mysql_query() as well? Wouldn't my scripts then be packed with if/else conditionals? And is it all even necessary? What's the chance that the connection, database selection or query will fail? Edited October 23, 2013 by Fluoresce Quote Link to comment Share on other sites More sharing options...
kicken Posted October 23, 2013 Share Posted October 23, 2013 trigger_error is just use to help log errors. It has nothing to do with handling them. Also, as mentioned for things where PHP already provides error messages like on failure of mysql_connect, it is entirely unnecessary. Where you might use it is in your own classes or functions to provide error reporting when necessary. For example, I've made a few classes before that use cURL to download a file then parse the contents. I used trigger_error to report things like the cURL download failing or the reason why parsing the file contents failed. Whether you use trigger_error at all or not though, you still need to make sure your code can handle such errors by checking the functions return value and acting accordingly. As for the chances of something like mysql_connect or mysql_query failing, it's > 0% so you need to handle it. In an ideal world these operations would never fail, but the world is far from perfect. Network problems, file corruption, hardware failures, etc all can cause these to fail at any time. Quote Link to comment Share on other sites More sharing options...
Fluoresce Posted October 23, 2013 Author Share Posted October 23, 2013 Good stuff! Okay, here's what I want to do. If a MySQL connection or query fails in the future, I want a user-friendly message to be presented to the user, a log to be made of the error, and an e-mail to be sent to me. Here are my php.ini settings: error_reporting = E_ALL display_errors = Off log_errors = On error_log = [nameoffile] Here's what I've got so far: // Prepare headers for e-mail $headers = "From: help@mysite.com\r\n"; $headers .= "MIME-Version: 1.0\r\n"; $headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n"; // Connect to MySQL $con = mysql_connect("", "", ""); if(!$con) { echo "<p>User-friendly message for user.</p>"; error_log("MySQL connection failed! Date: " . date("l jS \of F, Y, h:i:s A") . ". File: " . $_SERVER['REQUEST_URI'], 1, "personaladdress@whatever.com", $headers); } else { // Rest of code } The code works. The user-friendly message is presented to the user, a log is made of the error, and an e-mail is sent to me specifying the data and time of the error and the file in which the error occurred. Does it look okay to you guys? How would you do it? Quote Link to comment Share on other sites More sharing options...
Solution Ch0cu3r Posted October 23, 2013 Solution Share Posted October 23, 2013 (edited) Make a function, that calls error_log so you don't have to define the email headers each time you want to log an error. // define custom error logging function function my_error_log($error_txt) { // Prepare headers for e-mail $headers = "From: help@mysite.com\r\n"; $headers .= "MIME-Version: 1.0\r\n"; $headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n"; // append error information to error message $error_text .= " Date: " . date("l jS \of F, Y, h:i:s A") . ". File: " . $_SERVER['REQUEST_URI']; // call error_log function error_log($error_text, 1, "personaladdress@whatever.com", $headers); } // Connect to MySQL $con = mysql_connect("", "", ""); if(!$con) { echo "<p>User-friendly message for user.</p>"; // call custom error log function my_error_log("MySQL connection failed!"); // jsut pass in the error message } else { // Rest of code } Edited October 23, 2013 by Ch0cu3r Quote Link to comment Share on other sites More sharing options...
Fluoresce Posted October 23, 2013 Author Share Posted October 23, 2013 (edited) Make a function, that calls error_log so you don't have to define the email headers each time you want to log an error. // define custom error logging function function my_error_log($error_txt) { // Prepare headers for e-mail $headers = "From: help@mysite.com\r\n"; $headers .= "MIME-Version: 1.0\r\n"; $headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n"; // append error information to error message $error_text .= " Date: " . date("l jS \of F, Y, h:i:s A") . ". File: " . $_SERVER['REQUEST_URI']; // call error_log function error_log($error_text, 1, "personaladdress@whatever.com", $headers); } // Connect to MySQL $con = mysql_connect("", "", ""); if(!$con) { echo "<p>User-friendly message for user.</p>"; // call custom error log function my_error_log("MySQL connection failed!"); // jsut pass in the error message } else { // Rest of code } Thanks, but it's not working: PHP Notice: Undefined variable: error_text in ... The email is sent, but the string (error message) that I enter into my_error_log() doesn't appear in the email. I tried putting $error_text = ''; both inside and outside the function. Although the notice goes away when I try it inside the function, the error message that I enter into my_error_log() still doesn't appear in the email. Edited October 23, 2013 by Fluoresce Quote Link to comment Share on other sites More sharing options...
Ch0cu3r Posted October 23, 2013 Share Posted October 23, 2013 (edited) Sorry, I left the letter e out of error_text, the line below function my_error_log($error_txt) should be function my_error_log($error_text) Edited October 23, 2013 by Ch0cu3r Quote Link to comment Share on other sites More sharing options...
Fluoresce Posted October 23, 2013 Author Share Posted October 23, 2013 Sorry, I left the letter e out of error_text, the line below function my_error_log($error_txt) should be function my_error_log($error_text) Nice eyes, man! Working perfectly now. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.