Symfony:自定义会话保存处理程序最大执行时间

Posted

技术标签:

【中文标题】Symfony:自定义会话保存处理程序最大执行时间【英文标题】:Symfony: Custom Session Save Handler Maximum Execution Time 【发布时间】:2015-08-29 21:17:47 【问题描述】:

我正在使用 Symfony 的自定义会话处理程序。当我第一次设置会话但刷新页面时它工作正常。该页面将继续加载,并在 30 秒后(在 php.ini 中定义为max_execution_time)显示错误。为了设置自定义保存处理程序,我在 ratchet 数据库中创建了一个表 sessions。表中结构及数据:

现在页面顶部的脚本如下所示,用于初始化自定义保存处理程序:

<?php 

ini_set('session.auto_start', false);

use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;

    require dirname(__DIR__) . '/vendor/autoload.php';

    $pdo = new \PDO('mysql:host=localhost;dbname=ratchet', 'root', '');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $storage = new NativeSessionStorage(array(), new PdoSessionHandler($pdo)); // Here when PdoSessionHandler class is initialized again on refreshing it locks the page there
    $session = new Session($storage);

    $session->start();

    $username = $session->get('username');

PHP 脚本在第 153 行抛出的错误:

第 153 行是以下方法中的一条语句,它执行并从数据库中读取会话值。

private function doRead($sessionId)

    $this->sessionExpired = false;

    if (self::LOCK_ADVISORY === $this->lockMode) 
        $this->unlockStatements[] = $this->doAdvisoryLock($sessionId);
    

    $selectSql = $this->getSelectSql();
    $selectStmt = $this->pdo->prepare($selectSql);
    $selectStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
    $selectStmt->execute(); // Line 153

框架组件中是否有问题或我遗漏了什么?我已按照文档进行操作。我找不到任何新的或自己添加的内容。

加法

除了在 web 应用程序中初始化会话之外,我还在我的 server 脚本中初始化 symfony 会话,因为它是为每个连接附加相同的会话对象所必需的。注意事项:

    应用程序在第一次尝试时运行良好。 聊天服务器按预期工作。它从不抛出错误。 当我连接websocket服务器的页面刷新时,保持加载状态30秒。然后出现错误。 在其他浏览器中也会发生同样的情况。喜欢它会让连接建立,但是当我刷新时............见上文:D

【问题讨论】:

你在本地机器上测试它吗? @DavidY 是的,ofc。我为什么要把它放到真实的服务器上? 【参考方案1】:

你提到过:

我也在我的服务器脚本中初始化 symfony 会话

这是否也调用new NativeSessionStorage

我认为正在发生的事情是,您实际上创建了两个会话处理程序,但 PHP 只知道一个,因此只关闭数据库连接/解除其中一个的数据库锁定。让我看看能不能解释清楚。每次实例化 NativeSessionStorage 时,该类都会通过 session_set_save_handler 向 php 注册 sessionHandler(在您的情况下为 pdo 会话处理程序),您可以在 NativeSessionStorage 代码 here 中看到。

当 PHP 停止执行时,它会调用 PdoSessionHandler-&gt;close() 方法。但是,由于您有两个实例,而 php 只有一个注册为会话处理程序,所以它的关闭一个而不是另一个。这使数据库保持锁定。根据您的描述,我认为这可能是您的问题。您应该能够通过显式调用 Session-&gt;save() 轻松测试这一点,尝试在您的应用和服务器代码中显式执行此操作,看看您是否不再收到锁定错误。

希望这会有所帮助!

【讨论】:

【参考方案2】:

当 websocket 断开连接时会话是否关闭?如果没有,它会保持会话记录的锁定,并且不允许传入的请求在会话启动之后继续。初始页面加载有效,因为 websocket 会在页面加载完成时获取会话。

【讨论】:

我离开了那个项目。刚开始回来。那你有什么建议?我能理解你说的话。我认为当用户断开连接时,我们需要关闭与数据库的连接。这就是我能从中收集到的全部信息。 在SessionProvider.php中,已经有注释Close 'session' for Connection。我认为开发人员忘了在那里做。 -_-

以上是关于Symfony:自定义会话保存处理程序最大执行时间的主要内容,如果未能解决你的问题,请参考以下文章

Symfony 1.4:表单中 CSRF 的自定义错误消息

向 JavaScript 对象添加一些自定义会话变量

Symfony2 将实体对象序列化为会话

如何在自定义 Spring Security 登录成功处理程序中注入会话 bean

Symfony 5 / 使用 API 编写自定义身份验证总是返回我无效的凭据

利用全局变量$_SESSION和register_shutdown_function自定义会话处理