用户
 找回密码
 入住 CI 中国社区
搜索
查看: 8179|回复: 8
收起左侧

[会话/Cookie] CI中使用flash上传插件时session丢失解决方案

[复制链接]
发表于 2011-12-19 23:11:21 | 显示全部楼层 |阅读模式
本帖最后由 Closer 于 2015-3-20 11:47 编辑

CI中使用flash插件上传,可能是很多人选择的方式,但是随之而来的session丢失问题也着实让人头疼。
下面先上一段网上摘录的解决方案:

I just wanted to extend from my previous discussionabout session information being lost when using SWFupload - an uploaderthat uses Flash as a method of uploading a file via HTTP allowing theuser to see the progress of the upload.
The reason for the new topic is because this issue relates to theFlash Player in specific rather then just SWFupload. This issue is alsorelated to CI because by default it uses Cookies to handle sessioninformation.
I found a great postjust recently about this issue on the SWFupload forum but through Iwould let people on here know about it as well because it will extendto other sites utilising http requests via flash.
Please note this is all just based on my own research.
The Problem - IE
When Flash is used to make a http request to your CI site in IE7 thesession for the logged in user/current session is lost. The reason forthis is because Flash makes the http request with a different UserAgent to IE causing CI to re-issue a new session cookie for Flash.
This looks to be an ok practice but from what I can evaluate Flashuses the IE cookies directory for storage and hence replaces yourcurrent IE session cookie with the new one for Flash.
I thought that making the $config[‘sess_match_useragent’] variableset to false would fix this but it doesn’t. Reason being from what Ican see is that flash doesn’t at first check if there are any currentcookies for it to use for the site and requests a new one from CI.
The Problem - Firefox / others
It seems that there is no problem in Firefox and but there is. Thereason why other browsers (in a Windows environment) don’t see theseproblems is because Flash in these browsers still uses the IE cookies.eg. I log into site with IE and leave it open then open firefox andlogin and then upload via flash I stayed logged in in Firefox but IEhas been logged out.
A possible fix
The first problem to solve is that Flash when uploading doesn’t have asession to give to CI meaning when uploading it’s treated as a new user- not the current user. The way I have worked around this is the usuageof a ‘token’ that is sent as a POST variable (you could use a urisegment) from the first function (where flash is located) to the secondfunction. You could use the session ID but keep in mind that it ischanged every few minutes and will be cleared after the issue of thenew one. This first fix is really dependant on your ownapplication/database structure.
The second fix needed is to stop the overwriting of this cookie andthe best way I have found is to not issue one at all. Personally I donot like the following fix and would like to see some bettersuggestions but it does work for me for in the meantime.
In your sessions class you need to change the following line in the CI_Session function that is run on object construct:
$this->sess_run();
with
if (! stristr($this->CI->input->user_agent(),'shockwave')) {
    $this->sess_run();
}

文章比较简单,我就不翻译了,但是好像文中作者使用的kndbsession类比较老。我当初用的1.7.2的CI,是将
$this->_sess_run();
修改为:
if (! stristr($this->object->input->user_agent(),'shockwave')) {
        $this->_sess_run();
}


flash使用单独的session进程,把php中的session给覆盖掉了,然后后台中取不到php起初设置的session,然后就退出了,所以在使用flash程序中必须解决这个问题,除了在设置刚开始我们修改的session文件外,还需要修改swfupload的初始化配置信息。
<script type="text/javascript">
        var upload1;

        var loadInit = function() {
            upload1 = new SWFUpload({
                // Backend Settings
                upload_url:"<? echo base_url()?>index.php/upload/upload/server/<?php echosession_id(); ?>/<?php echo$this->session->userdata('uid');?>/<?php echo$this->session->userdata('level');?>/<?php echo$this->session->userdata('admin_name');?>",
                post_params: {
                    "PHPSESSID" : "<?php echo session_id(); ?>",
                    "sessionUid":"<?php echo $this->session->userdata('uid');?>",
                    "sessionLevel":"<?php echo $this->session->userdata('level');?>",
                    "sessionName":"<?php echo $this->session->userdata('admin_name');?>"
               },


                // File Upload Settings
                file_size_limit : "102400000",    // 100MB
                file_types : "*.*",
                file_types_description : "All Files",
                file_upload_limit : "100",
                file_queue_limit : "0",

                // Event Handler Settings (all my handlers are in the Handler.js file)
                file_dialog_start_handler : fileDialogStart,
                file_queued_handler : fileQueued,
                file_queue_error_handler : fileQueueError,
                file_dialog_complete_handler : fileDialogComplete,
                upload_start_handler : uploadStart,
                upload_progress_handler : uploadProgress,
                upload_error_handler : uploadError,
                upload_success_handler : uploadSuccess,
                upload_complete_handler : uploadComplete,

                // Button Settings
                button_image_url : "<? echo base_url()?>images/XPButtonUploadText_61x22.png",
                button_placeholder_id : "spanButtonPlaceholder1",
                button_width: 61,
                button_height: 22,
               
                // Flash Settings
                flash_url : "<? echo base_url()?>js/swfupload/swfupload.swf",
               

                custom_settings : {
                    progressTarget : "fsUploadProgress1",
                    cancelButtonId : "btnCancel1"
                },
               
                // 我们可以在此设置是否输出调试信息
                debug: true
            });
        }
        addLoadEvent(loadInit);
    </script>

注意标注紫色背景部分的代码,起初的时候我在upload_url参数中只设置为upload_url: "<? echo base_url()?>index.php/upload/upload/server/,设置post_params为示例中的内容。但是,在控制器中取不到我post过来的值,可能是flash中的某些操作吧post值给覆盖掉了,我也不是很清楚。然后我就尝试了在url中传递保存的session信息。将upload_url参数改为:upload_url:"<? echo base_url()?>index.php/upload/upload/server/<?php echosession_id(); ?>/<?php echo$this->session->userdata('uid');?>/<?php echo$this->session->userdata('level');?>/<?php echo$this->session->userdata('admin_name');?>",然后相应的修改一下控制器的函数:
public function server($sid='',$uid='',$level='',$name='') {
        if($sid!=''&&$uid!=''&&$level!=''&&$name!='') {            
            session_id($sid);//重新生成session
            $this->session->set_userdata('uid',$uid);
            $this->session->set_userdata('level',$level);
            $this->session->set_userdata('admin_name',$name);
            //输入文件大小等安全性检测。。。。。。。
            //如果安全性符合要求,我们开始上传:
            if (!@move_uploaded_file($_FILES[$upload_name]["tmp_name"], $save_path.$file_name)) {
                  $this->HandleError("File could not be saved.");
                  exit(0);
           }//上传结束
           else {
                 $this->HandleError('you have not login!!');//提示尚未登录
           }
}
最后重新登录后台,运行swfupload那部分功能,竟然不退出了,大功告成。


本帖被以下淘专辑推荐:

发表于 2011-12-21 10:08:47 | 显示全部楼层
这个可以有。。。晚上拿你代码去试下效果。。。
发表于 2012-1-5 11:44:25 | 显示全部楼层
是有这么回事,不过也修改配置文件就可以搞定
发表于 2012-1-11 12:48:33 | 显示全部楼层
不错,remark下
发表于 2012-2-6 15:15:09 | 显示全部楼层
PHP复制代码
明白了
复制代码
发表于 2012-10-30 19:52:45 | 显示全部楼层
你好。我遇到一个奇怪的现象:

        public function __construct()
        {
                parent::__construct();
                $a=$this->input->get("SSID");
                //

                        session_id('2a3cbeadc2adf54a46b4ba0c6f599859');
                                //echo '<script>alert("'.$a.'");</script>';
                        $dataa=array(
                                //'id'=>1,
                                //'name'=>'a',
                                'logged_in'=>1
                                );
                        $this->session->set_userdata($dataa);



//echo '<script>alert("a:'.$a.'-'.$this->session->userdata('logged_in').'");</script>';
                if($this->session->userdata('logged_in')!== 1)
                {
                        redirect('login');
                }

这样可以。上传成功后。刷新都OK,不退出到登陆页

这个方案我是查看源码。找到session_id值,写上去的。

但是下面这样就不行。可以上传,但上传成功后一刷新就退出到后台登陆页了。

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class MY_Controller extends CI_Controller{

        public function __construct()
        {
                parent::__construct();
                $a=$this->input->get("SSID");
                //
                if ($a) {
                        session_id($a);
                                //echo '<script>alert("'.$a.'");</script>';
                        $dataa=array(
                                //'id'=>1,
                                //'name'=>'a',
                                'logged_in'=>1
                                );
                        $this->session->set_userdata($dataa);


                }
//echo '<script>alert("a:'.$a.'-'.$this->session->userdata('logged_in').'");</script>';
                if($this->session->userdata('logged_in')!== 1)
                {
                        redirect('login');
                }


这个$a的session值是可以取到的。为什么这样不行呢。能否指点指点。
 楼主| 发表于 2012-10-31 09:16:38 | 显示全部楼层
lawzk 发表于 2012-10-30 19:52
你好。我遇到一个奇怪的现象:

        public function __construct()

$a的值不正确吧
 楼主| 发表于 2012-10-31 09:17:16 | 显示全部楼层
lawzk 发表于 2012-10-30 19:52
你好。我遇到一个奇怪的现象:

        public function __construct()

最终要的是去掉useragent判断,否则都不会成功。
发表于 2013-3-22 11:11:34 | 显示全部楼层
水平有限啊我。。。

本版积分规则