Many PHP developers are used to seeing server-side errors show up in their browsers automatically, because PHP's
display_errors directive is set in their PHP configuration file by default to
on. This is a bad idea, for a number of reasons:
As we discussed in the last section, it's important to distinguish between the code that is running on the server, and the response that it sends back to the client.
In general, code can contain sensitive information that we do not want to share with the end user - for example, passwords and API keys. If something goes wrong with the database connection code, it will generate a stack trace that contains the database credentials. By dumping this trace into the response, your application is risking making this information public:
Therefore we want to keep a tight rein on what makes it into the response, and this means turning off
You might say, "well wait a minute, that's only a problem when I'm in production! I can still use
display_errors in development, right?"
The answer is yes, you can, but there are some other reasons that I strongly recommend against it.
POST requests, such as navigating to a page or submitting a form using your browser's default submission handling, the default behavior of most browsers is to directly display the response it receives in the main viewport. This is done automatically, so we don't even really think of it as a request-response transaction.
However with the rise of "Web 2.0" and more complex web applications, we've seen the widespread adoption of AJAX for submitting requests and working with response data, all without refreshing the page. Often times, the user doesn't even know that a request has been issued!
This is hardly a convenient and predictable way to get at debugging and error messages!
Dumping server-side error and debugging messages into the HTTP response further blurs the distinction between server-side and client-side concerns for new developers. It's no wonder that some novice PHP developers end up thinking that their PHP script is being run in their browser!
At the end of the day, the HTTP response should be a carefully crafted piece of content designed to be consumed in a specific way by the client - not a dump of every possible type of output that the server might generate.
I should point out that there is a difference between developer-facing messages, and user-facing messages. User-facing messages are messages which are intended for the end user - things like "Please choose at least one owl" or "Sorry, your owlId is incorrect!" These are generally explicitly generated by your application, and can and should be sent in an HTTP response.
Developer-facing messages, on the other hand, should only be seen by developers and system administrators. These are things like the MySQL credentials error and stack trace we saw earlier. These are the types of messages we want to avoid injecting into our HTTP response.
So then, how do we deliver debugging and error messages to our tech team?
Fortunately, we have means for shunting messages to a log file.
To begin with, PHP natively supports error logging by setting the
log_errors directive to
on, and specifying a path to an error log file (what we will call the php error log) with the
error_log directive. Enabling
log_errors and disabling
display_errors will cause PHP to dump error messages to the log instead of the response.
To manually invoke the error logger, we can use the
error_log function. This will let us write to the php error log:
// Print a simple string to the log error_log("Fetching owls from database..."); // Print an array or object to the log error_log(print_r($owls, true));
We can use this as a simple alternative to using
echo to print debugging information directly to the response.
It'd be nice if we could separate our reports of actual, unexpected errors from routine debugging statements, by sending them to separate log files. UserFrosting supports this as well, and creates the following log files in the
debug.log is meant for dumping routine debugging statements. To log something to the debugging log, simply use the
use UserFrosting\Sprinkle\Core\Facades\Debug; ... Debug::debug("Fetching owls from database..."); Debug::debug("Owls found:", $owls);
Debug is a facade for a Monolog logger instance, whose
debug method takes a string as the first parameter and an optional array as a second parameter, and writes them to a log file. Monolog also supports more advanced logging capabilities - check their documentation for more details.
errors.log is where most run-time error messages generated by uncaught exceptions are sent. Slim, the microframework upon which UserFrosting is built, converts all PHP errors into exceptions. Thus, the majority of application error messages will be found in this log. You can read more about how the error-handling system as a whole works in Chapter 10.
mail.log is a special logger for mail-related activity. The underlying phpMailer instance that we use reports its SMTP activity to this log. The level of detail can be specified with the
mail.smtp_debug configuration value, using the values specified in the PHPMailer documentation:
2Data and commands
3As 2 plus connection status
4Low-level data output