会话(PHP)以及它们如何相互交互

时间:2022-05-12 13:44:37

This is a question about sessions in php.

这是关于php中的会话的问题。

I have Page A.php, C.php, D.php. A.php is displaying content A, upon login I want A.php to display content B, when moving from Page A.php to Page D.php and then again to A.php it displays the content A instead of content B.

我有Page A.php,C.php,D.php。 A.php正在显示内容A,登录时我希望A.php显示内容B,当从Page A.php移动到Page D.php然后再转到A.php时它显示内容A而不是内容B.

The pages A.php C.php and D.php are all communicating through ajax.

A.php C.php和D.php这些页面都是通过ajax进行通信的。

I'm wondering how can I check if a session is on-going on page A.php with ajax, so that it displays content B instead of content A.

我想知道如何在aphax页面A.php上检查会话是否正在进行,以便它显示内容B而不是内容A.

1 个解决方案

#1


1  

TL;DR;

You shouldn't.

你不应该。

Simply because your problem isn't the session it's a race-condition.

仅仅因为你的问题不是会话,那就是竞争条件。


First, one needs to be clear about the distinction between an HTTP request and a PHP script. Each HTTP request can invoke multiple PHP scripts (e.g. one script includes another script in the same request). However, multiple HTTP requests to the same or different script always run in their own isolated environment (where no request shares information with another request). This is the share-nothing architecture that PHP is built on and it's important to understand this concept when dealing with PHP server-side sessions.

首先,需要明确HTTP请求和PHP脚本之间的区别。每个HTTP请求都可以调用多个PHP脚本(例如,一个脚本包含同一请求中的另一个脚本)。但是,对相同或不同脚本的多个HTTP请求始终在其自己的隔离环境中运行(其中没有请求与另一个请求共享信息)。这是PHP构建的无共享体系结构,在处理PHP服务器端会话时理解这个概念很重要。

It's also important to recognize that each user typically has their own session file on the server. So concurrent requests from multiple users is normally not a problem no matter how many scripts are making use of that session in a single request.

同样重要的是要认识到每个用户通常在服务器上都有自己的会话文件。因此,无论有多少脚本在单个请求中使用该会话,来自多个用户的并发请求通常都不是问题。

会话(PHP)以及它们如何相互交互

The default session handler in PHP will lock an active session from the moment session_start() is called until the script ends or session_write_close() is called. This exclusive lock prevents any other instance of the interpreter from being able to read from or write to this session file until the lock has been released (in order to prevent corruption in the session). This means that concurrent requests to the same session will block. However, this is only a problem when the same session is being accessed from multiple concurrent HTTP requests (such as in the case of multiple asynchronous - AJAX - requests).

PHP中的默认会话处理程序将从调用session_start()的那一刻起锁定活动会话,直到脚本结束或调用session_write_close()。此独占锁可防止解释器的任何其他实例在释放锁之前能够读取或写入此会话文件(以防止会话中的损坏)。这意味着对同一会话的并发请求将被阻止。但是,当从多个并发HTTP请求(例如,在多个异步 - AJAX请求的情况下)访问相同会话时,这只是一个问题。

会话(PHP)以及它们如何相互交互

In other words, PHP makes it safe for you to transparently use the session across multiple concurrent requests without having to worry about the concurrency model breaking your session.

换句话说,PHP使您可以安全地跨多个并发请求透明地使用会话,而不必担心会破坏会话的并发模型。

This, however, does not mean that you should rely on the session for the purposes of concurrency.

但是,这并不意味着您应该为了并发而依赖会话。


Let me give you an example of race conditions you can yourself design by accident. The user lands on your homepage at www.example.com where a session is started by A.php (and say the user is not logged in). Now, the user attempts to log in (say C.php is the script responsible for login/authentication and is called through AJAX). Let's say C.php redirects the user back to the homepage after login (typical PRG scenario). When A.php is loading again it's using the session and is locking it. Let's say another AJAX request is triggered in the background to B.php, which also needs the session. It will have to wait on A.php to release the lock or end before it can do anything. So now it's sitting in a blocked state until that lock is released.

让我举一个你可以自己设计的竞赛条件的例子。用户登陆您的主页www.example.com,其中A.php启动会话(并说用户未登录)。现在,用户尝试登录(例如,C.php是负责登录/身份验证的脚本,通过AJAX调用)。假设C.php在登录后将用户重定向回主页(典型的PRG场景)。当A.php再次加载时,它正在使用会话并锁定它。假设另一个AJAX请求在后台触发到B.php,后者也需要会话。它必须等待A.php释放锁或结束才能执行任何操作。所以现在它处于阻塞状态,直到锁被释放。

Typically these kinds of issues don't matter if your requests are loading within a reasonable amount of time (typically just fractions of a second). They do however have cascading consequences.

如果您的请求在合理的时间内(通常只有几分之一秒)加载,这些问题通常无关紧要。然而,他们确实有连带的后果。

Let's say your javascript has a setInterval() callback that calls on B.php every 5 seconds. Now let's say your server becomes suddenly overwhelmed with requests and B.php is now taking about ~6 seconds to load. Now your webserver has a queue backedup with multiple requests that will all block each other as they'll be all asking for the same session. You can see how this can become more and more of a problem if not planned for carefully.

假设您的javascript有一个setInterval()回调,每5秒调用一次B.php。现在让我们假设您的服务器突然被请求所淹没,而B.php现在需要大约6秒才能加载。现在,您的Web服务器有一个备份队列,其中包含多个请求,这些请求将全部阻塞,因为它们都会要求同一个会话。如果不仔细计划,你可以看到这会变得越来越成问题。


Sessions are generally used as a way to keep stateful information through what is otherwise a stateless protocol (i.e. HTTP). This usually works out fine for tracking things like is the user authenticated/logged-in, preferences they may have saved on your site, or shopping cart checkout information, etc...

会话通常用作通过无状态协议(即HTTP)保持有状态信息的方式。这通常可以很好地跟踪用户身份验证/登录,他们可能在您的网站上保存的偏好,或购物车结帐信息等等...

What you really shouldn't rely on the session for is tracking state beyond that which concerns a single request. Meaning, if you want to use a session to determine if the user is making other concurrent requests or examine other sessions outside of this user's immediate request you're really breaking some of the architecture constraints that PHP was designed around and are likely to run into unexpected failures.

您真正不应该依赖会话的是跟踪超出单个请求的状态。这意味着,如果您想使用会话来确定用户是否正在进行其他并发请求,或者在此用户的即时请求之外检查其他会话,那么您实际上正在破坏PHP围绕这些设计构建的一些约束,并且可能会遇到意外失败。

#1


1  

TL;DR;

You shouldn't.

你不应该。

Simply because your problem isn't the session it's a race-condition.

仅仅因为你的问题不是会话,那就是竞争条件。


First, one needs to be clear about the distinction between an HTTP request and a PHP script. Each HTTP request can invoke multiple PHP scripts (e.g. one script includes another script in the same request). However, multiple HTTP requests to the same or different script always run in their own isolated environment (where no request shares information with another request). This is the share-nothing architecture that PHP is built on and it's important to understand this concept when dealing with PHP server-side sessions.

首先,需要明确HTTP请求和PHP脚本之间的区别。每个HTTP请求都可以调用多个PHP脚本(例如,一个脚本包含同一请求中的另一个脚本)。但是,对相同或不同脚本的多个HTTP请求始终在其自己的隔离环境中运行(其中没有请求与另一个请求共享信息)。这是PHP构建的无共享体系结构,在处理PHP服务器端会话时理解这个概念很重要。

It's also important to recognize that each user typically has their own session file on the server. So concurrent requests from multiple users is normally not a problem no matter how many scripts are making use of that session in a single request.

同样重要的是要认识到每个用户通常在服务器上都有自己的会话文件。因此,无论有多少脚本在单个请求中使用该会话,来自多个用户的并发请求通常都不是问题。

会话(PHP)以及它们如何相互交互

The default session handler in PHP will lock an active session from the moment session_start() is called until the script ends or session_write_close() is called. This exclusive lock prevents any other instance of the interpreter from being able to read from or write to this session file until the lock has been released (in order to prevent corruption in the session). This means that concurrent requests to the same session will block. However, this is only a problem when the same session is being accessed from multiple concurrent HTTP requests (such as in the case of multiple asynchronous - AJAX - requests).

PHP中的默认会话处理程序将从调用session_start()的那一刻起锁定活动会话,直到脚本结束或调用session_write_close()。此独占锁可防止解释器的任何其他实例在释放锁之前能够读取或写入此会话文件(以防止会话中的损坏)。这意味着对同一会话的并发请求将被阻止。但是,当从多个并发HTTP请求(例如,在多个异步 - AJAX请求的情况下)访问相同会话时,这只是一个问题。

会话(PHP)以及它们如何相互交互

In other words, PHP makes it safe for you to transparently use the session across multiple concurrent requests without having to worry about the concurrency model breaking your session.

换句话说,PHP使您可以安全地跨多个并发请求透明地使用会话,而不必担心会破坏会话的并发模型。

This, however, does not mean that you should rely on the session for the purposes of concurrency.

但是,这并不意味着您应该为了并发而依赖会话。


Let me give you an example of race conditions you can yourself design by accident. The user lands on your homepage at www.example.com where a session is started by A.php (and say the user is not logged in). Now, the user attempts to log in (say C.php is the script responsible for login/authentication and is called through AJAX). Let's say C.php redirects the user back to the homepage after login (typical PRG scenario). When A.php is loading again it's using the session and is locking it. Let's say another AJAX request is triggered in the background to B.php, which also needs the session. It will have to wait on A.php to release the lock or end before it can do anything. So now it's sitting in a blocked state until that lock is released.

让我举一个你可以自己设计的竞赛条件的例子。用户登陆您的主页www.example.com,其中A.php启动会话(并说用户未登录)。现在,用户尝试登录(例如,C.php是负责登录/身份验证的脚本,通过AJAX调用)。假设C.php在登录后将用户重定向回主页(典型的PRG场景)。当A.php再次加载时,它正在使用会话并锁定它。假设另一个AJAX请求在后台触发到B.php,后者也需要会话。它必须等待A.php释放锁或结束才能执行任何操作。所以现在它处于阻塞状态,直到锁被释放。

Typically these kinds of issues don't matter if your requests are loading within a reasonable amount of time (typically just fractions of a second). They do however have cascading consequences.

如果您的请求在合理的时间内(通常只有几分之一秒)加载,这些问题通常无关紧要。然而,他们确实有连带的后果。

Let's say your javascript has a setInterval() callback that calls on B.php every 5 seconds. Now let's say your server becomes suddenly overwhelmed with requests and B.php is now taking about ~6 seconds to load. Now your webserver has a queue backedup with multiple requests that will all block each other as they'll be all asking for the same session. You can see how this can become more and more of a problem if not planned for carefully.

假设您的javascript有一个setInterval()回调,每5秒调用一次B.php。现在让我们假设您的服务器突然被请求所淹没,而B.php现在需要大约6秒才能加载。现在,您的Web服务器有一个备份队列,其中包含多个请求,这些请求将全部阻塞,因为它们都会要求同一个会话。如果不仔细计划,你可以看到这会变得越来越成问题。


Sessions are generally used as a way to keep stateful information through what is otherwise a stateless protocol (i.e. HTTP). This usually works out fine for tracking things like is the user authenticated/logged-in, preferences they may have saved on your site, or shopping cart checkout information, etc...

会话通常用作通过无状态协议(即HTTP)保持有状态信息的方式。这通常可以很好地跟踪用户身份验证/登录,他们可能在您的网站上保存的偏好,或购物车结帐信息等等...

What you really shouldn't rely on the session for is tracking state beyond that which concerns a single request. Meaning, if you want to use a session to determine if the user is making other concurrent requests or examine other sessions outside of this user's immediate request you're really breaking some of the architecture constraints that PHP was designed around and are likely to run into unexpected failures.

您真正不应该依赖会话的是跟踪超出单个请求的状态。这意味着,如果您想使用会话来确定用户是否正在进行其他并发请求,或者在此用户的即时请求之外检查其他会话,那么您实际上正在破坏PHP围绕这些设计构建的一些约束,并且可能会遇到意外失败。