Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP Custom Session Handler Problems (PHP 7.1)

Tags:

php

session

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?

like image 688
SpacePhoenix Avatar asked Jan 13 '18 23:01

SpacePhoenix


People also ask

What does $Session do in PHP?

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.

What is PHP session_start () and Session_destroy () function?

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.

What is Gc_maxlifetime?

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).

How many sessions can PHP handle?

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.


1 Answers

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

like image 159
SpacePhoenix Avatar answered Oct 03 '22 15:10

SpacePhoenix