Laravel 会话突然被破坏

Posted

技术标签:

【中文标题】Laravel 会话突然被破坏【英文标题】:Laravel session gets suddenly destroyed 【发布时间】:2014-07-02 10:00:13 【问题描述】:

我有一个处理体育赛事注册的多页表单。我们有很多用户(约占所有用户的 15%,与平台/浏览器无关)遇到以下错误:

表单包含以下页面:

    开始 详情 团队 类 批次 商品 调查 完成

在每一页上,我们检查会话是否包含前一页的数据。如果没有,我们将他重定向回来。

遇到的问题是第 4 步输入数据后 15% 组被重定向回来。

这可能意味着会话/数据在第 4 步的存储功能中被损坏,但我不知道如何/为什么/在哪里。但如果这是问题所在,那么只有 15% 的用户会遇到问题是没有意义的。此外,经过数小时的尝试,我们无法重现此错误。

我知道会话被完全刷新/销毁,因为用户被级联返回:showBatchPage 将用户恢复为 showClassPage,showClassPage 恢复为 showMembersPage,showMembersPage 恢复为 showStartPage 等。我们还会记录这些恢复。

我的代码如下所示:

<?php

public function saveClassPage($slug)

    $rules = [];
    $messages = [];
    $memberClasses = [];    

    // prepare solo error messages    
    foreach (Session::get('entry.members') as $id => $member)
    
        if (!isset($member['group'])) 
            $rules["class.$id"] = 'required';
            $messages["class.$id.required"] = "Please select a class for member $member['firstname'] $member['lastname']";
        
    

    // prepare team error messages
    foreach (Session::get('entry.groups', []) as $id => $group)
    
        $rules["group.$id"] = 'required';
        $messages["group.$id.required"] = "Please select a class for group $group['name']";
    

    $validator = Validator::make(Input::all(), $rules, $messages);

    // loop trough solo members and set class
    foreach (Input::get('class', []) as $i => $class)
    
        Session::put("entry.members.$i.class", $class);

        // if there is only one class in the batch, assign it
        $memberClasses[$i] = ClassModel::find($class);
        if ($memberClasses[$i]->batches()->count() < 2) 
            Session::put("entry.members.$i.batch", $memberClasses[$i]->batches()->first()->id);
        
    

    // loop trough teams and set class
    foreach (Input::get('group', []) as $i => $class)
    
        foreach (Session::get("entry.groups.$i.members", []) as $id)
        
            Session::put("entry.members.$id.class", $class);

            // if there is only one class in the batch, assign it
            $memberClasses[$id] = ClassModel::find($class);
            if ($memberClasses[$id]->batches()->count() < 2) 
                Session::put("entry.members.$i.batch", $memberClasses[$id]->batches()->first()->id);
            
        
        Session::put("entry.groups.$i.class", $class);
    

    $allClassesAreEmpty = true;
    foreach ($memberClasses as $class)
    
        if ($class->batches()->count() > 1) 
            $allClassesAreEmpty = false;
            break;
        
    

    if ($validator->passes()) 
        // skip batch page if there is only one batch
        if ($allClassesAreEmpty) 
            return Redirect::action('EventEntryController@showExtrasPage', array('slug' => $slug));
         else 
            return Redirect::action('EventEntryController@showBatchPage', array('slug' => $slug));
        
    

    return Redirect::action('EventEntryController@showClassPage', array('slug' => $slug))->withErrors($validator);


public function showBatchPage($slug)

    $firstMember = head( Session::get('entry.members', []) );

    if (!isset($firstMember['class'])) 
        Log::info('showBatchPage@revertToClass');

        return Redirect::action('EventEntryController@showClassPage', array('slug' => $slug));
    

    // other stuff (preparing view data etc.)

    return View::make('entry/batch', $viewData);

我的应用程序/config/session.php

<?php

return array(

    /*
    |--------------------------------------------------------------------------
    | Default Session Driver
    |--------------------------------------------------------------------------
    |
    | This option controls the default session "driver" that will be used on
    | requests. By default, we will use the lightweight native driver but
    | you may specify any of the other wonderful drivers provided here.
    |
    | Supported: "file", "cookie", "database", "apc",
    |            "memcached", "redis", "array"
    |
    */

    'driver' => 'file',

    /*
    |--------------------------------------------------------------------------
    | Session Lifetime
    |--------------------------------------------------------------------------
    |
    | Here you may specify the number of minutes that you wish the session
    | to be allowed to remain idle before it expires. If you want them
    | to immediately expire on the browser closing, set that option.
    |
    */

    'lifetime' => 120,

    'expire_on_close' => false,

    /*
    |--------------------------------------------------------------------------
    | Session File Location
    |--------------------------------------------------------------------------
    |
    | When using the native session driver, we need a location where session
    | files may be stored. A default has been set for you but a different
    | location may be specified. This is only needed for file sessions.
    |
    */

    'files' => storage_path().'/sessions',

    /*
    |--------------------------------------------------------------------------
    | Session Database Connection
    |--------------------------------------------------------------------------
    |
    | When using the "database" or "redis" session drivers, you may specify a
    | connection that should be used to manage these sessions. This should
    | correspond to a connection in your database configuration options.
    |
    */

    'connection' => null,

    /*
    |--------------------------------------------------------------------------
    | Session Database Table
    |--------------------------------------------------------------------------
    |
    | When using the "database" session driver, you may specify the table we
    | should use to manage the sessions. Of course, a sensible default is
    | provided for you; however, you are free to change this as needed.
    |
    */

    'table' => 'sessions',

    /*
    |--------------------------------------------------------------------------
    | Session Sweeping Lottery
    |--------------------------------------------------------------------------
    |
    | Some session drivers must manually sweep their storage location to get
    | rid of old sessions from storage. Here are the chances that it will
    | happen on a given request. By default, the odds are 2 out of 100.
    |
    */

    'lottery' => array(2, 100),

    /*
    |--------------------------------------------------------------------------
    | Session Cookie Name
    |--------------------------------------------------------------------------
    |
    | Here you may change the name of the cookie used to identify a session
    | instance by ID. The name specified here will get used every time a
    | new session cookie is created by the framework for every driver.
    |
    */

    'cookie' => 'laravel_session',

    /*
    |--------------------------------------------------------------------------
    | Session Cookie Path
    |--------------------------------------------------------------------------
    |
    | The session cookie path determines the path for which the cookie will
    | be regarded as available. Typically, this will be the root path of
    | your application but you are free to change this when necessary.
    |
    */

    'path' => '/',

    /*
    |--------------------------------------------------------------------------
    | Session Cookie Domain
    |--------------------------------------------------------------------------
    |
    | Here you may change the domain of the cookie used to identify a session
    | in your application. This will determine which domains the cookie is
    | available to in your application. A sensible default has been set.
    |
    */

    'domain' => null,

    /*
    |--------------------------------------------------------------------------
    | HTTPS Only Cookies
    |--------------------------------------------------------------------------
    |
    | By setting this option to true, session cookies will only be sent back
    | to the server if the browser has a HTTPS connection. This will keep
    | the cookie from being sent to you if it can not be done securely.
    |
    */

    'secure' => false,

);

【问题讨论】:

你能发布你所有的 app/config/session.php 代码吗? 您是否尝试过切换会话类型?也许是数据库,或者安装 memcache? 不,还没有。你认为这有什么关系?由于问题发生在同一个位置,而且并非总是如此(如果我完全复制受影响的用户操作,我完全没有问题),对我来说,它不希望成为会话提供者的问题。 它是关于排除事情的。如果问题发生在数据库会话中 - 那么您知道它不是您的文件会话。但目前你还不确定——这可能是最简单的改变选择。 哦 - 还有一件事 - 将你的 cookie 更改为不带下划线的东西 - 一些较旧的 IE 浏览器不喜欢带下划线的 cookie。 【参考方案1】:

假设您正在使用本地盒子(Dev),以避免使用相同的默认 Session Cookie Name 和相同的 domain 与其他 Laravel 应用程序混淆:

    清除所有与您的 Laravel 应用程序使用的域相关的 browser cookies 以进行故障排除。 将您的Session Cookie Name 更改为更独特的(如果需要,不要下划线)。

如果您使用默认会话驱动程序file,请确保您对文件夹app/storage 具有写入权限。

【讨论】:

已经试过了,但是没有用。将 cookie 名称更改为唯一名称,后来更改为 db 驱动程序以排除文件系统错误。仍然没有发现问题,并且仍然无法重现它。

以上是关于Laravel 会话突然被破坏的主要内容,如果未能解决你的问题,请参考以下文章

重定向页面时突然会话数据被破坏

Laravel - 在登录时销毁现有会话

当从 laravel 控制器调用 html 时,猫头鹰轮播被破坏

Laravel 会话数据被重写

Laravel 4.1 会话变量被随机遗忘

会话销毁或关闭浏览器选项卡或关闭浏览器后,使用Laravel 5.2执行注销