douyi2798 2012-12-07 18:03
浏览 87

PHP:在会话中断会话中存储闭包

Update: solved

I finally figured out my problem (I think). I'm pretty sure the issue is that closures cannot be serialized, which means they cannot be stored in the session. The next issue then is that PHP was not returning a very useful error, and was breaking in an unexpected way, instead of just telling me that I couldn't serialize a closure.


I store my session data in a mysql database. I've had that part of my application in place and working well for quite a while. Today I tried to store a closure (i.e. anonymous function) in the session and that broke my otherwise very well behaved sessions.

My session management is handled by an object, which automatically calls session_write_close() when PHP attempts to destroy the object. I did this so that because otherwise, by the time PHP tries to close the session, my database connection (a mysqli object) has already been destroyed.

I take over the session handling like this:

// set the session save handler
session_set_save_handler(
    array( $this, '_open' ),
    array( $this, '_close' ),
    array( $this, '_read' ),
    array( $this, '_write' ),
    array( $this, '_destroy' ),
    array( $this, '_clean' )
);

which is pretty standard. The part that handles session closing is this:

public function __destruct()
{
    // this variable will only be destroyed when the script is closing
    // at this point it is safe to close the session
    // if we wait for php to close the session then we will
    // have lost the database connection, so we do it now

    session_write_close();
}

// write session data
public function _write( $sid, $data )
{
    // run query to write to database
    $now = NOW;
    $stmt = $this->mysqli->prepare( "REPLACE INTO $this->table (sid,time,data) VALUES (?,?,?)" );
    $stmt->bind_param( 'sis', $sid, $now, $data );

    // execute
    $success = $stmt->execute();

    // close
    $stmt->close();

    // and return
    return $success;
}

// close session store
public function _close()
{
    // close the database connection
    $this->mysqli->close();

    return true;
}

A couple print functions reveal that normally this works just as you would think: the __destruct() function is called, which calls session_write_close(), which is immediately followed up by calls to _write() and _close(). However, the moment I store a closure to the session:

$test = function($name)
{
    print "Hello $name";
};

$_SESSION['test'] = $test;

Everything breaks. __destruct() is called as before, but execution never reaches the _write() or _close() functions. Instead I get these messages:

Warning: session_write_close() [function.session-write-close]: Failed to write session data (user). Please verify that the current setting of session.save_path is correct (/var/lib/php/session) in /var/www/vhosts/ambida.com/httpdocs/includes/core/session_handler.php on line 48

Fatal error: Exception thrown without a stack frame in Unknown on line 0

Which really makes no sense. It looks like it has reverted back to the default session handler, which would of course fail because the tmp file was never opened (since my function took over opening the session). I don't understand why storing a closure in the session would cause such a revert to happen, or why this is breaking in general. Any help would be appreciated.

  • 写回答

1条回答 默认 最新

  • douzongmu2543 2014-07-22 14:17
    关注

    This can now be achieved by using the SuperClosurefrom Jeremy Lindblom. The Package can be found on his github : https://github.com/jeremeamia/super_closure

    评论

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器