Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Insufficient data for unserializing #11

Open
weierophinney opened this issue Dec 31, 2019 · 5 comments
Open

[Question] Insufficient data for unserializing #11

weierophinney opened this issue Dec 31, 2019 · 5 comments

Comments

@weierophinney
Copy link
Member

Hello, maybe someone will be able to help me. I'm trying to save UserEntity (simple getters and setters, 1:1 mapping to db table, no extra methods or logic) into SessionArrayStorage, save handler is db table (session value column - text without length restrictions).
When I just simply put stdClass from getResultRowObject of Zend Authentication into storage, everything works fine. But when I hydrate stdClass into UserEntity, data inside DB value column is truncated:

...{s:7:"storage";O:23:"User\Entity\UserEntity":6:{s:36:" <- session value ends here

and warnings are generated: PHP Warning: Insufficient data for unserializing, Warning: session_start(): Failed to decode session object. Session has been destroyed

I've disabled DB storage and serialized data inside sess_xxx file was complete, getIdentity returned full UserEntity object. So, are there some restrictions when using DB storage and automatic serialization or is it my fault somewhere?


Originally posted by @xorock at zendframework/zend-session#64

@weierophinney
Copy link
Member Author

It certainly sounds like the db is silently truncating the value. What column type? Size? Which database? Accessed over the network or via socket (if the former and MySQL, check max_allowed_packet). Anything unusual about the property names in your entity that the db encoding isn't going to handle?


Originally posted by @kynx at zendframework/zend-session#64 (comment)

@weierophinney
Copy link
Member Author

Database is PostgreSQL 9.4. Session data column: session_data text NOT NULL.
I dumped serialized $userEntity:
\Zend\Debug\Debug::dump(serialize($userEntity));

and got this:

:6:{s:36:"\000User\Entity\UserEntity\000userId";N

What are those zeros? According to google it's NULL char but where they come from? Most probably they are a problem here.

<?php

namespace User\Entity;

class UserEntity
{
    /**
     * @var int
     */
    private $userId;
php -v
PHP 7.0.12 (cli) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.12, Copyright (c) 1999-2016, by Zend Technologies
    with Xdebug v2.4.1, Copyright (c) 2002-2016, by Derick Rethans

Edit: I did some test and use json_encode/decode in Zend\Session\SaveHandler\DbTableGateway. Now session data is correct and I receive full entity. But how can I fix it natively?


Originally posted by @xorock at zendframework/zend-session#64 (comment)

@weierophinney
Copy link
Member Author

Ok. After some more reading everything is clear now.
http://php.net/manual/en/function.serialize.php

Returns a string containing a byte-stream representation of value that can be stored anywhere.

Note that this is a binary string which may include null bytes, and needs to be stored and handled as such. For example, serialize() output should generally be stored in a BLOB field in a database, rather than a CHAR or TEXT field.

I did some test on pure PDO object with PDO::PARAM_LOB and bytea field, serializing/unserializing my entity and full object was stored and returned.

My problem was due to incorrect behaviour of Zend\Session\SaveHandler\DbTableGateway which always converts data to string and it is not possible to store it as PARAM_LOB. Also, I don't know how to pass PARAM_LOB to Zend\Db\TableGateway.

Possible solution: convert data to json (many db engines have appropriate fields) or use bin2hex/pack and store as BLOB. It can not be just serialize/unserialize because it will throw PDOException on bytea field and on text field, it will cut string on first null byte.


Originally posted by @xorock at zendframework/zend-session#64 (comment)

@weierophinney
Copy link
Member Author

I'd never noticed the NULLs around private property names either. But then I tend to avoid serialising objects in session. Personally I would just save the userId rather than the whole object. It'll be easy enough to fetch the entity back from the DB.


Originally posted by @kynx at zendframework/zend-session#64 (comment)

@weierophinney
Copy link
Member Author

Of course there are many workarounds. For now, I have just extended DbTableGateway to work on JSON data. I had some bad experiences with objects and ZF1 Zend_Session, but because I'm rewriting my entire app I wanted to do it right. Fetching back user entity with every request doesn't make sense. More natural would be writing data to the array and hydrate when needed. Still, it's a bug in Db save handler but also in the documentation that suggests the use of a text field.


Originally posted by @xorock at zendframework/zend-session#64 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant