php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #73616 session file read warning when using custom DB session handler
Submitted: 2016-11-27 23:05 UTC Modified: 2016-11-28 05:20 UTC
From: jfoster at cervistech dot com Assigned: yohgaki (profile)
Status: Closed Package: Session related
PHP Version: 7.1.0RC6 OS: Windows 10, 2012, and 2008 r2
Private report: No CVE-ID: None
 [2016-11-27 23:05 UTC] jfoster at cervistech dot com
Description:
------------
When using session_set_save_handler to implement a custom database based session handler, PHP is throwing the following warning on session_start():

PHP Warning:  session_start(): Failed to read session data: user (path: C:\PHP\session\)

The session handler is functioning correctly and reading/writing correctly to the DB, but is throwing the warning when no files are being used for sessions.

This same code has functioned without throwing the warning for every version of PHP since PHP 5.4.  The warning only started occurring in 7.1

Test script:
---------------
$sess = new SessionManager();
session_start();

class SessionManager 
	{  
	var $life_time;   
	#function SessionManager()
	function __construct() 
		{
		// Read the maxlifetime setting from PHP
	   	$this->life_time = get_cfg_var("session.gc_maxlifetime");      
		// Register this object as the session handler
		session_set_save_handler( 
			array($this, "_open"), 
	        array($this, "_close"),
	        array($this, "_read"),
	        array($this, "_write"),
	        array($this, "_destroy"),
	        array($this, "_gc")
			);  
		}
		
	function _open() 
		{
     	return true;
   		}  
	
	function _close() 
		{
      	return true;
   		}    
		
	function _read($id) 
		{
		//code to read session data from db based on $id
   		}   
		
	function _write($id, $data) 
		{ 
		//code to write/update session data to db based on $id
      	return TRUE;
   		} 
		
	function _destroy($id) 
		{ 
		//code to delete session data from db based on $id
      	return TRUE;
   		}   
		
	function _gc() 
		{
		//code to delete session data from db based on timestamp
	    return true;
    	}
	}

Expected result:
----------------
Session handler to process session without throwing read file warning

Actual result:
--------------
Session handler processes session data from db successfully, but throws file read error.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-11-28 00:14 UTC] yohgaki@php.net
-Status: Open +Status: Not a bug
 [2016-11-28 00:14 UTC] yohgaki@php.net
2 problems in your example code.

1) You should not register save handler as this code. Create handler object, then register it by sesion_set_save_handler() outside of the object. 

2) You should return "string" data from read(). Do you return "string"? It seems this is the reason why you get error from read()

For 1), you may register save handler methods like this, but intended usage is to register "object", not "methods".

Refer this test script for correct usage.
http://lxr.php.net/xref/PHP-7.0/ext/session/tests/session_set_save_handler_class_001.phpt

If you still have problem with modified save handler object, reopen this bug and paste whole save handler code.
 [2016-11-28 02:05 UTC] jfoster at cervistech dot com
-Operating System: +Operating System: Windows 10, 2012, and 2008 r2
 [2016-11-28 02:05 UTC] jfoster at cervistech dot com
Thanks for the input.  I am returning string data from read.  I've tried rewriting the handler with the code below based on the PHP documentation (http://php.net/manual/en/function.session-set-save-handler.php), but still getting the same warning (PHP Warning:  session_start(): Failed to read session data: user (path: C:\PHP\session\)).  Again, everything is working just fine, it is not failing to read the session data.  It can both read and write the session data fine from the DB, but it is returning the error that it cannot read from the file path since update to 7.1, even though it is correctly reading from the database.  Same code has worked fine on PHP 7.0 and every version in the last 6 years.

<?php
class DBSessionHandler implements SessionHandlerInterface
	{  
	public function open($save_path, $session_name) 
		{
     	return true;
   		}   
	
	public function close() 
		{
      	return true;
   		}    
		
	public function read($id) 
		{
		global $cid;
		// Set empty result
		$data = '';      
		// Fetch session data from the selected database  
		$sql = $cid->prepare("SELECT session_data FROM sessions WHERE session_id = ?");
		$sql->bind_param("s", $id);
		$sql->execute() or trigger_error("Session Error: " . mysqli_error($cid). " -- Query: " . $sql);
		$rs = $sql->get_result();	

		$a = mysqli_num_rows($rs);      
		if($a > 0) 
			{
			$row = mysqli_fetch_assoc($rs);
			$data = $row['session_data'];
			}      
		#trigger_error("read - " . $_SERVER['REQUEST_URI']);
		settype($data, "string");
		return $data;
   		}   
		
	public function write($id, $data) 
		{ 
		$time = time() + get_cfg_var("session.gc_maxlifetime");  

		$sql = $cid->prepare("REPLACE INTO sessions (session_id,session_data,expires) VALUES (?, ?, ?)");
		$sql->bind_param("ssi", $id, $data, $time);
		$sql->execute() or trigger_error("Session Error: " . mysqli_error($cid). " -- Query: " . $sql);

		#trigger_error("write - " . $_SERVER['REQUEST_URI']. " - " . mysqli_thread_id($cid));

      	return TRUE;
   		} 
		
	public function destroy($id) 
		{ 
		global $cid;
		
		$sql = $cid->prepare("DELETE FROM sessions WHERE session_id = ?");
		$sql->bind_param("s", $id);
		$sql->execute() or trigger_error("Session Error: " . mysqli_error($cid). " -- Query: " . $sql);

      	return TRUE;
   		}   
		
	public function gc($maxlifetime) 
		{
		// Garbage Collection
		global $cid;
		
	    $sql = 'DELETE FROM sessions WHERE expires < UNIX_TIMESTAMP();';      
		mysqli_query($cid, $sql) or trigger_error("Session Error: " . mysqli_error($cid). " -- Query: " . $sql);      
		// Always return TRUE

	    return true;
    	}
	}

$handler = new DBSessionHandler();
session_set_save_handler($handler, true);

session_start();
?>
 [2016-11-28 02:53 UTC] yohgaki@php.net
-Status: Not a bug +Status: Re-Opened -Assigned To: +Assigned To: yohgaki
 [2016-11-28 03:04 UTC] yohgaki@php.net
-Status: Re-Opened +Status: Feedback
 [2016-11-28 03:04 UTC] yohgaki@php.net
Do you get read() error always or on occasion?
Could you check content of $data?

	public function read($id) 
		{
		global $cid;
		// Set empty result
		$data = '';      
		// Fetch session data from the selected database  
		$sql = $cid->prepare("SELECT session_data FROM sessions WHERE session_id = ?");
		$sql->bind_param("s", $id);
		$sql->execute() or trigger_error("Session Error: " . mysqli_error($cid). " -- Query: " . $sql);
		$rs = $sql->get_result();	

		$a = mysqli_num_rows($rs);      
		if($a > 0) 
			{
			$row = mysqli_fetch_assoc($rs);
			$data = $row['session_data'];
			}      
		#trigger_error("read - " . $_SERVER['REQUEST_URI']);
		if (!is_string($data)) var_dump($data); // <-- Something like this
		return (string)$data;
   		}
 [2016-11-28 05:20 UTC] jfoster at cervistech dot com
-Status: Feedback +Status: Closed
 [2016-11-28 05:20 UTC] jfoster at cervistech dot com
Looks like you were spot on.  Occasionally, the result from the DB would not return any data.  I configured the read function to return a blank string instead of NULL on empty results and it cleared up the error.  Strange this warning never fired on previous versions.

Thanks so much for your help.  Sorry to waste your time.
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sun Nov 19 01:31:42 2017 UTC