yiisoft / yii2

Yii 2: The Fast, Secure and Professional PHP Framework
http://www.yiiframework.com
BSD 3-Clause "New" or "Revised" License
14.24k stars 6.9k forks source link

error saving sessions #9438

Closed spiritdead closed 7 years ago

spiritdead commented 9 years ago

hi all, im using the new version of the yii2 2.0.6 but i have this problem

i get this Error

[16-Aug-2015 19:18:46 UTC] PHP Fatal error: Uncaught exception 'yii\base\ErrorException' with message 'Unknown: Failed to write session data (user). Please verify that the current setting of session.save_path is correct (/tmp)' in Unknown:0 Stack trace:

0 [internal function]: yii\base\ErrorHandler->handleError(2, 'Unknown: Failed...', 'Unknown', 0, Array)

1 {main}

thrown in Unknown on line 0

and is because i use this configuration

'session' => [
            'class' => 'yii\web\DbSession',
            'readCallback' => function ($fields) {
                    return [
                        'expireDate' => Yii::$app->formatter->asDate($fields['expire']),
                    ];
                },
            'writeCallback' => function ($session) {
                    return [
                        'user_id' => Yii::$app->user->id,
                        'ip' => $_SERVER['REMOTE_ADDR'],
                        'is_trusted' => $session->get('is_trusted', false),
                        'controllerCurrent' => Yii::$app->requestedAction->controller->id,
                        'actionCurrent' => Yii::$app->requestedAction->id,
                        'pageCurrent' => Yii::$app->id,
                        'is_guest' => Yii::$app->user->isGuest
                    ];
                }
        ]

in the common.php

in the localhost work Perfectly but in the remote i get the error

any have idea how can solve this ?

cebe commented 9 years ago

Please verify that the current setting of session.save_path is correct (/tmp)'

looks like a server configuration issue. Please make sure your server is configured correctly. If you still think there is a yii issue here, please give more details about where.

spiritdead commented 9 years ago

@cebe i know but why yii2 cant implement session_save_path('folder'); for this cases ? and define the config in the config.php ?

and yes is the server im trying contact the support

cebe commented 9 years ago

as far as I see you are using DbSession, so how is session_save_path involved here?

spiritdead commented 9 years ago
'session' => [
            'class' => 'yii\web\DbSession',
            'readCallback' => function ($fields) {
                    return [
                        'expireDate' => Yii::$app->formatter->asDate($fields['expire']),
                    ];
                },
            'writeCallback' => function ($session) {
                    return [
                        'user_id' => Yii::$app->user->id,
                        'ip' => $_SERVER['REMOTE_ADDR'],
                        'is_trusted' => $session->get('is_trusted', false),
                        'controllerCurrent' => Yii::$app->requestedAction->controller->id,
                        'actionCurrent' => Yii::$app->requestedAction->id,
                        'pageCurrent' => Yii::$app->id,
                        'is_guest' => Yii::$app->user->isGuest
                    ];
                }
        ],

when i use write and read callbacks, this save the session file in the /temp and in my localhost work good, but in this remote i get the error and cant log-in, in this case is true i need call the datacenter, but if yii2 can provide the parameter for change this folder i think this will be a good solution

the session_save_path('folder'); is a method php for change the folder

spiritdead commented 9 years ago

@cebe thx for open this, if can provide the option for define a custom path for save the session in the common\config.php etc a additional param like $sessionPath etc in the hosting is /home/user/temp/ and the php when you try get the path get /temp/ u.u and of course error

cebe commented 9 years ago

the actual issue here is, that the DbSession class should never try to store a session file somewhere on the disk. I reopened this primarily as a bug report.

spiritdead commented 9 years ago

that will be true :S i tryed too, change 2 time the path in the web/index.php

[16-Aug-2015 21:46:18 UTC] PHP Fatal error: Uncaught exception 'yii\base\ErrorException' with message 'Unknown: Failed to write session data (user). Please verify that the current setting of session.save_path is correct (/home/bluegerc/temp/)' in Unknown:0 Stack trace:

0 [internal function]: yii\base\ErrorHandler->handleError(2, 'Unknown: Failed...', 'Unknown', 0, Array)

1 {main}

thrown in Unknown on line 0

[16-Aug-2015 21:47:40 UTC] PHP Fatal error: Uncaught exception 'yii\base\ErrorException' with message 'Unknown: Failed to write session data (user). Please verify that the current setting of session.save_path is correct (/home/bluegerc/public_html/temp/)' in Unknown:0 Stack trace:

0 [internal function]: yii\base\ErrorHandler->handleError(2, 'Unknown: Failed...', 'Unknown', 0, Array)

1 {main}

thrown in Unknown on line 0

spiritdead commented 9 years ago

@cebe a question i will need wait the 2.0.7 for use this ? :/

cebe commented 9 years ago

there is not even a fix for it so I can not tell you when it will be fixed.

spiritdead commented 9 years ago

i think the problem is in the yii\web\session the base class of the dbsession

spiritdead commented 9 years ago

@samdark i hosted this in a remote server, and in the logs i receive this error, and i cant login, when i comment the session configuration in the common config.php this work again. Is true why dbsession write in the disk a file session? like this "sess_1isgea6dp79tn8e0vpi1o8m5h5" i can see this in my /tmp folder in XAMPP(localhost)

fcaldarelli commented 9 years ago

I've solved putting

'is_guest' => (\Yii::$app->user->getIdentity(false) == null)

Otherwise calling \Yii::$app->user->isGuest I also get that error

spiritdead commented 9 years ago

@FabrizioCaldarelli the problem is, this class create a file in the server, and in webservers i get errors :/

fcaldarelli commented 9 years ago

What class are you talking about?

I refer to this configuration:

'session' => [
            'class' => 'yii\web\DbSession',
            'readCallback' => function ($fields) {
                    return [
                        'expireDate' => Yii::$app->formatter->asDate($fields['expire']),
                    ];
                },
            'writeCallback' => function ($session) {
                    return [
                        'user_id' => Yii::$app->user->id,
                        'ip' => $_SERVER['REMOTE_ADDR'],
                        'is_trusted' => $session->get('is_trusted', false),
                        'controllerCurrent' => Yii::$app->requestedAction->controller->id,
                        'actionCurrent' => Yii::$app->requestedAction->id,
                        'pageCurrent' => Yii::$app->id,
                        'is_guest' => (\Yii::$app->user->getIdentity(false) == null)
                    ];
                }
        ]
spiritdead commented 8 years ago

@FabrizioCaldarelli the class DbSessions @cebe any have idea how fix this ?

andrewnester commented 8 years ago

Hi @spiritdead Could you please provide all content of your config file? I am trying to reproduce your error

spiritdead commented 8 years ago

@andrewnester yeah is this

<?php

return [
    'language' => 'es-ES',
    'name' => 'Proyect Cat',
    'timeZone' => 'Europe/Berlin',
    'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
    'modules' => [
        'gridview' => [
            'class' => '\kartik\grid\Module'
        ]
    ],
    'components' => [
        'cache' => [
            'class' => 'yii\caching\FileCache',
        ],
        'slimApi' =>[
            'class' => 'common\components\SlimApi',
            'apiKey' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
            'userID' => 'xxxx'
        ],
        'session' => [
            'class' => 'yii\web\DbSession',
            'readCallback' => function ($fields) {
                    return [
                        'expireDate' => Yii::$app->formatter->asDate($fields['expire']),
                    ];
                },
            'writeCallback' => function ($session) {
                    return [
                        'user_id' => Yii::$app->user->id,
                        'ip' => $_SERVER['REMOTE_ADDR'],
                        'is_trusted' => $session->get('is_trusted', false),
                        'controllerCurrent' => Yii::$app->requestedAction->controller->id,
                        'actionCurrent' => Yii::$app->requestedAction->id,
                        'pageCurrent' => Yii::$app->id,
                        'is_guest' => Yii::$app->user->isGuest
                    ];
                }
        ],
        'log' => [
            'traceLevel' => YII_DEBUG ? 3 : 0,
            'targets' => [
                [
                    'class' => 'yii\log\FileTarget',
                    'levels' => ['error', 'warning'],
                ],
                'db'=>[
                    'class' => 'yii\log\DbTarget',
                    'levels' => ['error', 'warning'],
                    'except'=>['yii\web\HttpException', 'yii\i18n\I18N'],
                    'prefix'=>function(){
                            $url = !Yii::$app->request->isConsoleRequest ? Yii::$app->request->getUrl() : null;
                            $user = Yii::$app->has('user', true) ? Yii::$app->user : null;
                            $userName = $user ? $user->identity->username : '-';
                            return sprintf('[%s][%s][%s]',$userName, Yii::$app->id, $url);
                        },
                    'logVars'=>[],
                    'logTable'=>'log'
                ]
            ],
        ],
        'urlManager'=>[
            //'urlFormat'=>'path',
            'enablePrettyUrl' => true,
            'showScriptName' => false,
            'rules'=>[
                '<controller:[a-z\-]+>/<id:\d+>'=>'<controller>/view',
                '<controller:[a-z\-]+>/<action:[a-z\-]+>/<id:\d+>'=>'<controller>/<action>',
                '<controller:[a-z\-]+>/<action:[a-z\-]+>'=>'<controller>/<action>',
            ],
        ],
        'urlManagerUpload' => [
            'class' => 'yii\web\urlManager',
            'baseUrl' => '/uploads/',
            'enablePrettyUrl' => true,
            'showScriptName' => false,
        ],
        'urlManagerBase' => [
            'class' => 'yii\web\urlManager',
            'baseUrl' => '/',
            'enablePrettyUrl' => true,
            'showScriptName' => false,
        ],
        'urlManagerFrontToBack' => [
            'class' => 'yii\web\urlManager',
            'baseUrl' => '/backend',
            'enablePrettyUrl' => true,
            'showScriptName' => false,
        ],
        'urlManagerBackToFront' => [
            'class' => 'yii\web\urlManager',
            'baseUrl' => '/frontend',
            'enablePrettyUrl' => true,
            'showScriptName' => false,
        ]
    ],
];
andrewnester commented 8 years ago

Can't reproduce it. @FabrizioCaldarelli @spiritdead guys, could you please provide details how are you reproducing this error?

spiritdead commented 8 years ago

@andrewnester is in shared servers, in the localhost work good, but the problem is, if i use dbsession why this write a file in the temp (session file) ?

andrewnester commented 8 years ago

@spiritdead are you sure you have session table in your database on your hosted server? and could you please attach your Yii log file, it will help to find out what's wrong, because I can reproduce error neither on localhost or on hosted server.

spiritdead commented 8 years ago

@andrewnester i added the migration of the table session of course, but this report is a little old and i use now other server :/

joetwostep commented 8 years ago

I was having this same error too for the longest time and couldn't figure out why. After spending hours tracing the code with the debugger I discovered the problem for me was in my writeCallback() function, like you inside that function I had several calls to $session->get('param_name').

The problem is, the writeCallback function is called upon sessionClose(), and by the time it gets to my call to session->get() the session is already closed. Inside the session->get() function the first thing it does is open the session if it is not already open, so my session was getting reopened after it had been closed. Then when the script ends and the memory is freed up from my session object, session_destroy() is called and that's when the error is triggered: "'Unknown: Failed to write session data (user). Please verify that the current setting of session.save_path is correct (/tmp)'", I believe because the session was still open?

See if commenting out your line: 'is_trusted' => $session->get('is_trusted', false),

fixes your problem. I had to rework my read and write callback functions and once I eliminated the session->get calls everything worked OK. I don't know if this is a bug or if its a result of me using the session class incorrectly, but I had to store the session params I needed in separate variables in memory and access them there in order to get the writeCallback to work. Maybe not the ideal solution but at least now it works. Hope it helps you.

spiritdead commented 8 years ago

@joetwostep @samdark that will be true, but then we got to the session variable in the function ?

if we get this error getting a property of the session, why receive this var in the parameters of the function...

'writeCallback' => function ($session) {

we should receive variable from a secondary memory location that does not affect the session in general not?

samdark commented 8 years ago

secondary memory location?

spiritdead commented 8 years ago

if this is the problem

The problem is, the writeCallback function is called upon sessionClose(), and by the time it gets to my call to session->get() the session is already closed. Inside the session->get() function the first thing it does is open the session if it is not already open, so my session was getting reopened after it had been closed. Then when the script ends and the memory is freed up from my session object, session_destroy() is called and that's when the error is triggered: "'Unknown: Failed to write session data (user). Please verify that the current setting of session.save_path is correct (/tmp)'", I believe because the session was still open?

why the writecallback give access to the parameter $session ?

samdark commented 8 years ago

@joetwostep are you sure session_write_close() calls write callback with session already closed? Which PHP version are you using?

samdark commented 8 years ago

Normally it should be write and then close.

AlexGx commented 8 years ago

Have same issue:

FastCGI sent in stderr: "PHP message: PHP Fatal error: Uncaught yii\base\ErrorException: Unknown: Failed to write session data (user). Please verify that the current setting of session.save_path is correct (/var/lib/php/sessions) in Unknown:0

Any ideas (fixes)?

klimov-paul commented 8 years ago

http://stackoverflow.com/questions/5104065/php-session-handling-errors

cebe commented 7 years ago

'class' => 'yii\web\DbSession',

@klimov-paul it should not even try to write to a file.

maz0717 commented 7 years ago

This error happens when the writeCallback is trying to access something that has not been created yet. Such as the Yii::$app->user. This normally happens because of an uncaught error that causes the app to error out before the accessed object is setup.

To reproduce the error, set write callback to:

'writeCallback' => function($session) { return [ 'user_id' => \Yii::$app->user->id ]; }

And create a controller action that executes the following: ArrayHelper('string',null,[]);

SilverFire commented 7 years ago

Verified.

I have no idea how to prevent this error. @samdark do you?

samdark commented 7 years ago

No immediate idea. Need to dig into it more.

alexxxst commented 7 years ago

Any news here?

samdark commented 7 years ago

Not yet. Do you have additional info that may help solving it?

alexxxst commented 7 years ago

Nothing but tracelog.

yii\base\ErrorException: session_regenerate_id(): Session write failed. ID: user (path: /var/lib/php/session) in /var/www/basic/vendor/yiisoft/yii2/web/Session.php:295
Stack trace:
#0 [internal function]: yii\base\ErrorHandler->handleError(2, 'session_regener...', '/var/www/basic/...', 295, Array)
#1 /var/www/basic/vendor/yiisoft/yii2/web/Session.php(295): session_regenerate_id(false)
#2 /var/www/basic/vendor/yiisoft/yii2/web/DbSession.php(103): yii\web\Session->regenerateID(false)
#3 /var/www/basic/vendor/yiisoft/yii2/web/User.php(618): yii\web\DbSession->regenerateID(true)
#4 /var/www/basic/vendor/yiisoft/yii2/web/User.php(292): yii\web\User->switchIdentity(Object(app\models\User), 2592000)
#5 /var/www/basic/vendor/yiisoft/yii2/web/User.php(674): yii\web\User->loginByCookie()
#6 /var/www/basic/vendor/yiisoft/yii2/web/User.php(188): yii\web\User->renewAuthStatus()
#7 /var/www/basic/vendor/yiisoft/yii2/web/User.php(333): yii\web\User->getIdentity()
#8 /var/www/basic/vendor/yiisoft/yii2/base/Component.php(132): yii\web\User->getIsGuest()
#9 /var/www/panel3/panel/controllers/UserController.php(67): yii\base\Component->__get('isGuest')
#10 /var/www/basic/vendor/yiisoft/yii2/base/Controller.php(154): app\controllers\UserController->beforeAction(Object(yii\base\InlineAction))
#11 /var/www/basic/vendor/yiisoft/yii2/base/Module.php(523): yii\base\Controller->runAction('login', Array)
#12 /var/www/basic/vendor/yiisoft/yii2/web/Application.php(102): yii\base\Module->runAction('user/login', Array)
#13 /var/www/basic/vendor/yiisoft/yii2/base/Application.php(380): yii\web\Application->handleRequest(Object(yii\web\Request))
#14 /var/www/panel3/panel/web/index.php(22): yii\base\Application->run()
#15 {main}
cebe commented 7 years ago

Nothing but tracelog.

I would not call that nothing, there is a lot of useful information in here.

DbSession is calling session_regenerate_id() which is then trying to write files for whatever reason.

cebe commented 7 years ago

@alexxxst could you provide your PHP config regarding sessions, i.e. all settings that begin with session. and the PHP version you are using?

alexxxst commented 7 years ago

There are nothing specific.

bash-4.1$ php -i | grep session
igbinary session support => yes
session
session.auto_start => Off => Off
session.cache_expire => 180 => 180
session.cache_limiter => nocache => nocache
session.cookie_domain => no value => no value
session.cookie_httponly => Off => Off
session.cookie_lifetime => 0 => 0
session.cookie_path => / => /
session.cookie_secure => Off => Off
session.entropy_file => /dev/urandom => /dev/urandom
session.entropy_length => 32 => 32
session.gc_divisor => 1000 => 1000
session.gc_maxlifetime => 3600 => 3600
session.gc_probability => 1 => 1
session.hash_bits_per_character => 5 => 5
session.hash_function => 0 => 0
session.lazy_write => On => On
session.name => PHPSESSID => PHPSESSID
session.referer_check => no value => no value
session.save_handler => files => files
session.save_path => /var/lib/php/session => /var/lib/php/session
session.serialize_handler => php => php
session.upload_progress.cleanup => On => On
session.upload_progress.enabled => On => On
session.upload_progress.freq => 1% => 1%
session.upload_progress.min_freq => 1 => 1
session.upload_progress.name => PHP_SESSION_UPLOAD_PROGRESS => PHP_SESSION_UPLOAD_PROGRESS
session.upload_progress.prefix => upload_progress_ => upload_progress_
session.use_cookies => On => On
session.use_only_cookies => On => On
session.use_strict_mode => Off => Off
session.use_trans_sid => 0 => 0
bash-4.1$ php -v
PHP 7.0.20 (cli) (built: Jun 13 2017 19:33:52) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.0.20, Copyright (c) 1999-2017, by Zend Technologies
bash-4.1$ ./yii help
This is Yii version 2.0.12.
cebe commented 7 years ago

are you sure the webserver config is the same?

alexxxst commented 7 years ago

Yep, it's the same. Except session.save_handler of course. It is set to "user".

samdark commented 7 years ago

So to reproduce it in basic app. Session component config:

'session' => [
    'class' => 'yii\web\DbSession',
    'writeCallback' => function ($session) {
        return 1; // will cause fail 
    }
],

Then create session table as usual. Then modify your php.ini so default handler errors i.e. add something like session.save_path = "N;/non_existing".

After that login as admin and log out.

samdark commented 7 years ago

This is PHP 7 only issue. 5.6 works fine.

samdark commented 7 years ago

The error displayed is clear and is pointing to writeCallback if using 5.6 but is quite cryptic when using PHP 7. The fix could be made to DbSession::writeSession() so PHP 7 displays error correctly in debug mode:

} catch (\Exception $e) {
    $exception = ErrorHandler::convertExceptionToString($e);
    // its too late to use Yii logging here
    error_log($exception);
    if (YII_DEBUG) {
        Yii::$app->errorHandler->handleException($e); // <----- this
    }

     return false;
}
samdark commented 7 years ago

@alexxxst do you have writeCallback? Do you have anything in PHP logs (not Yii log but PHP one)?

alexxxst commented 7 years ago

Yep, writeCallback returns array with user_id. But nothing special in PHP logs.

samdark commented 7 years ago

Looks like the case I've described in https://github.com/yiisoft/yii2/issues/9438#issuecomment-326141935 Do you have a chance to try the change I've proposed?

ghost commented 7 years ago

I I've solved this problem by overriding close() method in a subclass of DbSession like this: public function close(){} but I don't know have any side effect or not.

samdark commented 7 years ago

@mhd-shf is your session properly written with empty close()?

ghost commented 7 years ago

@samdark Yes, I have no problem with that. maybe this is specific to my project that every thing is ok.