Skip to content

Instantly share code, notes, and snippets.

@yohgaki
Last active January 30, 2020 20:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yohgaki/432579e535ae97856a1227e4d47d0e2e to your computer and use it in GitHub Desktop.
Save yohgaki/432579e535ae97856a1227e4d47d0e2e to your computer and use it in GitHub Desktop.
How to implement user defined serializer by PHP 7.1 or less
<?php
// This code is to explain why current API is not good for user defined serializer.
// https://wiki.php.net/rfc/user_defined_session_serializer
ob_start();
ini_set('session.serialize_handler', 'php_serialize');
ini_set('session.save_handler', 'files');
ini_set('session.save_path', '/tmp');
ini_set('session.use_strict_mode', 0);
//Note: Use of save handler for user defined serializer requires needless
// two PHP serialize()/unserialize() calls for loading/saving session data.
class MyHandler extends SessionHandler {
// This is stupid function becase
// it converts JSON serialized data string to array,
// then it converts the array to PHP serilize()ed string,
// then session serializer converts PHP serialized()ed string to array, _again_.
// This is what this code does.
function read($session_id) {
$json = parent::read($session_id);
$php_serialized = serialize(json_decode($json));
return $php_serialized;
}
// Stupid code for the reason above.
function write($session_id, $session_data) {
$json = json_encode(unserialize($session_data));
return parent::write($session_id, $json);
}
}
// Current PHP forces users to write stupid code.
session_set_save_handler(new MyHandler);
session_id('SESSIONTEST');
session_start();
$_SESSION['abc']=1234;
session_commit();
session_start();
var_dump($_SESSION);
/* To do the same with user defined serializer RFC
https://wiki.php.net/rfc/user_defined_session_serializer
Following code is required to do the same. This code
is more efficient and precise.
i.e.
Efficient: No stupid array to PHP serializ()ed string, the stirng to array, array
to JSON string converions. There is only "array" to "JSON string" conversion for
saving session data. This code is 25% faster than above code.
Precise: It uses session's submodule structure correctly. It does not requires to
override C written save handler which crated number of problems. This code is much
cleaner than above code.
session_set_serializer(
function ($arr) {
return json_encode($arr);
},
function ($str) {
return $str ? json_decode($str) : [];
}
);
*/
@nolimitdev
Copy link

nolimitdev commented Aug 14, 2018

You do not have to use serialize and unserialize to store JSON in session file. See my solution...

class MyHandler extends SessionHandler {

    function read($session_id) {
        $content = parent::read($session_id);
        if (!empty($content) && ($json_decode = json_decode($content, true)) !== null) {
            $_SESSION = $json_decode;
            return '';
        }

        return $content;
    }

    function write($session_id, $session_data) {
        if (empty($_SESSION) || ($json_encode = json_encode($_SESSION, JSON_UNESCAPED_UNICODE)) === false) {
            $json_encode = '';
        }

        return parent::write($session_id, $json_encode);
    }
}

Advantages of this solution:

  • no overhead using serialize() and unserialize()
  • independent on session.serialize_handler ("php_serialize" is not required because of omitting serialize and unserialize... "php_serialize" is not available before PHP 5.5.4)
  • when using internal "php" (not compatible with serialize and unserialize functions) as session.serialize_handler we can use special characters (| and !) in indexes of $_SESSION
  • deploying this code first time on production will not break existing sessions (thanks to return $content when decoding as JSON fails)

... so I do not thing that something like suggested session_set_save_handler() is needed

@reedzhao
Copy link

You do not have to use serialize and unserialize to store JSON in session file. See my solution...

    function read($session_id) {
        $content = parent::read($session_id);
        if (!empty($content) && ($json_decode = json_decode($content, true)) !== null) {
            $_SESSION = $json_decode;
            return '';
        }
        return $content;
    }
... so I do not thing that something like [suggested session_set_save_handler()](https://github.com/php/php-src/pull/2205) is needed

The problem of your code is, it relies on un-documented behavior of SessionHandler::read().

http://php.net/manual/en/sessionhandler.read.php

Returns an encoded string of the read data. If nothing was read, it must return an empty string. Note this value is returned internally to PHP for processing.

Looking at PHP session source code, it is safe now. But I will not be surprised to see return ''; clears $_SESSION variable in a future version of PHP.

https://github.com/php/php-src/blob/master/ext/session/session.c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment