我有一个页面,我在这个页面的开头我要进行长时间的轮询
session_start();
session_write_close();
Run Code Online (Sandbox Code Playgroud)
因为:
为防止并发写入,任何时候只有一个脚本可以在会话上运行
因此,如果我不这样做并且长轮询正在运行,则用户将无法加载另一个页面.
因此,可以从此轮询页面访问我在会话中的数据,但在我的脚本中的某些时候,我要将会话保存回服务器,因为我对其进行了一些更改.
这样做的方法是什么?
这将是非常好的,这将是一种做某事的方式
session_write_open();
//do stuff
session_write_close();
Run Code Online (Sandbox Code Playgroud)
但是session_write_open()不存在!
谢谢
Arm*_*ier 10
以前的解决方案将创建会话ID和cookie ...我不会按原样使用它:
每次调用session_start()时都会创建会话.如果您想避免多个cookie,请编写更好的代码.多个session_start()特别是同一个脚本中的相同名称似乎是一个非常糟糕的主意.
见这里:https://bugs.php.net/bug.php?id = 38104
我现在也在寻找解决方案,我找不到一个.我同意那些说这是"虫子"的人.你应该可以重新打开一个php会话,但正如你所说的session_write_open()那样......
我在上面的帖子中找到了一个解决方法.它涉及在处理请求后发送一个手动指定会话ID的cookie的头.幸运的是,我正在使用自制的前置控制器,这样可以让任何子控制器都不会自己发送数据.简而言之,它完全适用于我的情况.要使用它,您可能只需要使用ob_start()和ob_get_clean().这是神奇的界限:
if (SID) header('Set-Cookie: '.SID.'; path=/', true);
Run Code Online (Sandbox Code Playgroud)
编辑:看下面CMCDragonkai的答案,看起来不错!?
这里的其他答案提出了很好的解决方案.正如@Jon所提到的,诀窍是在你想要进行更改之前再次调用session_start().然后,当您完成更改后,再次调用session_write_close().
正如@Armel Larcier所提到的,问题在于PHP尝试生成新的标头并且可能会生成警告(例如,如果您已经将非标头数据写入客户端).当然,你可以简单地在session_start()前加上"@"(@session_start()),但是有更好的方法.
由@VolkerK提供的另一个Stack Overflow问题揭示了最佳答案:
session_start(); // first session_start
...
session_write_close();
...
ini_set('session.use_only_cookies', false);
ini_set('session.use_cookies', false);
//ini_set('session.use_trans_sid', false); //May be necessary in some situations
ini_set('session.cache_limiter', null);
session_start(); // second session_start
Run Code Online (Sandbox Code Playgroud)
这可以防止PHP再次尝试发送标头.您甚至可以编写一个辅助函数来包装ini_set()函数,以使其更方便:
function session_reopen() {
ini_set('session.use_only_cookies', false);
ini_set('session.use_cookies', false);
//ini_set('session.use_trans_sid', false); //May be necessary in some situations
ini_set('session.cache_limiter', null);
session_start(); //Reopen the (previously closed) session for writing.
}
Run Code Online (Sandbox Code Playgroud)
原始相关的SO问题/答案:https://stackoverflow.com/a/12315542/114558
这里的所有答案似乎都在说使用会话方法,而这些方法显然不打算使用...即session_start()多次调用。
PHP网站提供了一个示例SessionHandlerInterface实现,该实现将与现有会话一样工作,但不锁定文件。仅仅实现它们的示例接口即可解决我的锁定问题,以允许在同一会话上进行并发连接,而不会限制我向会话添加var的能力。为了防止某些竞争情况,由于应用程序的会话不是完全无状态的,因此我确实必须设法在不关闭会话的情况下保存会话中的请求,以便重要的更改可以在更改后立即保存,而不太重要的会话var可以保存在请求结束时。请参阅以下示例以了解用法:
Session::start();
echo("<pre>Vars Stored in Session Were:\n");print_r($_SESSION);echo("</pre>");
$_SESSION['one'] = 'one';
$_SESSION['two'] = 'two';
//save won't close session and subsequent request will show 'three'
Session::save();
$_SESSION['three'] = 'three';
Run Code Online (Sandbox Code Playgroud)
如果您更换Session::start()同session_start()和Session::save()同session_write_close(),你会发现,后续请求将永远不会打印出的第三个变量...它将会丢失。但是,使用SessionHandler(如下),不会丢失任何数据。
OOP实现需要PHP 5.4+。但是,您可以在旧版本的PHP中提供单独的回调方法。参见docs。
namespace {
class Session implements SessionHandlerInterface {
/** @var Session */
private static $_instance;
private $savePath;
public static function start() {
if( empty(self::$_instance) ) {
self::$_instance = new self();
session_set_save_handler(self::$_instance,true);
session_start();
}
}
public static function save() {
if( empty(self::$_instance) ) {
throw new \Exception("You cannot save a session before starting the session");
}
self::$_instance->write(session_id(),session_encode());
}
public function open($savePath, $sessionName) {
$this->savePath = $savePath;
if (!is_dir($this->savePath)) {
mkdir($this->savePath, 0777);
}
return true;
}
public function close() {
return true;
}
public function read($id) {
return (string)@file_get_contents("$this->savePath/sess_$id");
}
public function write($id, $data) {
return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
}
public function destroy($id) {
$file = "$this->savePath/sess_$id";
if (file_exists($file)) {
unlink($file);
}
return true;
}
public function gc($maxlifetime) {
foreach (glob("$this->savePath/sess_*") as $file) {
if (filemtime($file) + $maxlifetime < time() && file_exists($file)) {
unlink($file);
}
}
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
21791 次 |
| 最近记录: |