When using php redis as a session handler with session locking if there is an error where a lock cannot happen a php notice is thrown and the script continues. Is there a way to configure it for a fatal error and the script NOT process at all?
-
you could use [control structures](https://www.php.net/manual/en/language.control-structures.php)/[conditionals](https://www.php.net/manual/en/control-structures.if.php) to check the session locking, if it fails, `throw new Exception()` – treyBake Feb 03 '20 at 16:40
-
I don't see a way to do this because the locking happens outside of my application via php redis module – Chris Muench Feb 03 '20 at 19:23
-
Aside from editing the package code where the error handling occurs, this may help you: https://stackoverflow.com/questions/51364016/is-there-any-way-to-notice-e-notice-in-php-code – SJacks Sep 21 '20 at 18:36
-
1This is exactly what was I was looking for. Thanks! – Chris Muench Sep 21 '20 at 18:51
2 Answers
Make sure that you follow this documentation statement:
Locking feature is currently only supported for Redis setup with single master instance
If you still have some problems then a quick fix for whole application could be set your own error handler with set_error_handler that takes care for that particular problem. An example handler below that reacts only to using not declared variable. Change the regex pattern so it matches your Redis error msg.
<?php
error_reporting(E_ALL);
$redisNoticeFunction = function($errno, $errstr, $errfile, $errline, array $errcontext) {
// is the error E_NOTICE?
if ($errno === \E_NOTICE) {
// if error was suppressed with the @-operator
if (0 === \error_reporting()) {
// do nothing, continue execution of script
return;
}
// check if notice is about Redis
$pattern = '/.*Undefined variable.*/'; // <== change pattern so it matches notice about Redis
$subject = $errstr;
$status = \preg_match($pattern, $subject);
// if there was a problem with regex
if (false === $status) {
$msg = 'Could not perform preg_math with pattern: ' . $pattern . ' and subject: ' . $subject . \PHP_EOL;
// exit by throwing an exception
throw new \InvalidArgumentException($msg);
}
// if notice was about about Redis
if ($status) {
$error_msg = 'Redis locking problem with notice msg: ' . $errstr;
$error_msg .= ' at ' . $errfile . ':' . $errline . \PHP_EOL;
// signal fatal error
$error_type = \E_USER_ERROR;
\trigger_error ($error_msg, $error_type);
// or throw exception (comment above line with \trigger_error())
throw new \RuntimeException($error_msg);
}
// the notice was not related to the Redis
// echo its message and continue script
echo $errstr . \PHP_EOL;
return;
}
// the error was not the E_NOTICE
// do other error handling if needed
// or just end the script
die;
};
set_error_handler($redisNoticeFunction);
echo @ $notDeclared; // does not end script
echo $notDeclared; // end script or throws an exception
the last line
echo $notDeclared; // end script or throws an exception
ends script with info:
Fatal error: Redis locking problem with notice msg: Undefined variable: notDeclared at /tmp/index.php:59
set_error_handler should be used at the beginning of your php script (perfectly inside a common file that is required everywhere like a bootstrap.php)
The downside of using your own error handler is that if you work with a framework or other wrapping code it might already set its own error handler that provides some useful features like debugging or maybe even that error handler is essential to that framework error handling, logging etc.
If you wish to restore to original error handler (that default from PHP or the one that was set before your own) use restore_error_handler

- 5,644
- 6
- 44
- 71
In case anyone wants to know the exact code for turning session_lock notice into fatal error; here it is. (I couldn't have done it without the other answer, but this is exactly what I used)
function redisNoticeFunction($errno, $errstr, $errfile, $errline, array $errcontext)
{
// is the error E_NOTICE?
if ($errno === E_NOTICE)
{
// if error was suppressed with the @-operator
if (0 === error_reporting())
{
// do nothing, continue execution of script
return;
}
// if notice was about about Redis locking
if ($errstr == 'session_start(): Acquire of session lock was not successful')
{
$error_msg = 'Redis locking problem with notice msg: ' . $errstr;
$error_msg .= ' at ' . $errfile . ':' . $errline . \PHP_EOL;
// signal fatal error
$error_type = E_USER_ERROR;
trigger_error ($error_msg, $error_type);
}
return;
}
}
$current_error_reporting = error_reporting();
error_reporting(E_ALL);
set_error_handler('redisNoticeFunction');
session_start();
//Use regular error handling if session_start() does not end in a lock
restore_error_handler();
error_reporting($current_error_reporting);

- 17,444
- 70
- 209
- 362