Custom Session Handler With JSON in PHP Destroy Session by Mistake - Hack The Tech - Latest News related to Computer and Technology

Hack The Tech - Latest News related to Computer and Technology

Get Daily Latest News related to Computer and Technology and hack the world.

Monday, August 14, 2023

Custom Session Handler With JSON in PHP Destroy Session by Mistake

I have a task to implement my Custom Session Handler in PHP, where data from each session is saved in a specified directory in JSON file. Here is the code (it's a combination of code from documentation and user's notes from it):

class CustomSessionHandler implements SessionHandlerInterface
{
    //this field contains folder, where all sessions files will be stored
    private string $savePath;

    //according to docs
    public function close(): bool
    {
        return true;
    }

    //delete file of session with specified ID
    public function destroy(string $id): bool
    {
        $sessionPath = $this->savePath . DIRECTORY_SEPARATOR . "sess_" . $id . ".json";
        if (file_exists($sessionPath)) {
            unlink($sessionPath);
        }
        return true;
    }

    //according to docs
    public function gc(int $max_lifetime): int|false
    {
        foreach (glob($this->savePath . DIRECTORY_SEPARATOR . "sess_*" . ".json") as $file) {
            if (filemtime($file) + $max_lifetime < time() && file_exists($file)) {
                unlink($file);
            }
        }
        return true;
    }

    //generally, 'if' doesn't make any sense because save directory in my
    //study project will always exist
    public function open(string $path, string $name): bool
    {
        $this->savePath = $path;
        if (!is_dir($path)) {
            mkdir($path);
        }
        return true;
    }

    //I think the problem is here...
    public function read(string $id): string
    {
        $sessionPath = $this->savePath . DIRECTORY_SEPARATOR . "sess_" . $id . ".json";
        if (!file_exists($sessionPath)) {
            file_put_contents($sessionPath, "");
            chmod($sessionPath, 0777);
        }
        return file_get_contents($sessionPath);
    }

    //create JSON string from serialized session string
    public function write(string $id, string $data): bool
    {
        $rawData = [];
        try {
            $rawData = self::unserialize_php($data);
        } catch (Exception $e) {
            echo $e->getMessage();
        }
        $jsonData = json_encode($rawData);
        return !(file_put_contents($this->savePath . DIRECTORY_SEPARATOR . 'sess_' . $id . ".json", $jsonData) === false);
    }

    /**
     * @throws Exception
     */
    //this code is from comment section from docs and it works fine
    private static function unserialize_php($sessionData): array
    {
        $returnData = [];
        $offset = 0;
        while ($offset < strlen($sessionData)) {
            if (!str_contains(substr($sessionData, $offset), "|")) {
                throw new Exception("invalid data, remaining: " . substr($sessionData, $offset));
            }
            $pos = strpos($sessionData, "|", $offset);
            $num = $pos - $offset;
            $varName = substr($sessionData, $offset, $num);
            $offset += $num + 1;
            $data = unserialize(substr($sessionData, $offset));
            $returnData[$varName] = $data;
            $offset += strlen(serialize($data));
        }
        return $returnData;
    }
}

I create authentication system. In the beginning of file login.php, which is responsible for checking user credentials, such code placed:

$handler = new CustomSessionHandler();
session_set_save_handler($handler);
session_start([
    'save_path' => '/var/www/phpcourse.loc/hometask_3/sessions',
]);

if (isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true) {
    //welcome.php is the page, where user just see 'Hi, {username}' and can logout
    header('Location: welcome.php');
    exit;
}

The problem is that sessions files are created and deleted when it shouldn't happen. Because of this I can't login and I have a warning:

Warning: session_start(): Failed to decode session object. Session has been destroyed in /var/www/phpcourse.loc/hometask_3/login.php on line 12

Next in the code, if user's credentials are correct, $_SESSION variables are set:

if (password_verify($password, $hashed_password)) {
    $handler = new CustomSessionHandler();
    session_set_save_handler($handler);
    session_start([
        'save_path' => '/var/www/phpcourse.loc/hometask_3/sessions',
    ]);

    $_SESSION['logged_in'] = true;
    $_SESSION['id'] = $id;
    $_SESSION['username'] = $username;

    header('Location: welcome.php');
}

If I debug this code and go through each step, here what happens:

  1. On the first download of the login page session file is created completely empty
  2. After pressing LOGIN button session file is getting destroyed just after returning value from read() function of CustomSessionHandler class. It happens in session_start() that is first in code above.
  3. When the code reach second session_start(), when all credentials are correct and next page (welcome.php) is opening, session file is created again and all variables are getting written to it in JSON format.

But when I start session in the beginning of script welcome.php the same way as in file login.php file is getting destroyed again after read(). And I'm again on Login page.

What is going on?



source https://stackoverflow.com/questions/76894813/custom-session-handler-with-json-in-php-destroy-session-by-mistake

No comments:

Post a Comment