Welcome Guest, Not a member yet? Register   Sign In
CI_Session_redis_driver contains 2 abstract methods
#1

On huge loads we are getting the below error on creation session on Redis server.

Severity: Error --> Class CI_Session_redis_driver contains 1 abstract methods and must therefore be declared abstract or implement the remaining methods (SessionHandlerInterface::open, SessionHandlerInterface::close) /var/www/html/testproject/system/libraries/Session/drivers/Session_redis_driver.php 49

My Session_redis_driver.php as below.( I've already tried by replacing new codeigniter 3.1.4 system folder). My platform is XAMPP windows 7.1.1 and PHP Version 7.1.1

Tried with Apache restart as well.  

class CI_Session_redis_driver extends CI_Session_driver implements SessionHandlerInterface {

/**
* phpRedis instance
*
* @var resource
*/
protected $_redis;

/**
* Key prefix
*
* @var string
*/
protected $_key_prefix = 'ci_session:';

/**
* Lock key
*
* @var string
*/
protected $_lock_key;

/**
* Key exists flag
*
* @var bool
*/
protected $_key_exists = FALSE;

// ------------------------------------------------------------------------

/**
* Class constructor
*
* @param array $params Configuration parameters
* @return void
*/
public function __construct(&$params)
{
parent::__construct($params);

if (empty($this->_config['save_path']))
{
log_message('error', 'Session: No Redis save path configured.');
}
elseif (preg_match('#(?:tcp://)?([^:?]+)(?:\Sad\d+))?(\?.+)?#', $this->_config['save_path'], $matches))
{
isset($matches[3]) OR $matches[3] = ''; // Just to avoid undefined index notices below
$this->_config['save_path'] = array(
'host' => $matches[1],
'port' => empty($matches[2]) ? NULL : $matches[2],
'password' => preg_match('#auth=([^\s&]+)#', $matches[3], $match) ? $match[1] : NULL,
'database' => preg_match('#database=(\d+)#', $matches[3], $match) ? (int) $match[1] : NULL,
'timeout' => preg_match('#timeout=(\d+\.\d+)#', $matches[3], $match) ? (float) $match[1] : NULL
);

preg_match('#prefix=([^\s&]+)#', $matches[3], $match) && $this->_key_prefix = $match[1];
}
else
{
log_message('error', 'Session: Invalid Redis save path format: '.$this->_config['save_path']);
}

if ($this->_config['match_ip'] === TRUE)
{
$this->_key_prefix .= $_SERVER['REMOTE_ADDR'].':';
}
}

// ------------------------------------------------------------------------

/**
* Open
*
* Sanitizes save_path and initializes connection.
*
* @param string $save_path Server path
* @param string $name Session cookie name, unused
* @return bool
*/
public function open($save_path, $name)
{
if (empty($this->_config['save_path']))
{
return $this->_fail();
}

$redis = new Redis();
if ( ! $redis->connect($this->_config['save_path']['host'], $this->_config['save_path']['port'], $this->_config['save_path']['timeout']))
{
log_message('error', 'Session: Unable to connect to Redis with the configured settings.');
}
elseif (isset($this->_config['save_path']['password']) && ! $redis->auth($this->_config['save_path']['password']))
{
log_message('error', 'Session: Unable to authenticate to Redis instance.');
}
elseif (isset($this->_config['save_path']['database']) && ! $redis->select($this->_config['save_path']['database']))
{
log_message('error', 'Session: Unable to select Redis database with index '.$this->_config['save_path']['database']);
}
else
{
$this->_redis = $redis;
return $this->_success;
}

return $this->_fail();
}

// ------------------------------------------------------------------------

/**
* Read
*
* Reads session data and acquires a lock
*
* @param string $session_id Session ID
* @return string Serialized session data
*/
public function read($session_id)
{
if (isset($this->_redis) && $this->_get_lock($session_id))
{
// Needed by write() to detect session_regenerate_id() calls
$this->_session_id = $session_id;

$session_data = $this->_redis->get($this->_key_prefix.$session_id);

is_string($session_data)
? $this->_key_exists = TRUE
: $session_data = '';

$this->_fingerprint = md5($session_data);
return $session_data;
}

return $this->_fail();
}

// ------------------------------------------------------------------------

/**
* Write
*
* Writes (create / update) session data
*
* @param string $session_id Session ID
* @param string $session_data Serialized session data
* @return bool
*/
public function write($session_id, $session_data)
{
if ( ! isset($this->_redis, $this->_lock_key))
{
return $this->_fail();
}
// Was the ID regenerated?
elseif ($session_id !== $this->_session_id)
{
if ( ! $this->_release_lock() OR ! $this->_get_lock($session_id))
{
return $this->_fail();
}

$this->_key_exists = FALSE;
$this->_session_id = $session_id;
}

$this->_redis->setTimeout($this->_lock_key, 300);
if ($this->_fingerprint !== ($fingerprint = md5($session_data)) OR $this->_key_exists === FALSE)
{
if ($this->_redis->set($this->_key_prefix.$session_id, $session_data, $this->_config['expiration']))
{
$this->_fingerprint = $fingerprint;
$this->_key_exists = TRUE;
return $this->_success;
}

return $this->_fail();
}

return ($this->_redis->setTimeout($this->_key_prefix.$session_id, $this->_config['expiration']))
? $this->_success
: $this->_fail();
}

// ------------------------------------------------------------------------

/**
* Close
*
* Releases locks and closes connection.
*
* @return bool
*/
public function close()
{
if (isset($this->_redis))
{
try {
if ($this->_redis->ping() === '+PONG')
{
$this->_release_lock();
if ($this->_redis->close() === FALSE)
{
return $this->_fail();
}
}
}
catch (RedisException $e)
{
log_message('error', 'Session: Got RedisException on close(): '.$e->getMessage());
}

$this->_redis = NULL;
return $this->_success;
}

return $this->_success;
}

// ------------------------------------------------------------------------

/**
* Destroy
*
* Destroys the current session.
*
* @param string $session_id Session ID
* @return bool
*/
public function destroy($session_id)
{
if (isset($this->_redis, $this->_lock_key))
{
if (($result = $this->_redis->delete($this->_key_prefix.$session_id)) !== 1)
{
log_message('debug', 'Session: Redis::delete() expected to return 1, got '.var_export($result, TRUE).' instead.');
}

$this->_cookie_destroy();
return $this->_success;
}

return $this->_fail();
}

// ------------------------------------------------------------------------

/**
* Garbage Collector
*
* Deletes expired sessions
*
* @param int $maxlifetime Maximum lifetime of sessions
* @return bool
*/
public function gc($maxlifetime)
{
// Not necessary, Redis takes care of that.
return $this->_success;
}

// ------------------------------------------------------------------------

/**
* Get lock
*
* Acquires an (emulated) lock.
*
* @param string $session_id Session ID
* @return bool
*/
protected function _get_lock($session_id)
{
// PHP 7 reuses the SessionHandler object on regeneration,
// so we need to check here if the lock key is for the
// correct session ID.
if ($this->_lock_key === $this->_key_prefix.$session_id.':lock')
{
return $this->_redis->setTimeout($this->_lock_key, 300);
}

// 30 attempts to obtain a lock, in case another request already has it
$lock_key = $this->_key_prefix.$session_id.':lock';
$attempt = 0;
do
{
if (($ttl = $this->_redis->ttl($lock_key)) > 0)
{
sleep(1);
continue;
}

if ( ! $this->_redis->setex($lock_key, 300, time()))
{
log_message('error', 'Session: Error while trying to obtain lock for '.$this->_key_prefix.$session_id);
return FALSE;
}

$this->_lock_key = $lock_key;
break;
}
while (++$attempt < 30);

if ($attempt === 30)
{
log_message('error', 'Session: Unable to obtain lock for '.$this->_key_prefix.$session_id.' after 30 attempts, aborting.');
return FALSE;
}
elseif ($ttl === -1)
{
log_message('debug', 'Session: Lock for '.$this->_key_prefix.$session_id.' had no TTL, overriding.');
}

$this->_lock = TRUE;
return TRUE;
}

// ------------------------------------------------------------------------

/**
* Release lock
*
* Releases a previously acquired lock
*
* @return bool
*/
protected function _release_lock()
{
if (isset($this->_redis, $this->_lock_key) && $this->_lock)
{
if ( ! $this->_redis->delete($this->_lock_key))
{
log_message('error', 'Session: Error while trying to free lock for '.$this->_lock_key);
return FALSE;
}

$this->_lock_key = NULL;
$this->_lock = FALSE;
}

return TRUE;
}

}
Reply
#2

That's an OPCache bug. The only known work-around is to turn that Off.
Reply
#3

We are Not using OPcahe. We have cross verified our php.ini there is no "opchache" related extensions.
along with the above some time we are also getting below error

Session: Unable to obtain lock for ci_session:59c978074f37af2a6ae72648fc804f67641474fc after 30 attempts, aborting.

Severity: Warning --> session_start(): Failed to read session data: user (path: tcp://XXX.XXX.100.36:6379?auth=abcd@123) /var/www/html/testproject/system/libraries/Session/Session.php 143

We are using Redis as a session driver. but it is an intermittent error.
Reply




Theme © iAndrew 2016 - Forum software by © MyBB