Open themroc5 opened 7 years ago
Have you tried with code from master?
related to #10583
Encountered this problem as well. Did you find out what the reason was for the malformed session data?
When I try to open the session file in an editor I get the warning that the file contains some invalid characters and that it is not an UTF-8 content.
__flash|a:0:{}processes|a:1:{s:32:"682a64bf68f73e16ce8691f2a56c796b";a:2:{s:11:"processConf";O:39:"integration\models\ProcessConfiguration":13:{s:9:"productId";s:1:"1";s:8:"language";s:5:"en-US";s:9:"returnUrl";s:70:"http://integration.c4-application-template.localhost/site/dummy-target";s:8:"padColor";s:3:"red";s:12:"returnTarget";s:5:"_self";s:8:"referrer";s:52:"http://integration.c4-application-template.localhost";s:9:"templates";N;s:13:"blankTemplate";N;s:23:"\00yii\base\Model\00_errors";a:0:{}s:27:"\00yii\base\Model\00_validators";N;s:25:"\00yii\base\Model\00_scenario";s:27:"\00yii\base\Component\00_events";s:30:"\00yii\base\Component\00_behaviors";}s:10:"workspaces";}}
I have put an object (class derived from class Yii Model) into the session and as it seems that namespace declarations causing troubles (first and last backspace is suffixed with "00"). I'm wondering if I have done anything wrong when putting the object to the session (array). It was just a normal assignment, also the Model is quite regular.
(Putting the object into the session is probably not best practise or needs some further considerations. I have solved my problem with just storing $model->attributes
into session and then re-creating the object with new ProcessConfiguration(Yii::$app->session['processConf'])
)
In my case the session file was also deleted. Another session_start()
then just created the file again, but just with the __flash entry, so the actual data was lost.
PHP 7.0.19, Yii 2.0.11.2, Fedora
The exception is only suppressed if YII_DEBUG is not true. To me that is not the main issue, the main issue is that: i can confirm this, that storing object instances extending AR in an array within session, throws this exception when serializing it.
Yii 2.0.15.1, PHP 7.2.10-0ubuntu0.18.04.1
I managed to track down this to what it seems a bug in yii\base\Model
, which is triggered when your try to serialize a model with rules()
returning anonymous functions (e.g. in when
config), and you validate the model prior serialization.
This still applies to 2.0.16.
Given
class TestModel extends \yii\base\Model
{
public $attr;
public function rules()
{
return [['attr', 'required', 'when' => function() { return true; }]];
}
}
$model = new TestModel();
Then everything is fine If you do:
var_dump(unserialize(serialize($model));
But you get an error in this case:
$model->validate();
var_dump(unserialize(serialize($model));
PHP error is Serialization of 'Closure' is not allowed
. This is the same you get when you try to store the (serialized) model in the session (check your web server logs for that).
Apparently this is caused by validators being cached in $model->_validators
-- and PHP choking when trying to serialize the object if those validators contain anonymous functions.
$_validators
method-static inside getValidators()
(that's the only place it is used anyway).__sleep()
method to yii\base\Model
that remove $_validators
from the set of attributes to serialize. This might be tricky due to interactions with properties, behaviours, etc.IMHO, 2 is the simplest one.
rules()
. Move your logic to a method and use [$this, 'methodName']
as callback.getValidators()
in your model. Original implementation only checks for the validator cache in $_validators
, setting it up when empty. So you can simply do:public function getValidators()
{
return $this->createValidators();
}
Is it not solved? Still having problems using when
in validators. I'm using version 2.0.27
I managed to track down this to what it seems a bug in
yii\base\Model
, which is triggered when your try to serialize a model withrules()
returning anonymous functions (e.g. inwhen
config), and you validate the model prior serialization.This still applies to 2.0.16.
How to replicate
Given
class TestModel extends \yii\base\Model { public $attr; public function rules() { return [['attr', 'required', 'when' => function() { return true; }]]; } } $model = new TestModel();
Then everything is fine If you do:
var_dump(unserialize(serialize($model));
But you get an error in this case:
$model->validate(); var_dump(unserialize(serialize($model));
PHP error is
Serialization of 'Closure' is not allowed
. This is the same you get when you try to store the (serialized) model in the session (check your web server logs for that).Apparently this is caused by validators being cached in
$model->_validators
-- and PHP choking when trying to serialize the object if those validators contain anonymous functions.Suggested fixes
- Stop caching validation rules, because they usually contain anonymous functions.
- Make
$_validators
method-static insidegetValidators()
(that's the only place it is used anyway).- Add a
__sleep()
method toyii\base\Model
that remove$_validators
from the set of attributes to serialize. This might be tricky due to interactions with properties, behaviours, etc.IMHO, 2 is the simplest one.
Workarounds
- Do not use anonymous function in
rules()
. Move your logic to a method and use[$this, 'methodName']
as callback.- Override
getValidators()
in your model. Original implementation only checks for the validator cache in$_validators
, setting it up when empty. So you can simply do:public function getValidators() { return $this->createValidators(); }
@bianchi issue status suggests that it is not.
What steps will reproduce the problem?
Replace a running session file content with this one. This content might/propably is wrong already. But this is not the point here. Try to stay logged in.
What is the expected result?
yii\web\Session::open()
and in particular@session_start()
should somehow recognize if the following exception gets thrown:session_start(): Unexpected end of serialized data
. We actually don't know why the session data is malformed and we debugged quite some time to realize that this is the issue. The@session_start()
error suppression works against this. The function actually runs successful since$this->getIsActive()
returns true. However, the next session upkeep trial fails due to the missing identity id parameter in the session and the user has to login again.What do you get instead?
No exception :)
Additional info