We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Memcached Session Adapter JSON

How can I store JSON data in Memcached using the adapter given in the Incubator. I have been trying so many ways but cannot get it to work. These are the functions I have extended:

 public function read($sessionId){
        $tmp = $_SESSION;    
        $_SESSION = json_decode($this->_getMemcacheInstance()->get($this->_getSessionId($sessionId), $this->getOption('lifetime')),true);
        if(isset($_SESSION) && !empty($_SESSION) && $_SESSION != null){
            $new_data = session_encode();
            $_SESSION = $tmp;
            return $new_data;
        } else{
            return "";
        }
    }

    /**
     * Writes data into session object
     *
     * @param string $sessionId
     * @param string $data
     */
    public function write($sessionId, $data) {

        $tmp = $_SESSION;
        session_decode($data);
        $serializedData = json_encode($_SESSION);
        $_SESSION = $tmp;

        $this->_getMemcacheInstance()->save($this->_getSessionId($sessionId), $serializedData, $this->getOption('lifetime'));
    }

The function write does not write the correct data to Memcached.

This is the data I want to have in Memcached:

{"auth": {"id": 1, "name": "gasimzada"}} but I get:

a:1:{s:4:"auth";a:2:{s:2:"id";s:1:"1";s:4:"name";s:9:"gasimzada";}}

What am I doing wrong?

Thanks, Gasim



98.9k

You can just set the memcached adapter by setting:

session.save_handler = memcached 
session.save_path = "localhost:11211" 

up in your php.ini



8.7k

But that wouldn't fix serializing being JSON.



98.9k

Are you going to access the SESSION data from a different language than PHP?



8.7k

Yes. Javascript (NodeJS).



98.9k

Sorry, I have no experience with Node.



8.7k

Is there an advantage of declaring memcache as php configuration rather than as phalcon adapter?



10

+1 for ability to store session data in JSON.

Did anyone get phalcon sessions stored as json working? Interestingly I can get it to work outside of phalcon easily, my current hypothesis is that there is call(s) to session_decode and/or session_encode somewhere I can't find, possibly in phalcon's C code



8.7k

I had the exact same problem. However, there is nothing related to session_encode/decode. There needs to be something else causing the issue. The result I get when I use session data is empty array...

I have got it working!! More complicated than first thought - full disclosure with couchbase not memcache, but it claims to be drop in compatible so should work :)

problem 1 - session is saved in the wrong format. Our cache was using functions to perform extra serialization, \Phalcon\Cache\Frontend\Data::beforeStore and afterRetrieve a quick custom class solved that

namespace PhalconX\Cache\Frontend;

class SessionData extends \Phalcon\Cache\Frontend\Data
{
    public function afterRetrieve($data){
        return $data;
    }

    public function beforeStore($data){
        return $data;
    }
}

and on the cache adapter

    public function write($sessionId, $data){
        session_decode($data);
        $serializedData = json_encode($_SESSION);
        $this->_instance()->save($this->_getSessionId($sessionId), $serializedData, $this->getOption('lifetime'));
    }

The read was tricky, because the OP code gave me the warning that session_encode() couldn't use an non existent session, even after setting to $_SESSION. Couldn't figure out a way to access the session serialization directly, To get around this I needed to use another session_serializer, the project msgpack https://github.com/msgpack/msgpack-php seems to be virtually the only game in town.

\ini_set('session.serialize_handler', 'msgpack');

then in the read

    public function read($sessionId){
        $data =  $this->_instance()->get($this->_getSessionId($sessionId), $this->getOption('lifetime'));
        if(!empty($data)){
            $data = json_decode($data, true);
            return \msgpack_pack($data);
        }
        return '';
    }

this is because the read is expected to return a string in the encoded format.

Now theoretically you should just be able to use the msgpack serializer as is, and there are various versions for node, but I couldn't figure that out in my timescales.

Hope that helps :-)



8.7k
edited Mar '14

Great post but I want to mention one thing:

I think it would be better to use /Phalcon/Cache/Frontend/Json to encode/decode the cache data. According to cphalcon,

function beforeStore($data) {
   return json_encode($data);
}

function afterRetrieve($data) {
   return json_decode($data);
}

So, the code will be:

  public function write($sessionId, $data){
        session_decode($data);
        $this->_instance()->save($this->_getSessionId($sessionId), $_SESSION, $this->getOption('lifetime'));
    }

    public function read($sessionId){
        $data =  $this->_instance()->get($this->_getSessionId($sessionId), $this->getOption('lifetime'));
        if(!empty($data)){
            return \msgpack_pack($data);
        }
        return '';
    }

Also, in PHP 5.5.4, there is a new php_serialize handler (https://www.php.net/manual/en/session.configuration.php#ini.session.serialize-handler) introduced:

php_serialize uses plain serialize/unserialize function internally and does not have limitations that php and php_binary have

So, it is possible to use the serialize/unserialize functions; however, I have failed to get it to work. I will update this forum as soon as I find a suitable answer :)

Thank you for the guide!

UPDATE: Fixed the typo that was supposed to be PHP 5.5.4

Of course, you're right! using the beforeStore and afterRetrieve nicer :) probably how they were meant to be used! lol

Can I be so bold as to correct your typo though, I believe the php_serialize handler is new in 5.5.4 not 5.4. Though either way I am not sure that is best route for us, the json seems to be the language agnostic format of choice these days; what benefits can you see? Am I missing something?



8.7k

I don't understand what the question is about. Are you asking about JSON? Additionally, with increasing usage of Javascript on both client and server side, its an easy way to transfer data between "platforms"; since all languages have a stable implementation of JSON encoding and decoding. Its just my point of view though :D

Slight misunderstanding, I worded my post badly! I get the benefits of JSON, I am not so sure on the benefits of the php_serialize handler, does that allow you to specify JSON format? I was under the impression it would just use serialize() thanks :)



8.7k

From what I understand, php_serialize is just the serialize/unserialize functions used in the php itself. As you said, you can't use a non existent session with session_encode, so you used msgpack to serialize/pack the array. But with PHP 5.5.4, you do not need to use additional module like msgpack; you can just write the read function as:

public function read($sessionId){
    $data =  $this->_instance()->get($this->_getSessionId($sessionId), $this->getOption('lifetime'));
    if(!empty($data)){
        return \serialize($data);
    }
    return '';
}

ah! of course, thanks :)