In PHP sometimes we prepend a function call with the # operator to suppress the warnings that can be eventually shown on the page.
Assuming that the application is set up to log error and warnings to a file, when a warning is "suppressed" its correspondent entry in the logfile will be created anyway?
It is my understanding, that it won't write to the log file - after reading http://php.net/manual/en/language.operators.errorcontrol.php
It effectively temporarilly sets the error reporting level to 0, and I believe if the error reporting level is 0, errors are not written to the log
Related
This is my error setting
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL|E_PARSE);
Now I write this test code:
helloooooo;
And It shows me:
Use of undefined constant helloooooo ...
So far so good.
Now I remove the semicolon from end of my so-called code:
helloooooo
Shows nothing. It shows a white page.
In my experience whenever I see a white page there is a syntax error so I look for a typo.
The question is why doesn't PHP help in this case?
Someone said :
Syntax checking is done before executing any code. So it can't execute
the ini_set() functions if there's a syntax error.
How about PHP interpreter applies settings first then executes the rest of code?
JavaScript interpreter can detect the same error in runtime.
Just try this:
<script>
helloooooo
</script>
Now go to Firefox => Tools=> WebDeveloper => WebConsole
ReferenceError: helloooooo is not defined
PHP's default error reporting mechanism (might) suppress error output. If you're trying to turn it on at runtime using the error_reporting function, then PHP will first have to successfully parse the file, then execute it to set that new desired error reporting level. That fails when there are syntax errors, because then PHP can't successfully parse and execute the file to change the error reporting level. The syntax error is getting suppressed because… well… it couldn't change the error reporting level yet.
Javascript doesn't have that, it outputs any and all errors it encounters.
The reason PHP likes to suppress errors is because its running on the server, and internal server debug details shouldn't be shown on public web pages. In Javascript that is moot, since it's running in the browser anyway, and the errors are reported to the console, which regular users don't see. Moreover, PHP does log all errors to a log file, so the same way you go looking for errors in Javascript, you could explicitly go looking for them in PHP's log file as well.
I have:
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
It seems to work but when I use copy() function and try to copy to directory with denied access the error is displayed on the page itself. I don't need it. But I can't intercept copy()'s errors. I tried error_get_last() and try...catch (Exception $e) but still can't intercept it? How can I disable showing copy errors on page and how to intercept them in code?
If catching the copy error is all you need to do then:
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
// Log the error somewhere without spooking the users
return true;
});
copy(...);
restore_error_handler();
This way you can "silence" only this error and keep everything else working as before.
from runtime it is better (and more reliable) to use:
error_reporting(0);
see: http://php.net/manual/en/function.error-reporting.php for more info.
also you can suppress any errors regarding of reporting level by prefixing expression with #:
#copy(...)
see: http://php.net/manual/en/language.operators.errorcontrol.php for more info, also note what this cause a performance drop and causes expression to return boolean false if error occured, regardless of its original return type.
Worth noting:
If you are using nginx+php-fpm (or similar) ini values may be overriden in php-fpm's pool configuration.
If you are using apache+mod_php ini values may be overriden in .htaccess file.
Check that, before resolving to error_reporting(0), turning off error_reporting completely is not what you should do, as this may lead to broken logic (many popular libraries and frameworks rely on error reporting by setting handlers to traslate errors to exceptions).
In terms of portability use of error suppressing operator is preferred, dispite its affect on performance.
I am repairing some old code that was made before me and I took about 2 hours to find a error because it was hidden by #.
Is that a way to deactivate this in PHP?
display_errors don't get errors hidden by #
You can define a custom error handler as described in the php documentation for error control operator
You can enable track_errors to save whatever error was generated by the error control operator (#) to a PHP variable. You can set track_errors in your php.ini file or use ini_set.
If the track_errors feature is enabled, any error message generated by
the expression will be saved in the variable $php_errormsg. This
variable will be overwritten on each error, so check early if you want
to use it.
Example
<?php
ini_set('track_errors', true);
#strpos();
echo $php_errormsg;
Will output:
strpos() expects at least 2 parameters, 0 given
Caveats
It is important to note that critical errors that cause the script to terminate that are suppressed by # will not be discoverable this way. In this case, if your script dies unexpectedly and without an error message, that should be a good indication to search for the # in your code.
Currently the "#" error-control operator prefix will even disable
error reporting for critical errors that will terminate script
execution. Among other things, this means that if you use "#" to
suppress errors from a certain function and either it isn't available
or has been mistyped, the script will die right there with no
indication as to why.
I am using PHP 5.3.5 and I am using
$this->marubox=#imap_open($this->server,$this->username,$this->password);
The # sign should silence error reporting but it doesnt and I am sure that the error occurs on this line. I want my application to recognize the problem itself and react and get no NOTICE errors and I can't turn off error reporting for whole PHP because of my company development policy.
Without # i am getting:
imap_open() [function.imap-open]: Couldn't open stream {pop3.seznam.cz:110/pop3}INBOX
With it i get: Notice Unknown: Authentication failed (Authentication failed) (errflg=1)
If the login information is ok it opens the connection and no errors occur.
I always get NOTICE error when imap_open doesnt manage to connect and it's messing up with my JSON results. How to silence it please?
I added
$this->marubox=#imap_open($this->server,$this->username,$this->password);
imap_errors();
imap_alerts();
and imap_errors(); and imap_alerts(); do the magic :)
Two possibilities come to mind:
You could set error_reporting in your php.ini, ini_set or .htaccess or similar so that the NOTICE is suppressed, but since you wan't your application to handle the error, this is probably not, what you need
Implement your own error handling. This is not so difficult to do. You define a function for error hadnling and then tell PHP to use it instead of it's own default handler.
//define
function myHandler($errno, $errstr) {}
//somewhere towards the beginning of your processing script
set_error_handler("myHandler");
See set_error_handler for more. Also note that from the moment you register the handler, you're solely responsible. You can suppress or throw any errors you need/want.
Please tell me if this is correct. In my error handler, I need to be able to detect when the # error-control operator was used to suppress errors, because some external libraries (sadly) use it a lot. Execution of the script should continue, just like when you don't use custom error handlers.
When the at-sign is used, PHP temporarily sets error_reporting to 0. So at the start of a script we set error_reporting to any value but zero - we can now do some beautiful IF/ELSE magic. To avoid any errors being shown at the frontend, we also set display_errors to 0, this will override error_reporting (but we can still use it's value for magic).
<?php
ini_set('display_errors',0);
error_reporting(E_ALL);
function error_handler($errno, $errstr, $errfile, $errline)
{
if (error_reporting()===0) return;
else die();
}
set_error_handler('error_handler');
//This issues an error, but the handler will return and execution continues.
//Remove the at-sign and the script will die()
#file();
echo 'Execution continued, hooray.';
?>
So.. Are there no catches here? Except the one where the external library overrides my error handling.. (any tips on that?)
Considering what your script does, and some user notes on the # operator manual page, it seems what you are doing is OK.
For instance, taras says :
I was confused as to what the # symbol
actually does, and after a few
experiments have concluded the
following:
the error handler that is set gets called regardless of what level the
error reporting is set on, or whether
the statement is preceeded with #
it is up to the error handler to impart some meaning on the different
error levels. You could make your
custom error handler echo all errors,
even if error reporting is set to
NONE.
so what does the # operator do? It temporarily sets the error reporting
level to 0 for that line. If that line
triggers an error, the error handler
will still be called, but it will be
called with an error level of 0
And the set_error_handler manual page seems to confirm that :
Of particular note is that this value will be 0 if the statement
that caused the error was prepended by the # error-control operator.
Here too, there are some user notes that can be useful ; for instance, this one (see the begining of the code)
Still, if what you want is to "disable" the effect of the # operator (not sure I understood the question correctly ; this might help you anyway), to be able to get the error messages while you are on your development environment, you can install the scream extension (pecl, manual)
Provided you configure it the right way, setting this in your php.ini (after installating/loading the extension, of course) :
scream.enabled = 1
This extension will simply disable the # operator.
And here's an example (quoting the manual) :
<?php
// Make sure errors will be shown
ini_set('display_errors', true);
error_reporting(E_ALL);
// Disable scream - this is the default and produce an error
ini_set('scream.enabled', false);
echo "Opening http://example.com/not-existing-file\n";
#fopen('http://example.com/not-existing-file', 'r');
// Now enable scream and try again
ini_set('scream.enabled', true);
echo "Opening http://example.com/not-existing-file\n";
#fopen('http://example.com/another-not-existing-file', 'r');
?>
And this will output :
Opening http://example.com/not-existing-file
Opening http://example.com/not-existing-file
Warning: fopen(http://example.com/another-not-existing-file): failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found in example.php on line 14
I am not sure I would use this extension on a production server (where I never want errors displayed), but it is very useful on a development machine, when using old code, on an application/library that uses # operator extensivly...