I am working with a internal framework where every exception is catched by an error handler and returned in a proper JSON error response, suitable for a RESTFul API.
Then I have a suite of tests, which are API tests, that are mainly testing that the API returns the proper JSON responses with the expected error codes.
For every test, the global variables are modified (and then restored) to emulate a different HTTP request. I do it that way to avoid the overload of doing cURL tests (through Guzzle or similar), and cause under the CLI environment, the code does not know the server's url.
<?php
// ... example, part of a base ApiTestCase class:
// Override globals (should be backed up by PHPUnit)
$_SERVER['REQUEST_METHOD'] = $request->method;
$_SERVER['QUERY_STRING'] = http_build_query($request->parameters);
$_SERVER['PATH_INFO'] = $request->path;
$_SERVER['REQUEST_URI'] = $request->path . ($_SERVER['QUERY_STRING'] ? '?' : '') . $_SERVER['QUERY_STRING'];
$_SERVER['REQUEST_TIME'] = time();
$_SERVER['REQUEST_TIME_FLOAT'] = microtime(true);
$_SERVER['HTTP_COOKIE'] = '';
// Set headers, cookies and parameters
foreach ($request->headers as $k => $v) {
$_SERVER['HTTP_' . strtoupper(str_replace('-', '_', trim($k)))] = $v;
}
if ($_SERVER['HTTP_COOKIE']) {
$GLOBALS['_COOKIE'] = http_parse_cookie($_SERVER['HTTP_COOKIE']);
} else {
$GLOBALS['_COOKIE'] = [];
}
$GLOBALS['_REQUEST'] = $request->parameters;
$responseBody = $app->start();
$response->httpCode = http_response_code();
$response->body = $responseBody ? #json_decode($responseBody) : null;
$response->headers = headers_list();
(I know that changing globals this way is not nice, and the framework should not rely on globals directly, but I have still to deal with legacy code.)
Then here comes the problem: when I try to test JSON error responses: PHPUnit intercepts the thrown exception (before the handler I mentioned in the beginning), so the framework has no chance to convert it to JSON and return the proper response.
I tried to find something in the PHPUnit manual to disable the PHPUnit error handler with no luck.
What could I do in this case? Thanks
Just to be clear, it sounds like we're not actually talking about catching exceptions here; we're talking about using PHP's set_error_handler() to intercept a fatal error before it terminates the program. This will deal with both errors and uncaught exceptions.
One thing you will not be able to do is let those errors and exceptions fall through to your error handler function -- as you've already found out, phpUnit does its own error handling that you can't override (because it's kinda fundamental to how phpUnit works).
What you're going to have to do is tell phpUnit what kind of exception or error you're expecting; your test will then pass or fail according to whether the error occurs. You won't be running the error handler, but in truth, you shouldn't need to; you can test function that separately if you need to. For error conditions, you don't need to see that the error handler produces the right output every time, just that an error occurs that will trigger the handler.
For regular PHP exceptions, you can use phpUnit's #expectedException annotation above your test function, like so:
/**
* #expectedException YourExpectedExceptionClass
*/
function testThisWillThrowAnException() {
....
}
If the PHP code is expected to produce a PHP error (ie an error, not an exception), then you would use the same idea, but phpUnit provides a helper classname for the error: PHPUnit_Framework_Error. So your code would look like this:
/**
* #expectedException PHPUnit_Framework_Error
*/
function testThisWillProduceAPHPError() {
....
}
In either case, your test will pass if the expected error/exception occurs.
You can also test for specific exception messages and codes, in case the exception class itself isn't sufficient information for you to know whether the test has done what you want it to do. See the phpUnit manual page for annotations for more info.
The example above is also correct, mine only provide Exceptions as assertions and gives you knowladge of Exceptions Works.
/**
* #dataProvider fixturesProvider // its just example
*/
public function testDataIsWrong($fixtures)
{
try
{
//Some Code
$this->fail('Exception');
}
catch(Exception $ex)
{
$this->assertEquals($ex,'Exception');
}
}
This also provide in your code possibility ,that You can Test false or inncorect data and assert it is incorrect.
The only solution I implemented that solves my problem is to not delegate the exception handler the responsibility to build and send the API error responses, but catch exceptions in the top level of your application.
In the catch I have an exception-to-error-response converter that takes care of that (or re-throws the exception when convenient), so the errors that are not critical (like the ones producing HTTP 4xx responses) are not popping up in the PHPUnit tests anymore.
My PHPUnit tests are also now able to deal with PSR-7 HTTP Response objects, instead of capturing the output buffer.
I am getting an error trying to display a new page i setup. It gives a message "Internal error" which is configured in my errors controller:
public function show500Action()
{
\Phalcon\Tag::setTitle('Internal Error - '.SKIN_NAME);
}
Normally my error and access log display errors fine but from time to time it doesnt display anything. I am guessing there might be different levels of error logging but im not sure how to set that.
using
echo "test";
die();
In various parts of the code and managed to narrow down the error to a line:
$user = AdminUser::find(array("order" => "name_admin"));
So i tried this but i still dont get an error
try {
$user = AdminUser::find(array("order" => "name_admin"));
} catch(Exception $e) {
echo 'Message: ' .$e->getMessage();
}
Even if the try/catch worked im sure there is a way to make it write the error to the log like other logs rather than having to narrow down the error and do a try catch every time
There is a model called AdminUser and the corresponding database table adminUser so i cant figure out where the error is coming from
I had a similar error a couple of weeks back. After querying with a model php would get an error but log absolutely nothing and I was never able to log it in the end.
In my case, it was due to an invalid namespace usage. You could attempt to test if the class exists to check that. If it does not I would say there's an incorrect auto-loading of the model's namespace where your loader registers namespaces and/or the usage call at the top of the script is incorrect.
Hope that helps!
This is a general question regarding exception handing for exceptions thrown in onther people's code.
I am using the following Codeigniter PHP library: https://github.com/sepehr/ci-mongodb-base-model
which relies upon this library for MongoDB: https://github.com/alexbilbie/codeigniter-mongodb-library/tree/v2
If I call a function in the first library, and it then calls one from the second. Sometimes the second library throws exceptions which I want to be able to deal with in my own code, but there is a try-catch statement around the exception throwing call, which means that it is dealt with before I get a chance to (I just prints the exception to the screen).
My question is:
Without modifying all of the functions in the first and second libraries (i.e. removing all of the try catches), how can I deal with the exception that is thrown?
EDIT
This is how the functions in the second library are arranged:
class SomeClass
{
function do_something()
{
...
try {
...
}
catch {
$this->_show_error('Update of data into MongoDB failed: ' . $exception->getMessage(), 500);
}
}
function _show_error($error_message = '', $response_code = 500)
{
//Inbuilt Codeigniter helper function which can be disabled from printing the error to the screen
show_error($error_message, $response_code);
}
}
Although I can disable the error from being printed (which is of course just for debugging), I still have no way of knowing that it occurred and handling it.
(should be a comment rather than an answer, but it's a bit long)
just prints the exception to the screen
Really? Are you sure?
Did you check it doesn't trigger an error instead of an exception and you're running this on a system which is not configured as a production server?
If so then I'd steer way clear of this as a library.
(I sincerely doubt anyone would write code that dumb and publish it without lots of warnings)
I have three text files containing the same set of error messages in three languages: English, French and German.
I need to extend the exception class so that when something goes wrong, the own exception object will be thrown, such as "throw new My-Exception("English", 4) - then 4th message in English file will be shown.
This is what I made so far:
<?php
class My_Exception extends Exception {
function __construct($lang, $errcode) {
$this->lang = $lang;
$this->errcode = $errcode;
}
function getMessageMap() {
$errors = file('errfiles/'.$this->lang.'.txt');
foreach($errors as $error) {
list($key,$value) = implode(',', $errors);
$errorArray[$key] = $value;
}
return $errorArray[$this->errcode];
}
}
try { throw new My_Exception('english', 3); }
catch (My_Exception $e) { echo $e->getMessageMap(); }
?>
This doesn't work properly. I will appreciate any help.
Instead of throwing specific exception messages for each language, I would stick to one normal exception. Then, in your application when you catch those errors, you can show an error page for specific languages. In other words, don't overhaul your application architecture (even in this minor way) for what is ultimately a font-end problem.
You mention that the error message looks like this:
file(errfiles/English.txt): failed to open stream
So try using the full path of the error file...
$errors = file('C:/xampp/htdocs/HW4/errfiles/'.$this->lang.'.txt');
Also can you confirm that the file really does start with a capital "E"?
The second error:
Invalid argument supplied for foreach() in
C:\xampp\htdocs\HW4\index.php on line 13
Is because of the first one. Fix that and all is well.
I think you have implode() and explode() mixed up. Assuming your errors.txt file looks like:
1,I am error one
2,I am error two
You want each $errors as $error to thusly explode(',', '1,I am error one'); as:
array("1", "I am error 1")
And yes, the "1" is a string until you specifically cast it as an int using either (int)$errno or intval($errno).
PHP is 'loosely typed' and usually does this in the background so you don't have to worry about it, but you should worry about it. Otherwise you'll run into the occasional situations where your code does very strange things.
I'm familiar with some of the basics, but what I would like to know more about is when and why error handling (including throwing exceptions) should be used in PHP, especially on a live site or web app. Is it something that can be overused and if so, what does overuse look like? Are there cases where it shouldn't be used? Also, what are some of the common security concerns in regard to error handling?
One thing to add to what was said already is that it's paramount that you record any errors in your web application into a log. This way, as Jeff "Coding Horror" Atwood suggests, you'll know when your users are experiencing trouble with your app (instead of "asking them what's wrong").
To do this, I recommend the following type of infrastructure:
Create a "crash" table in your database and a set of wrapper classes for reporting errors. I'd recommend setting categories for the crashes ("blocking", "security", "PHP error/warning" (vs exception), etc).
In all of your error handling code, make sure to record the error. Doing this consistently depends on how well you built the API (above step) - it should be trivial to record crashes if done right.
Extra credit: sometimes, your crashes will be database-level crashes: i.e. DB server down, etc. If that's the case, your error logging infrastructure (above) will fail (you can't log the crash to the DB because the log tries to write to the DB). In that case, I would write failover logic in your Crash wrapper class to either
send an email to the admin, AND/OR
record the details of the crash to a plain text file
All of this sounds like an overkill, but believe me, this makes a difference in whether your application is accepted as a "stable" or "flaky". That difference comes from the fact that all apps start as flaky/crashing all the time, but those developers that know about all issues with their app have a chance to actually fix it.
Roughly speaking, errors are a legacy in PHP, while exceptions are the modern way to treat errors. The simplest thing then, is to set up an error-handler, that throws an exception. That way all errors are converted to exceptions, and then you can simply deal with one error-handling scheme. The following code will convert errors to exceptions for you:
function exceptions_error_handler($severity, $message, $filename, $lineno) {
if (error_reporting() == 0) {
return;
}
if (error_reporting() & $severity) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
}
set_error_handler('exceptions_error_handler');
error_reporting(E_ALL ^ E_STRICT);
There are a few cases though, where code is specifically designed to work with errors. For example, the schemaValidate method of DomDocument raises warnings, when validating a document. If you convert errors to exceptions, it will stop validating after the first failure. Some times this is what you want, but when validating a document, you might actually want all failures. In this case, you can temporarily install an error-handler, that collects the errors. Here's a small snippet, I've used for that purpose:
class errorhandler_LoggingCaller {
protected $errors = array();
function call($callback, $arguments = array()) {
set_error_handler(array($this, "onError"));
$orig_error_reporting = error_reporting(E_ALL);
try {
$result = call_user_func_array($callback, $arguments);
} catch (Exception $ex) {
restore_error_handler();
error_reporting($orig_error_reporting);
throw $ex;
}
restore_error_handler();
error_reporting($orig_error_reporting);
return $result;
}
function onError($severity, $message, $file = null, $line = null) {
$this->errors[] = $message;
}
function getErrors() {
return $this->errors;
}
function hasErrors() {
return count($this->errors) > 0;
}
}
And a use case:
$doc = new DomDocument();
$doc->load($xml_filename);
$validation = new errorhandler_LoggingCaller();
$validation->call(
array($doc, 'schemaValidate'),
array($xsd_filename));
if ($validation->hasErrors()) {
var_dump($validation->getErrors());
}
The best practice IMHO is to use the following approach:
1. create an error/exception handler
2. start it upon the app start up
3. handle all your errors from inside there
<?php
class Debug {
public static setAsErrorHandler() {
set_error_handler(array(__CLASS__, '__error_handler'));
}
public static function __error_handler($errcode, $errmsg, $errfile, $errline) {
if (IN DEV) {
print on screen
}
else if (IN PRO) {
log and mail
}
}
}
Debug::setAsErrorHandler();
?>
Unhanded errors stop the script, that alone is a pretty good reason to handle them.
Generally you can use a Try-Catch block to deal with errors
try
{
// Code that may error
}
catch (Exception $e)
{
// Do other stuff if there's an error
}
If you want to stop the error or warning message appearing on the page then you can prefix the call with an # sign like so.
#mysql_query($query);
With queries however it's generally a good idea to do something like this so you have a better idea of what's going on.
#mysql_query($query)
or die('Invalid query: ' . mysql_error() . '<br />Line: ' . __LINE__ . '<br />File: ' . __FILE__ . '<br /><br />');
You should use Error Handling in cases where you don't have explicit control over the data your script is working on. I tend to use it frequently for example in places like form validation. Knowing how to spot error prone places in code takes some practice: Some common ones are after function calls that return a value, or when dealing with results from a database query. You should never assume the return from a function will be what your expecting, and you should be sure to code in anticipation. You don't have to use try/catch blocks, though they are useful. A lot of times you can get by with a simple if/else check.
Error handling goes hand in hand with secure coding practices, as there are a lot of "errors" that don't cause your script to simply crash. while not being strictly about error handling per se, addedbytes has a good 4 article series on some of the basics of secure PHP programming which you can find HERE. There are a lot of other questions here on stackoverflow on topics such as mysql_real_escape_string and Regular Expressions which can be very powerful in confirming the content of user entered data.
Rather than outputing the mysql_error you might store it in a log. that way you can track the error (and you don't depend on users to report it) and you can go in and remove the problem.
The best error handling is the kind that is transparent to the user, let your code sort out the problem, no need to involve that user fellow.
besides handling errors right away in your code you can also make use of
http://us.php.net/manual/en/function.set-exception-handler.php
and
http://us.php.net/manual/en/function.set-error-handler.php
I find setting your own exception handler particularly useful. When an exception occurs you can perform different operations depending on what type of exception it is.
ex: when a mysql_connet call returns FALSE I throw a new DBConnectionException(mysql_error()) and handle it a "special" way: log the error, the DB connection info (host, username, password) etc and maybe even email the dev team notifying them that something may be really wrong with the DB
I use this to compliment standard error handling. i wouldnt recommend overusing this approach
Error suppression with # is very slow.
You can also use Google Forms to catch and analyse exceptions, without having to maintain a database or publicly accessible server. There is a tutorial here that explains the process.
public $error=array();
public function Errors($Err)
{
------ how to use -------
$Err = array("func" => "constr", "ref" => "constrac","context" =>
"2222222ت","state" => 3,);
$ResultErr=$this->Errors($Err);
$context=(array_filter(explode(',', $ResultErr['context'])));
$func=(array_filter(explode(',', $ResultErr['func'])));
$ref=(array_filter(explode(',', $ResultErr['ref'])));
$state=($ResultErr['state']);
$errors=array_merge(["context"=>$context], ["func"=>$func],
["ref"=>$ref], ["state"=>$state]);
var_dump($errors);
---------------begine ------------------------
global $error;
if (!is_array($Err)) {
return $error;
} else {
if (!(isset($error['state']))) {
$error['state']="";
}
if (!(isset($error['func']))) {
$error['func']="";
}
if (!(isset($error['ref']))) {
$error['ref']="";
}
if (!(isset($error['context']))) {
$error['context']="";
}
$error['state']=$error['state'];
$error['func']=$error['func'].= $Err["func"].",";
$error['ref']=$error['ref'].= $Err["ref"].",";
$error['context']=$error['context'].= $Err["context"].",";
$error["state"]=$Err["state"];
return $error;
}
}