【问题标题】:How to re-initialize a session in PHP?如何在 PHP 中重新初始化会话?
【发布时间】:2010-09-24 11:02:51
【问题描述】:

我正在尝试将现有支付平台集成到我的网上商店。交易成功后,支付平台向我的应用程序中的 URL 发送请求,交易 ID 包含在查询参数中。

但是,我需要进行一些后处理,例如发送订单确认等。为此,我需要访问用户的会话,因为那里存储了大量与订单相关的信息。为此,我将 session_id 包含在初始请求 XML 中,并在事务完成后执行以下操作:

$sessionId = 'foo'; // the sessionId is succesfully retrieved from the XML response
session_id($sessionId);
session_start();

上面的代码工作正常,但$_SESSION 仍然是空的。我是否忽略了某些东西,或者这根本不可能?

编辑:

感谢您的所有回答。问题还没有解决。如前所述,奇怪的是我可以使用属于下订单的用户的 session_id 成功启动一个新会话。还有其他想法吗?

【问题讨论】:

  • 两个应用程序是否在同一个域中?
  • 感谢您的回复。这些应用程序不在同一个域中。

标签: php session


【解决方案1】:

不是您真正要求的,但是您不需要在将客户发送到支付服务之前将订单保存到数据库中吗?当您收到付款确认时,最好在订单后处理中依赖持久数据。

依赖会话是不可靠的,因为您不知道此确认需要多长时间(通常是即时的,但在极少数情况下会延迟)。

此外,如果您的网络服务器在这段时间内重新启动,将会使您丢失相关数据。

第三个问题是,如果您有一个负载平衡解决方案,带有单独的会话管理(非常常见),那么您将无法保证支付服务器和您的客户端将访问同一个网络服务器(因为粘性通常是来源-基于IP)。

【讨论】:

  • 负载均衡是个好点!我之前做过的另一件事是向提供者发送一个哈希值(只是为了增加安全性,防止用户猜测 url)和订单的 id,然后在回调时使用它来识别订单。
  • 感谢您的回答。您提供了一个有效点,但我当前的订单流程仅将部分订单数据保留在数据库中。在订单过程中,一些特定于状态的数据存储在会话中,因为这为处理失败的付款提供了一种简单的解决方案。
【解决方案2】:

我冒昧地猜测,由于域与会话设置到您尝试读取它的位置不同,因此 php 正在安全地使用它,而不是检索由不同域设置的会话数据。这样做是为了保护安全,以防有人猜测会话 ID 并劫持数据。

解决方法是,假设交换发生在同一个物理磁盘上,将订单数据临时写入序列化(并且可能根据是否跟踪完整的信用卡号进行加密,这完全是另一回事)一旦被接收端读取的文件被立即删除。

本质上,所做的只是复制您试图退出会话的功能,而不会产生烦人的安全副作用。

【讨论】:

【解决方案3】:

非常感谢所有回复。

Smazurov's answer 让我思考并再次忽略了我的 PHP 配置。

PHP 的默认行为是不加密与会话相关的数据,应该使得在从另一个客户端重新启动旧会话后读取会话数据成为可能。但是,我使用Suhosin 来修补和防止一些安全问题。 Suhosin 的默认行为是encrypt session data based on the User Agent,这使得读取其他人的会话变得更加困难。

这也是我的问题的原因;禁用此行为已解决问题。

【讨论】:

    【解决方案4】:

    确保在尝试开始新会话之前关闭当前会话。所以你应该这样做:

    $id = 'abc123';
    session_write_close();
    session_id($id);
    session_start();
    

    【讨论】:

      【解决方案5】:

      很脏,但对我有用:

      告诉支付网关使用

      http://yourdomain.com/callbackurl.php?PHPSESSID=SESSIONIDHERE
      

      如果您设置了某些配置变量 (session.use_trans_sid),PHP 会使用该方法在自身周围传递会话,即使 PHP 被告知不要这样做,它似乎也可以工作。它当然一直对我有用。

      编辑:

      您的问题可能是您将 session.auto_start 设置为 true - 因此会话会在您的代码运行之前使用它生成的任何 ID 自动启动。

      【讨论】:

      • 我还没有尝试过这个解决方案,但是传递会话ID不是问题;这似乎有效。不过,$_SESSION 变量保持为空。
      • 查看有关 session.auto_start 的编辑 .... 停止你的方法工作,但允许我的工作。
      • 感谢您的回复。 session.auto_start 被禁用。不过,请求通过我的前端控制器,在那里会自动启动一个会话。为防止使用此会话,我在设置 ID 并开始新会话之前调用 session_destroy()。打印 session_id() 工作正常。
      • 尝试打开 error_reporting/display_errors - 由于多种原因,在发送标头时第二次调用 session_start 可能会失败。
      • 错误报告已启用并且不显示任何错误。我使用 var_dump($_SESSION);和死(session_id())。第一个是空的,第二个显示正确的 session_id(应该保存数据)
      【解决方案6】:

      如何在另一个 PHP 页面中执行此操作,然后执行 iframe 包含 / 将用户重定向到第二个页面?

      【讨论】:

        【解决方案7】:

        我不确定您的交易和支票之间的确切时间长度;但您的会话 cookie 似乎已过期。默认情况下,会话通常在 45 分钟左右后过期。这是为了释放更多的 uniqid 供 php 使用并防止潜在的会话劫持。

        我不确定您是否有自定义会话处理程序以及它是否存储在数据库中,但从您在此页面上的帖子和 cmets 猜测,我会假设它存储在服务器端 cookie 中。

        现在解决您的问题的方法是咬紧牙关,将必要的数据存储在数据库中并通过会话 ID 访问它,即使这意味着创建另一个表与您的订单表并排。

        但是,如果您立即执行该操作,则另一种解释是用户注销或提交了破坏其会话的操作(删除服务器端 cookie)。

        您将在您的服务器 /tmp 文件夹中看到这些 cookie,尝试查看您的 cookie,它应该命名为 'sess' + $session_id。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-09-12
          • 1970-01-01
          • 2014-12-29
          • 1970-01-01
          • 2017-12-11
          • 2015-04-02
          • 2012-08-15
          相关资源
          最近更新 更多