Alternating class not found error when using session handler - php

First of all, if it's relevant, this is in a session handler. This function is the one that writes to the database and is passed to session_set_save_handler along with my other functions like this
session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy', 'sess_gc');
I have this chunk of code...
$qid = "select count(*) as total
from zen_sessions
where sesskey = '" . $key . "'";
if(!class_exists('DB'))
require_once dirname(dirname(__FILE__)).'/class/DB.class.php';
var_dump(new DB()); //this is line 109
$total = DB::select_one($qid);
the conditional and var_dump are for testing. Oddly enough sometimes it works fine while others it gives me an error:
Fatal error: Class 'DB' not found in /path/to/file/session_functions.php on line 109
I cannot figure how this wouldn't crash at the require instead of the var_dump and why only sometimes?
Thanks in advance for any insight.
edit-- response to comment/question:
The result of the following code
var_dump(class_exists('DB', false));
var_dump(is_file(dirname(__DIR__).'/class/DB.class.php'));
is:
bool(false) bool(true)
before trying to require it and the same result after the require(or true true when it doesn't give me an error)
Looks something like:
bool(true) bool(true) object(DB)#3 (0) { }
The previous code chunk is the result about once out of every 5 page loads while the error is the result the other 4.
Edit2 -- new findings.
Even more curious is according to the manual I should never see these debugging statements or errors
Note:
The "write" handler is not executed until after the output stream is
closed. Thus, output from debugging statements in the "write" handler
will never be seen in the browser. If debugging output is necessary,
it is suggested that the debug output be written to a file instead.
Edit 3 - A Note for clarity:
The DB class Should have been autoloaded(and is everywhere else in the application) the class_exists and require are simply there for testing purposes.
Edit 4 - Stack trace
I decided to try and throw an exception when the class isn't found to see the stack trace, this is what I get
Fatal error: Uncaught exception 'Exception' with message 'DB Class Not Found.'
in /path/to/file/session_functions.php:108
Stack trace: #0 [internal function]: sess_write('074dabb967260e9...', 'securityToken|s...')
#1 {main} thrown in /path/to/file/session_functions.php on line 108

The only thing that I can think of that may be causing this, is from a notice in the PHP docs for session_set_save_handler:
Warning
Current working directory is changed with some SAPIs if session is closed in the script termination. It is possible to close the session earlier with session_write_close().
From what you are experiencing, I am guessing the current working directory is changed, so require_once doesn't find the file.
I would try adding session_write_close(); to somewhere in your function and see if that fixes it.
Admittedly, not sure why is_file would return true in this case, but maybe worth a shot.

Even though I can not be sure, but I bet that the error is somewhere else and it's just projecting itself as you've described it.
In order to test and debug your code, you need to use a debugger like PDT. But then the problem is that you need to debug a part of your code that is out of debugger's reach, the session writer! To overcome this problem you can use session_write_close. You can put it somewhere at the end of your bootstrap or if you don't have one, you can do it like this:
<?php
function shutdown_function()
{
session_write_close();
}
register_shutdown_function('shutdown_function');
Then by setting a break point, you can start debugging your session code from here. Let me know if I win the bet.

try:
$save_handler = new DB();
session_set_save_handler($save_handler, true);
then map read, write, etc functions inside your class. i faced a similar issue(bizarre random errors about a class not being found) implementing another user's custom save handler workaround for HHVM with redis, and this is how i fixed it. if you are using HipHopVirtualMachine (or possibly some other type of JIT compiler or app cache), sometimes your project can cache some functions without updating, producing odd errors like this. usually a restart of the fastcgi daemon and adding white space to one of your files is enough to force it to re interpret your project.

Related

What exactly does the # symbol in front of new mean? [duplicate]

In your opinion, is it ever valid to use the # operator to suppress an error/warning in PHP whereas you may be handling the error?
If so, in what circumstances would you use this?
Code examples are welcome.
Edit: Note to repliers. I'm not looking to turn error reporting off, but, for example, common practice is to use
#fopen($file);
and then check afterwards... but you can get rid of the # by doing
if (file_exists($file))
{
fopen($file);
}
else
{
die('File not found');
}
or similar.
I guess the question is - is there anywhere that # HAS to be used to supress an error, that CANNOT be handled in any other manner?
Note: Firstly, I realise 99% of PHP developers use the error suppression operator (I used to be one of them), so I'm expecting any PHP dev who sees this to disagree.
In your opinion, is it ever valid to use the # operator to suppress an error/warning in PHP whereas you may be handling the error?
Short answer:
No!
Longer more correct answer:
I don't know as I don't know everything, but so far I haven't come across a situation where it was a good solution.
Why it's bad:
In what I think is about 7 years using PHP now I've seen endless debugging agony caused by the error suppression operator and have never come across a situation where it was unavoidable.
The problem is that the piece of code you are suppressing errors for, may currently only cause the error you are seeing; however when you change the code which the suppressed line relies on, or the environment in which it runs, then there is every chance that the line will attempt to output a completely different error from the one you were trying to ignore. Then how do you track down an error that isn't outputting? Welcome to debugging hell!
It took me many years to realise how much time I was wasting every couple of months because of suppressed errors. Most often (but not exclusively) this was after installing a third party script/app/library which was error free in the developers environment, but not mine because of a php or server configuration difference or missing dependency which would have normally output an error immediately alerting to what the issue was, but not when the dev adds the magic #.
The alternatives (depending on situation and desired result):
Handle the actual error that you are aware of, so that if a piece of code is going to cause a certain error then it isn't run in that particular situation. But I think you get this part and you were just worried about end users seeing errors, which is what I will now address.
For regular errors you can set up an error handler so that they are output in the way you wish when it's you viewing the page, but hidden from end users and logged so that you know what errors your users are triggering.
For fatal errors set display_errors to off (your error handler still gets triggered) in your php.ini and enable error logging. If you have a development server as well as a live server (which I recommend) then this step isn't necessary on your development server, so you can still debug these fatal errors without having to resort to looking at the error log file. There's even a trick using the shutdown function to send a great deal of fatal errors to your error handler.
In summary:
Please avoid it. There may be a good reason for it, but I'm yet to see one, so until that day it's my opinion that the (#) Error suppression operator is evil.
You can read my comment on the Error Control Operators page in the PHP manual if you want more info.
I would suppress the error and handle it. Otherwise you may have a TOCTOU issue (Time-of-check, time-of-use. For example a file may get deleted after file_exists returns true, but before fopen).
But I wouldn't just suppress errors to make them go away. These better be visible.
Yes suppression makes sense.
For example, the fopen() command returns FALSE if the file cannot be opened. That's fine, but it also produces a PHP warning message. Often you don't want the warning -- you'll check for FALSE yourself.
In fact the PHP manual specifically suggests using # in this case!
If you don't want a warning thrown when using functions like fopen(), you can suppress the error but use exceptions:
try {
if (($fp = #fopen($filename, "r")) == false) {
throw new Exception;
} else {
do_file_stuff();
}
} catch (Exception $e) {
handle_exception();
}
Error suppression should be avoided unless you know you can handle all the conditions.
This may be much harder than it looks at first.
What you really should do is rely on php's "error_log" to be your reporting method, as you cannot rely on users viewing pages to report errors. ( And you should also disable php from displaying these errors )
Then at least you'll have a comprehensive report of all things going wrong in the system.
If you really must handle the errors, you can create a custom error handler
http://php.net/set-error-handler
Then you could possibly send exceptions ( which can be handled ) and do anything needed to report weird errors to administration.
I NEVER allow myself to use '#'... period.
When I discover usage of '#' in code, I add comments to make it glaringly apparent, both at the point of usage, and in the docblock around the function where it is used. I too have been bitten by "chasing a ghost" debugging due to this kind of error suppression, and I hope to make it easier on the next person by highlighting its usage when I find it.
In cases where I'm wanting my own code to throw an Exception if a native PHP function encounters an error, and '#' seems to be the easy way to go, I instead choose to do something else that gets the same result but is (again) glaringly apparent in the code:
$orig = error_reporting(); // capture original error level
error_reporting(0); // suppress all errors
$result = native_func(); // native_func() is expected to return FALSE when it errors
error_reporting($orig); // restore error reporting to its original level
if (false === $result) { throw new Exception('native_func() failed'); }
That's a lot more code that just writing:
$result = #native_func();
but I prefer to make my suppression need VERY OBVIOUS, for the sake of the poor debugging soul that follows me.
Most people do not understand the meaning of error message.
No kidding. Most of them.
They think that error messages are all the same, says "Something goes wrong!"
They don't bother to read it.
While it's most important part of error message - not just the fact it has been raised, but it's meaning. It can tell you what is going wrong. Error messages are for help, not for bothering you with "how to hide it?" problem. That's one of the biggest misunderstandings in the newbie web-programming world.
Thus, instead of gagging error message, one should read what it says. It has not only one "file not found" value. There can be thousands different errors: permission denied, save mode restriction, open_basedir restriction etc.etc. Each one require appropriate action. But if you gag it you'll never know what happened!
The OP is messing up error reporting with error handling, while it's very big difference!
Error handling is for user. "something happened" is enough here.
While error reporting is for programmer, who desperately need to know what certainly happened.
Thus, never gag errors messages. Both log it for the programmer, and handle it for the user.
is there not a way to suppress from the php.ini warnings and errors? in that case you can debug only changing a flag and not trying to discovering which # is hiding the problem.
Using # is sometimes counter productive. In my experience, you should always turn error reporting off in the php.ini or call
error_reporting(0);
on a production site. This way when you are in development you can just comment out the line and keep errors visible for debugging.
One place I use it is in socket code, for example, if you have a timeout set you'll get a warning on this if you don't include #, even though it's valid to not get a packet.
$data_len = #socket_recvfrom( $sock, $buffer, 512, 0, $remote_host, $remote_port )
The only place where I really needed to use it is the eval function. The problem with eval is that, when string cannot be parsed due to syntax error, eval does not return false, but rather throws an error, just like having a parse error in the regular script. In order to check whether the script stored in the string is parseable you can use something like:
$script_ok = #eval('return true; '.$script);
AFAIK, this is the most elegant way to do this.
Some functions in PHP will issue an E_NOTICE (the unserialize function for example).
A possible way to catch that error (for PHP versions 7+) is to convert all issued errors into exceptions and not let it issue an E_NOTICE. We could change the exception error handler as follow:
function exception_error_handler($severity, $message, $file, $line) {
throw new ErrorException($message, 0, $severity, $file, $line);
}
set_error_handler('exception_error_handler');
try {
unserialize('foo');
} catch(\Exception $e) {
// ... will throw the exception here
}
Today I encountered an issue that was a good example on when one might want to use at least temporarily the # operator.
Long story made short, I found logon info (username and password in plain text) written into the error log trace.
Here a bit more info about this issue.
The logon logic is in a class of it's own, because the system is supposed to offer different logon mechanisms. Due to server migration issues there was an error occurring. That error dumped the entire trace into the error log, including password info! One method expected the username and password as parameters, hence trace wrote everything faithfully into the error log.
The long term fix here is to refactor said class, instead of using username and password as 2 parameters, for example using a single array parameter containing those 2 values (trace will write out Array for the paramater in such cases). There are also other ways of tackling this issue, but that is an entire different issue.
Anyways. Trace messages are helpful, but in this case were outright harmful.
The lesson I learned, as soon as I noticed that trace output: Sometimes suppressing an error message for the time being is an useful stop gap measure to avoid further harm.
In my opinion I didn't think it is a case of bad class design. The error itself was triggered by an PDOException ( timestamp issue moving from MySQL 5.6 to 5.7 ) that just dumped by PHP default everything into the error log.
In general I do not use the # operator for all the reasons explained in other comments, but in this case the error log convinced me to do something quick until the problem was properly fixed.
You do not want to suppress everything, since it slows down your script.
And yes there is a way both in php.ini and within your script to remove errors (but only do this when you are in a live environment and log your errors from php)
<?php
error_reporting(0);
?>
And you can read this for the php.ini version of turning it off.
I have what I think is a valid use-case for error suppression using #.
I have two systems, one running PHP 5.6.something and another running PHP 7.3.something. I want a script which will run properly on both of them, but some stuff didn't exist back in PHP 5.6, so I'm using polyfills like random_compat.
It's always best to use the built-in functions, so I have code that looks like this:
if(function_exists("random_bytes")) {
$bytes = random_bytes(32);
} else {
#include "random_compat/random.php"; // Suppress warnings+errors
if(function_exists("random_bytes")) {
$bytes = random_bytes(32);
} else if(function_exists('openssl_random_pseudo_bytes')) {
$bytes = openssl_random_pseudo_bytes(4);
} else {
// Boooo! We have to generate crappy randomness
$bytes = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',64)),0,32);
}
}
The fallback to the polyfill should never generate any errors or warnings. I'm checking to see that the function exists after attempting to load the polyfill which is all that is necessary. There is even a fallback to the fallback. And a fallback to the fallback to the fallback.
There is no way to avoid a potential error with include (e.g. using file_exists) so the only way to do it is to suppress warnings and check to see if it worked. At least, in this case.
I can think of one case of use, for auto-increment a non existing array key.
<?php
$totalCars = [];
// suppressing error to avoid a getting a warning error
#$totalCars['toyota']++;
var_export($totalCars);
// array (
// 'toyota' => 1,
// )
// not suppressing error will throw a warning
// but still allows to increase the non-existing key value
$totalCars['ford']++;
var_export($totalCars);
// Warning: Undefined array key "ford"
// array (
// 'toyota' => 1,
// 'ford' => 1,
// )
See this example output here: https://onlinephp.io/c/433f0
If you are using a custom error handling function and wanna suppress an error (probably a known error), use this method. The use of '#' is not a good idea in this context as it will not suppress error if error handler is set.
Write 3 functions and call like this.
# supress error for this statement
supress_error_start();
$mail_sent = mail($EmailTo, $Subject, $message,$headers);
supress_error_end(); #Don't forgot to call this to restore error.
function supress_error_start(){
set_error_handler('nothing');
error_reporting(0);
}
function supress_error_end(){
set_error_handler('my_err_handler');
error_reporting('Set this to a value of your choice');
}
function nothing(){ #Empty function
}
function my_err_handler('arguments will come here'){
//Your own error handling routines will come here
}
In my experience I would say generally speaking, error suppress is just another bad practice for future developers and should be avoided as much as possible as it hides complication of error and prevent error logging unlike Exception which can help developers with error snapshot. But answering the original question which say "If so, in what circumstances would you use this?".
I would say one should use it against some legacy codes or library that don't throw exception errors but instead handles bad errors by keep the error variables with it's object(speaking of OOP) or using a global variable for logging error or just printing error all together.
Take for example the mysqli object
new mysqli($this->host, $this->username, $this->password, $this->db);
This code above barely or never throw an exception on failed connection, it only store error in mysqli::errno and mysli::error
For modern day coding the one solution I found was to suppress the ugly error messages (which helps no one especially when on production server where debug mode is off) and instead devs should throw their own exception. Which is consider modern practice and help coders track errors more quickly.
$this->connection = #new mysqli($this->host, $this->username, $this->password, $this->db);
if($this->connection->connect_errno)
throw new mysqli_sql_exception($this->connection->error);
You can notice the use of suppression # symbol to prevent the ugly error display should incase error display was turned on development server.
Also I had to throw my own exception. This way I was able to use # symbol and same time I didn't hide error nor did I just make my own guess of what the error could be.
I will say if used rightly, then it is justifiable.
I use it when trying to load an HTML file for processing as a DOMDocument object. If there are any problems in the HTML... and what website doesn't have at least one... DOMDocument->loadHTMLFile() will throw an error if you don't suppress it with #. This is the only way (perhaps there are better ones) I've ever been successful in creating HTML scrapers in PHP.

Throwing exception from custom error handler in PHP

I was working on resource streams and more specifically on fopen().
This function throws a warning when failing, in addition to returning false instead of a resource. The unwanted warnings beings a problem I decided to suppress them.
Two possibilities came to my mind: using the error-suppression operator # or using set_error_handler(). And having been told that # had not so good performances and posed often more problem than it resolved, I ran a quick benchmark to see how set_error_handler() fared against it.
And here comes the problematic code:
<?php
error_reporting(E_ALL);
function errorHandler(int $errorNumber, string $errorMessage)
{
throw new \Exception();
}
$previousHandler = set_error_handler("errorHandler");
$operations = 10000;
for($i = 0; $i < $operations; $i++) {
try{
$inexistant[0];
} catch (\Exception $e) {}
}
set_error_handler($previousHandler);
echo 'ok';
Running this simple code will crash the apache server with this message:
[mpm_winnt:notice] [pid 6000:tid 244] AH00428: Parent: child process 3904 exited with status 3221225725 -- Restarting.
After searching, this message means that the server had an access violation error, mainly in the case of reaching the stack size limit. This however should not be the case as this code should not increase the stack size (and in fact, it doesn't increase the PHP stack frames).
I also tested if the timing was important but even with a sleep of 3ms between each iteration the crash happen after more or less the same number of iteration. This number is around 700 but fluctuate very slightly, sometimes running fine at 704 and sometimes not.
Also, searching on the php bug tracker doesn’t show anything relevant, except maybe for this bug entry which talk about the fact that there is handling around the call to the handling function. This could mean there is a possibility the exception could bypass some handling on the exit of the function, but as I don't know a thing about the PHP source code, this is pure speculation.
As I would like to propagate the error message properly, the way using set_error_handler() would be the most legible way, but I know I can use error_get_last() and the # operator to achieve the same goal with a lot more code (as there is multiple functions like fopen() called one after another in the real projet).
So here are the questions: Is this a bug of PHP? Is there a way to circumvent this problem while keeping clear code?
Thanks.
PS: I know the reason for the benchmark is... dubious at best and I should take whatever code is the most legible as long as the performances are viable, but it still made me discover this interesting point of code.
Edit: I forgot to put the versions I tested this against:
Windows 7, Apache 2.4.38, PHP 7.3.2 via XAMPP
Windows 7, Apache 2.4.29, PHP 7.2.2 via XAMPP
Ubuntu Server 18.04, Apache/2.4.29 (Ubuntu), PHP 7.2.15-0ubuntu0.18.04.1
Why go through all this hassle? It would be a lot better to just handle the return value of false, since the docs state: Returns a file pointer resource on success, or FALSE on error. Therefore it should be sufficient to just check if the return value of fopen is false and then continue operation based on that (or throw your own error if necessary).
As this was has been confirmed as a PHP bug and the exact reason was found, I'll post both the answers and how to solve this until the bug is solved.
First, here is the bug report: https://bugs.php.net/bug.php?id=77693.
It is a stack overflow caused the capture of the exception context, which in this case include the function calling the error handler as this is in his behavior to capture the parent context. This parent context include the previoulsy caught exception, which is added to the context of the new exception to be caught, and repeating ad vitam aeternam until a crash.
As the reason is clearly determined, the solution is simple: Just add an unset() to the end of the catch block, like so:
$operations = 10000;
for($i = 0; $i < $operations; $i++) {
try{
$inexistant[0];
} catch (\Exception $e) {
unset($e);
}
}
Then there is no more problem.
To add to the second question asking for clean alternatives in the case of fopen, and other methods like it, here is a solution:
function throwLastError() {
$context = error_get_last();
error_clear_last();
throw new ErrorException($context["message"],
0,
$context["type"],
$context["file"],
$context["line"]);
}
// Wrong call to fopen
if (!#fopen("", "a"))
throwLastError();
Both answers have around the same performances, the # method being 10% slower, when all the error parameters are used in both.

When would you use '#' expression to mute PHP error messages, rather than just debugging the issue? [duplicate]

In your opinion, is it ever valid to use the # operator to suppress an error/warning in PHP whereas you may be handling the error?
If so, in what circumstances would you use this?
Code examples are welcome.
Edit: Note to repliers. I'm not looking to turn error reporting off, but, for example, common practice is to use
#fopen($file);
and then check afterwards... but you can get rid of the # by doing
if (file_exists($file))
{
fopen($file);
}
else
{
die('File not found');
}
or similar.
I guess the question is - is there anywhere that # HAS to be used to supress an error, that CANNOT be handled in any other manner?
Note: Firstly, I realise 99% of PHP developers use the error suppression operator (I used to be one of them), so I'm expecting any PHP dev who sees this to disagree.
In your opinion, is it ever valid to use the # operator to suppress an error/warning in PHP whereas you may be handling the error?
Short answer:
No!
Longer more correct answer:
I don't know as I don't know everything, but so far I haven't come across a situation where it was a good solution.
Why it's bad:
In what I think is about 7 years using PHP now I've seen endless debugging agony caused by the error suppression operator and have never come across a situation where it was unavoidable.
The problem is that the piece of code you are suppressing errors for, may currently only cause the error you are seeing; however when you change the code which the suppressed line relies on, or the environment in which it runs, then there is every chance that the line will attempt to output a completely different error from the one you were trying to ignore. Then how do you track down an error that isn't outputting? Welcome to debugging hell!
It took me many years to realise how much time I was wasting every couple of months because of suppressed errors. Most often (but not exclusively) this was after installing a third party script/app/library which was error free in the developers environment, but not mine because of a php or server configuration difference or missing dependency which would have normally output an error immediately alerting to what the issue was, but not when the dev adds the magic #.
The alternatives (depending on situation and desired result):
Handle the actual error that you are aware of, so that if a piece of code is going to cause a certain error then it isn't run in that particular situation. But I think you get this part and you were just worried about end users seeing errors, which is what I will now address.
For regular errors you can set up an error handler so that they are output in the way you wish when it's you viewing the page, but hidden from end users and logged so that you know what errors your users are triggering.
For fatal errors set display_errors to off (your error handler still gets triggered) in your php.ini and enable error logging. If you have a development server as well as a live server (which I recommend) then this step isn't necessary on your development server, so you can still debug these fatal errors without having to resort to looking at the error log file. There's even a trick using the shutdown function to send a great deal of fatal errors to your error handler.
In summary:
Please avoid it. There may be a good reason for it, but I'm yet to see one, so until that day it's my opinion that the (#) Error suppression operator is evil.
You can read my comment on the Error Control Operators page in the PHP manual if you want more info.
I would suppress the error and handle it. Otherwise you may have a TOCTOU issue (Time-of-check, time-of-use. For example a file may get deleted after file_exists returns true, but before fopen).
But I wouldn't just suppress errors to make them go away. These better be visible.
Yes suppression makes sense.
For example, the fopen() command returns FALSE if the file cannot be opened. That's fine, but it also produces a PHP warning message. Often you don't want the warning -- you'll check for FALSE yourself.
In fact the PHP manual specifically suggests using # in this case!
If you don't want a warning thrown when using functions like fopen(), you can suppress the error but use exceptions:
try {
if (($fp = #fopen($filename, "r")) == false) {
throw new Exception;
} else {
do_file_stuff();
}
} catch (Exception $e) {
handle_exception();
}
Error suppression should be avoided unless you know you can handle all the conditions.
This may be much harder than it looks at first.
What you really should do is rely on php's "error_log" to be your reporting method, as you cannot rely on users viewing pages to report errors. ( And you should also disable php from displaying these errors )
Then at least you'll have a comprehensive report of all things going wrong in the system.
If you really must handle the errors, you can create a custom error handler
http://php.net/set-error-handler
Then you could possibly send exceptions ( which can be handled ) and do anything needed to report weird errors to administration.
I NEVER allow myself to use '#'... period.
When I discover usage of '#' in code, I add comments to make it glaringly apparent, both at the point of usage, and in the docblock around the function where it is used. I too have been bitten by "chasing a ghost" debugging due to this kind of error suppression, and I hope to make it easier on the next person by highlighting its usage when I find it.
In cases where I'm wanting my own code to throw an Exception if a native PHP function encounters an error, and '#' seems to be the easy way to go, I instead choose to do something else that gets the same result but is (again) glaringly apparent in the code:
$orig = error_reporting(); // capture original error level
error_reporting(0); // suppress all errors
$result = native_func(); // native_func() is expected to return FALSE when it errors
error_reporting($orig); // restore error reporting to its original level
if (false === $result) { throw new Exception('native_func() failed'); }
That's a lot more code that just writing:
$result = #native_func();
but I prefer to make my suppression need VERY OBVIOUS, for the sake of the poor debugging soul that follows me.
Most people do not understand the meaning of error message.
No kidding. Most of them.
They think that error messages are all the same, says "Something goes wrong!"
They don't bother to read it.
While it's most important part of error message - not just the fact it has been raised, but it's meaning. It can tell you what is going wrong. Error messages are for help, not for bothering you with "how to hide it?" problem. That's one of the biggest misunderstandings in the newbie web-programming world.
Thus, instead of gagging error message, one should read what it says. It has not only one "file not found" value. There can be thousands different errors: permission denied, save mode restriction, open_basedir restriction etc.etc. Each one require appropriate action. But if you gag it you'll never know what happened!
The OP is messing up error reporting with error handling, while it's very big difference!
Error handling is for user. "something happened" is enough here.
While error reporting is for programmer, who desperately need to know what certainly happened.
Thus, never gag errors messages. Both log it for the programmer, and handle it for the user.
is there not a way to suppress from the php.ini warnings and errors? in that case you can debug only changing a flag and not trying to discovering which # is hiding the problem.
Using # is sometimes counter productive. In my experience, you should always turn error reporting off in the php.ini or call
error_reporting(0);
on a production site. This way when you are in development you can just comment out the line and keep errors visible for debugging.
One place I use it is in socket code, for example, if you have a timeout set you'll get a warning on this if you don't include #, even though it's valid to not get a packet.
$data_len = #socket_recvfrom( $sock, $buffer, 512, 0, $remote_host, $remote_port )
The only place where I really needed to use it is the eval function. The problem with eval is that, when string cannot be parsed due to syntax error, eval does not return false, but rather throws an error, just like having a parse error in the regular script. In order to check whether the script stored in the string is parseable you can use something like:
$script_ok = #eval('return true; '.$script);
AFAIK, this is the most elegant way to do this.
Some functions in PHP will issue an E_NOTICE (the unserialize function for example).
A possible way to catch that error (for PHP versions 7+) is to convert all issued errors into exceptions and not let it issue an E_NOTICE. We could change the exception error handler as follow:
function exception_error_handler($severity, $message, $file, $line) {
throw new ErrorException($message, 0, $severity, $file, $line);
}
set_error_handler('exception_error_handler');
try {
unserialize('foo');
} catch(\Exception $e) {
// ... will throw the exception here
}
Today I encountered an issue that was a good example on when one might want to use at least temporarily the # operator.
Long story made short, I found logon info (username and password in plain text) written into the error log trace.
Here a bit more info about this issue.
The logon logic is in a class of it's own, because the system is supposed to offer different logon mechanisms. Due to server migration issues there was an error occurring. That error dumped the entire trace into the error log, including password info! One method expected the username and password as parameters, hence trace wrote everything faithfully into the error log.
The long term fix here is to refactor said class, instead of using username and password as 2 parameters, for example using a single array parameter containing those 2 values (trace will write out Array for the paramater in such cases). There are also other ways of tackling this issue, but that is an entire different issue.
Anyways. Trace messages are helpful, but in this case were outright harmful.
The lesson I learned, as soon as I noticed that trace output: Sometimes suppressing an error message for the time being is an useful stop gap measure to avoid further harm.
In my opinion I didn't think it is a case of bad class design. The error itself was triggered by an PDOException ( timestamp issue moving from MySQL 5.6 to 5.7 ) that just dumped by PHP default everything into the error log.
In general I do not use the # operator for all the reasons explained in other comments, but in this case the error log convinced me to do something quick until the problem was properly fixed.
You do not want to suppress everything, since it slows down your script.
And yes there is a way both in php.ini and within your script to remove errors (but only do this when you are in a live environment and log your errors from php)
<?php
error_reporting(0);
?>
And you can read this for the php.ini version of turning it off.
I have what I think is a valid use-case for error suppression using #.
I have two systems, one running PHP 5.6.something and another running PHP 7.3.something. I want a script which will run properly on both of them, but some stuff didn't exist back in PHP 5.6, so I'm using polyfills like random_compat.
It's always best to use the built-in functions, so I have code that looks like this:
if(function_exists("random_bytes")) {
$bytes = random_bytes(32);
} else {
#include "random_compat/random.php"; // Suppress warnings+errors
if(function_exists("random_bytes")) {
$bytes = random_bytes(32);
} else if(function_exists('openssl_random_pseudo_bytes')) {
$bytes = openssl_random_pseudo_bytes(4);
} else {
// Boooo! We have to generate crappy randomness
$bytes = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',64)),0,32);
}
}
The fallback to the polyfill should never generate any errors or warnings. I'm checking to see that the function exists after attempting to load the polyfill which is all that is necessary. There is even a fallback to the fallback. And a fallback to the fallback to the fallback.
There is no way to avoid a potential error with include (e.g. using file_exists) so the only way to do it is to suppress warnings and check to see if it worked. At least, in this case.
I can think of one case of use, for auto-increment a non existing array key.
<?php
$totalCars = [];
// suppressing error to avoid a getting a warning error
#$totalCars['toyota']++;
var_export($totalCars);
// array (
// 'toyota' => 1,
// )
// not suppressing error will throw a warning
// but still allows to increase the non-existing key value
$totalCars['ford']++;
var_export($totalCars);
// Warning: Undefined array key "ford"
// array (
// 'toyota' => 1,
// 'ford' => 1,
// )
See this example output here: https://onlinephp.io/c/433f0
If you are using a custom error handling function and wanna suppress an error (probably a known error), use this method. The use of '#' is not a good idea in this context as it will not suppress error if error handler is set.
Write 3 functions and call like this.
# supress error for this statement
supress_error_start();
$mail_sent = mail($EmailTo, $Subject, $message,$headers);
supress_error_end(); #Don't forgot to call this to restore error.
function supress_error_start(){
set_error_handler('nothing');
error_reporting(0);
}
function supress_error_end(){
set_error_handler('my_err_handler');
error_reporting('Set this to a value of your choice');
}
function nothing(){ #Empty function
}
function my_err_handler('arguments will come here'){
//Your own error handling routines will come here
}
In my experience I would say generally speaking, error suppress is just another bad practice for future developers and should be avoided as much as possible as it hides complication of error and prevent error logging unlike Exception which can help developers with error snapshot. But answering the original question which say "If so, in what circumstances would you use this?".
I would say one should use it against some legacy codes or library that don't throw exception errors but instead handles bad errors by keep the error variables with it's object(speaking of OOP) or using a global variable for logging error or just printing error all together.
Take for example the mysqli object
new mysqli($this->host, $this->username, $this->password, $this->db);
This code above barely or never throw an exception on failed connection, it only store error in mysqli::errno and mysli::error
For modern day coding the one solution I found was to suppress the ugly error messages (which helps no one especially when on production server where debug mode is off) and instead devs should throw their own exception. Which is consider modern practice and help coders track errors more quickly.
$this->connection = #new mysqli($this->host, $this->username, $this->password, $this->db);
if($this->connection->connect_errno)
throw new mysqli_sql_exception($this->connection->error);
You can notice the use of suppression # symbol to prevent the ugly error display should incase error display was turned on development server.
Also I had to throw my own exception. This way I was able to use # symbol and same time I didn't hide error nor did I just make my own guess of what the error could be.
I will say if used rightly, then it is justifiable.
I use it when trying to load an HTML file for processing as a DOMDocument object. If there are any problems in the HTML... and what website doesn't have at least one... DOMDocument->loadHTMLFile() will throw an error if you don't suppress it with #. This is the only way (perhaps there are better ones) I've ever been successful in creating HTML scrapers in PHP.

PHP Try Catch Buffer

I was working on this book and I found an unexpected situation.
When working in a PHP/HTML hybrid file, the book says, if I use PHP try/catch without the ob buffer thing, and if there's an error somewhere in the middle of the file, the PHP engine won't be able to reach the catch{} line since some output has already been sent to the browser. The book then says this situation could be fixed by using ob_start(), ob_end_clean() and ob_end_flush()
However, when I was playing with the book's sample code, the try/catch worked just fine without the ob buffer stuff. By saying just fine I mean if there's an exception the catch{} line could be reached and executed without a problem.
I used a Linode VPS for testing, the PHP version is 5.3.2. I set up the VPS with some ordinary Linode script.
Why is that? :)
That statement is nonsense. PHP's try..catch works just as you would expect, regardless of output that has or hasn't already been sent to the browser.
Seeing that even the errata to that book contains errors, I'd say it's simply not a very good book and am not surprised at all that it contains wrong statements. Just a very quick glance reveals:
In step 4, the third line of code should read as follows:
if ($_POST && isset($missing) && !empty($missing)) {
No, it should actually read:
if ($_POST && !empty($missing)) {
or
if ($_POST && $missing) {
The author apparently does not understand how to use empty.
Further:
An opening curly brace is missing at the end of line 4 of the code in step 2. It should read:
if (!#include('includes/connection.inc.php')) {
That reeks of bad practices and should be rewritten to:
if (!file_exists('includes/connection.inc.php')) {
or:
require_once 'includes/connection.inc.php';
I'm sure there's more... :)

EINTR error for semop call

I am using the following code fragment in a php script to safely update a shared resource.
$lock_id = sem_get( ftok( 'tmp/this.lock', 'r'));
sem_acquire($lock_id)
//do something
sem_release($lock_id)
When I stress test this code with large number of requests I get an error:
Warning: semop() failed acquiring SYSVSEM_SETVAL for key 0x1e: No space left on device in blahblah.php on line 1293
php sources show the following code for failed acquiring SYSVSEM_SETVAL
while (semop(semid, sop, 3) == -1) {
if (errno != EINTR) {
php3_error(E_WARNING, "semop() failed acquiring SYSVSEM_SETVAL for key 0x%x: %s", key, strerror(errno));
break;
}
}
which means semop fails with EINTR. man page reveals that the semop() system call was interrupted by a signal.
My question is can I safely ignore this error and retry sem_acquire?
Edit: I have misunderstood this problem, Pl see the clarification I have posted below.
raj
I wouldn't ignore the ENOSPC (you're getting something other than EINTR, as the code shows). You may end up in a busy loop waiting for a resource that you have earlier exhausted. If you're out of some space somewhere, you want to make sure that you deal with that issue. ENOSPC generally means you are out of...something.
A couple of random ideas:
I am not an expert on the PHP implementation, but I'd try to avoid calling sem_get() each time you want the semaphore. Store the handle instead. It may be that some resource is associated with each call to sem_get, and that is where you're running out of space.
I'd make sure to check your error returns on sem_get(). It's a code snippet, but if you were to fail to get the sema4, you would get inconsistent results when trying to sem_op() it (perhaps EINTR makes sense)
After posting this question I noticed that I misread the code as errno == EINTR and jumped into conclusion. So as bog has pointed out, the error is ENOSPC and not EINTR. After some digging I located the reason for ENOSPC. The number of undo buffers were getting exhausted. I have increased the number of semmnu and now the code is running with out issues. I have used semmni*semmsl as the value of semmnu

Categories