I've just migrated from PHP 7.0 to PHP 7.1 (fresh/clean install of the current version of WAMP) on a computer and it seems to have broken something in the custom session handler that's supposed to save the session to the database instead of using the file system.
The custom hander class is:
class db_session_handler implements SessionHandlerInterface {
public function __construct($db) {
$this->db = $db;
}
public function open($save_path,$session_name) {
$this->db;
return true;
}
public function close() {
unset($this->db);
return true;
}
public function read($session_id) {
if (!isset($session_id)) {
$session_id='';
}
try {
$sql="
SELECT
sess_data
FROM
ue_user_session
WHERE
sess_id = :sess_id
";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':sess_id', $session_id);
$stmt->execute();
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (count($res) <> 1 ) {
return false;
} else {
return $res[0]['sess_data'];
}
}
catch (PDOException $e) {
error_log('Error reading the session data table in the session reading method.',3,"C:\wamp\www\universal_empires\test_log.txt");
error_log(" Query with error: $sql",3,"C:\wamp\www\universal_empires\test_log.txt");
error_log(" Reason given: $e->getMessage()",3,"C:\wamp\www\universal_empires\test_log.txt");
return false;
}
}
public function write($session_id,$session_data) {
try {
$sql="
SELECT
sess_data
FROM
ue_user_session
WHERE
sess_id = :sess_id
";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':sess_id', $session_id);
$stmt->execute();
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
catch (PDOException $e) {
error_log('Error reading the session data table in the session reading method.',3,"C:\wamp\www\universal_empires\test_log.txt");
error_log(" Query with error: $sql",3,"C:\wamp\www\universal_empires\test_log.txt");
error_log(" Reason given: $e->getMessage()",3,"C:\wamp\www\universal_empires\test_log.txt");
return false;
}
$ip = get_ip();
if (isset($_SESSION['user_id'])) {
$user_id = (int) $_SESSION['user_id'];
} else {
$user_id= (int) 0;
}
if (empty($res)) {
if (!isset($_SERVER['REDIRECT_URL'])) {
$location = 'Unknown';
} else {
$location = $_SERVER['REDIRECT_URL'];
}
try {
if (count($res) === 0) {
$sql="
INSERT INTO
ue_user_session
(
sess_id
, user
, start
, last_activity
, location
, ip
, user_agent
, user_host
, user_language
, expires
, sess_data
)
VALUES
(
:sess_id
, 0
, NOW()
, NOW()
, :location
, :ip
, :user_agent
, :user_host
, :user_lang
, DATE_ADD(NOW(), INTERVAL 30 MINUTE)
, :sess_data
)
";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':sess_id', $session_id);
$stmt->bindParam(':location', $location);
$stmt->bindParam(':ip', $ip);
$stmt->bindParam(':user_agent', $_SERVER['HTTP_USER_AGENT']);
$stmt->bindParam(':user_host', $_SERVER['REMOTE_HOST']);
$stmt->bindParam(':user_lang', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
$stmt->bindParam(':sess_data', $session_data);
$stmt->execute();
return true;
}
}
catch (PDOException $e) {
error_log('Error reading the session data table in the session reading method.',3,"C:\wamp\www\universal_empires\test_log.txt");
error_log(" Query with error: $sql",3,"C:\wamp\www\universal_empires\test_log.txt");
error_log(" Reason given: $e->getMessage()",3,"C:\wamp\www\universal_empires\test_log.txt");
return false;
}
} else {
try {
$sql="
UPDATE
ue_user
SET
last_activity = NOW()
WHERE
id = :user_id
";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':user_id', $user_id);
$stmt->execute();
}
catch (PDOException $e) {
error_log('Error reading the session data table in the session reading method.',3,"C:\wamp\www\universal_empires\test_log.txt");
error_log(" Query with error: $sql",3,"C:\wamp\www\universal_empires\test_log.txt");
error_log(" Reason given: $e->getMessage()",3,"C:\wamp\www\universal_empires\test_log.txt");
return false;
}
if (!isset($_SERVER['REDIRECT_URL'])) {
$location = 'Unknown';
} else {
$location = $_SERVER['REDIRECT_URL'];
}
try {
$sql="
UPDATE
ue_user_session
SET
last_activity = NOW()
, expires = DATE_ADD(NOW(), INTERVAL 30 MINUTE)
, location = :location
, ip = :ip
, user_agent = :user_agent
, user_host = :user_host
, user_language = :user_lang
, sess_data = :sess_data
, user = :user_id
WHERE
sess_id = :sess_id
";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':location', $location);
$stmt->bindParam(':ip', $ip);
$stmt->bindParam(':user_agent', $_SERVER['HTTP_USER_AGENT']);
$stmt->bindParam(':user_host', $_SERVER['REMOTE_HOST']);
$stmt->bindParam(':user_lang', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
$stmt->bindParam(':sess_data', $session_data);
$stmt->bindParam(':user_id', $user_id);
$stmt->bindParam(':sess_id', $session_id);
$stmt->execute();
return true;
}
catch (PDOException $e) {
error_log('Error reading the session data table in the session reading method.',3,"C:\wamp\www\universal_empires\test_log.txt");
error_log(" Query with error: $sql",3,"C:\wamp\www\universal_empires\test_log.txt");
error_log(" Reason given: $e->getMessage()",3,"C:\wamp\www\universal_empires\test_log.txt");
return false;
}
}
$this->gc();
}
public function destroy($session_id) {
try {
$sql="
DELETE FROM
ue_user_session
WHERE
sess_id = :sess_id
";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':sess_id', $session_id);
$stmt->execute();
return true;
}
catch (PDOException $e) {
error_log('Error reading the session data table in the session reading method.',3,"C:\wamp\www\universal_empires\test_log.txt");
error_log(" Query with error: $sql",3,"C:\wamp\www\universal_empires\test_log.txt");
error_log(" Reason given: $e->getMessage()",3,"C:\wamp\www\universal_empires\test_log.txt");
return false;
}
}
public function gc($max_lifetime) {
try {
$sql="
DELETE FROM
ue_user_session
WHERE
NOW() > expires
";
$stmt = $this->db->prepare($sql);
$stmt->execute();
return true;
}
catch (PDOException $e) {
error_log('Error reading the session data table in the session reading method.',3,"C:\wamp\www\universal_empires\test_log.txt");
error_log(" Query with error: $sql",3,"C:\wamp\www\universal_empires\test_log.txt");
error_log(" Reason given: $e->getMessage()",3,"C:\wamp\www\universal_empires\test_log.txt");
return false;
}
}
}
It's initilised by:
ini_set('session.use_only_cookies', 1);
$db_session_handler = new db_session_handler($db);
session_set_save_handler($db_session_handler, true);
if (session_start() === false ) {
die('The Session Handler Is Broken!!!!');
}
Reading through the manual page for session_set_save_handler()
I can't spot anything mentioned that might explain the error that I'm getting which is:
Warning: session_start(): Failed to read session data: user (path: c:/wamp/tmp) in C:\wamp\www\universal_empires\libs\bootstrap.php on line 36
Line 36 in that file is the call to session_start()
.
Googling around the only fixes that I can find are specific to a given framework. What I need to know is what's causing session_start()
to fail (from reading about changes to 7.1 session_start()
returns false instead of trying to plod on when something's not right.
My guess is that something has changed in 7.1 where in 7.0 possibly it was allowed to carry on but in 7.1 it's more stricter with whatever the problem is and makes session_start()
return false.
I've emptied the sessions table in the database and have checked where file-based sessions get stored. The only "file-based" session file present is PHPMyAdmin.
Does anyone know what it's falling foul of in PHP 7.1 that it doesn't fall foul of in PHP 7.0?
A session is a way to store information (in variables) to be used across multiple pages. Unlike a cookie, the information is not stored on the users computer.
session_destroy() destroys all of the data associated with the current session. It does not unset any of the global variables associated with the session, or unset the session cookie. To use the session variables again, session_start() has to be called. Note: You do not have to call session_destroy() from usual code.
gc_maxlifetime specifies the number of seconds after which data will be seen as 'garbage' and potentially cleaned up. Garbage collection may occur during session start (depending on session. gc_probability and session. gc_divisor). Defaults to 1440 (24 minutes).
PHP sessions are (by default) file based, so you can have as many of them as can fit on your server's disk. Save this answer. Show activity on this post. No, this exactly means that there can't be more than 30 simultaneous connections.
Culprit has been found. It turns out that session_start() doesn't like the read method of a custom session handler returning false if there's no session in existence. if anyone else gets a similar problem, if you've no session in existence, then the read method needs to return an empty string instead of either false or null.
The solution was found at http://php.net/manual/en/function.session-start.php#120589 i was looking at the the manual page for session_set_save_handler(), not expecting the solution to actually be in the comments section of the session_start() page.
I don't know why the change was made to what the session_start() method expects to get from the read method of a custom session handler
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With