你能在一个Session中切换PHP会话吗?

11

我有两个应用程序,我想将它们合并。其中一个是我编写的,另一个是我正在使用的CMS。我的身份验证是在我编写的应用程序中进行的,我希望我的CMS能够知道这些信息。问题是CMS使用一个会话名称,而我的应用程序使用另一个名称。由于可能存在名称空间冲突,我不想让它们使用相同的名称,但我仍然希望获取此信息。

在请求过程中是否可以切换会话名称?例如,在CMS中执行以下操作:

//session_start already called by cms by here

$oldSession = session_name();
session_name("SESSION_NAME_OF_MY_APP");
session_start();

//get values needed
session_name($oldSession);
session_start();

这个方案可行吗?我在文档和网络上找不到任何关于在调用session_start()后是否可以使用类似此方案的信息。有什么建议吗?

如果没有其他解决方法,我一直在考虑开发Web服务来获取信息,但显然从会话中获取信息更好,因为那些信息已经可用。

谢谢!

7个回答

5

这里是一个实际工作中如何在会话之间切换的示例:

session_id('my1session');
session_start();
echo ini_get('session.name').'<br>';
echo '------------------------<br>';
$_SESSION['value'] = 'Hello world!';
echo session_id().'<br>';
echo $_SESSION['value'].'<br>';
session_write_close();
session_id('my2session');
session_start();
$_SESSION['value'] = 'Buy world!';
echo '------------------------<br>';
echo session_id().'<br>';
echo $_SESSION['value'].'<br>';
session_write_close();
session_id('my1session');
session_start();
echo '------------------------<br>';
echo $_SESSION['value'];

日志将会是这样的:


PHPSESSID
------------------------
my1session
Hello world!
------------------------
my2session
Buy world!
------------------------
Hello world!

因此,您可以看到,在更改会话时保存和恢复会话变量。

4
请不要手动更改会话ID - 这是区分一个用户和另一个用户的方式。如果您手动操纵会话ID,就会导致会话劫持的发生,这对于没有经验的人来说是非常危险的事情。 - Guss
不必手动设置session_id,您可以调用session_regenerate_id()(但必须在第二个session_start()之后执行)。通过进行此更改并从代码中删除两个session_id()调用,您可以获得相同的效果,而无需处理会话ID。请注意,这不会加载旧会话 - “第二个会话”中存在的所有数据与第一个会话中的数据相同 - 它只是防止将新数据写入旧会话。它看起来像是构建自己的可交换会话管理机制的开始。 - Guss

3

注意:下面的答案不正确,请不要使用或投票。我将其留在这里作为讨论的场所。

你的解决方案应该是可行的(尽管我从未尝试过类似的方法),但是在调用 session_name() 之前,你必须手动关闭先前的会话,否则它将默默地失败。

你可以尝试像这样的代码:

session_write_close();
$oldsession = session_name("MY_OTHER_APP_SESSION");
session_start();

$varIneed = $_SESSION['var-I-need'];
session_write_close();
session_name($oldsession);
session_start;

没有必要实际操作会话ID值,无论是通过PHP会话ID操纵例程还是手动cookie修改 - PHP将自行处理所有这些,您不应该对此进行更改。


1
在我看来,你可能会得到两个具有相同ID的不同会话名称。如果发生这种情况,即使它们具有不同的名称,这两个会话也共享相同的数据。为了避免这种情况,你可能需要修改会话ID... - commonpike
1
我不认为会发生这种情况,除非你假设两个不同的客户端也可能“错误地”获得相同的会话ID。这是因为session_name()的工作方式是更改PHP用于标识会话的cookie,如果这导致您生成新会话(而不是加载现有会话),PHP将保证使用新会话ID-否则很容易劫持会话。 - Guss
此外,随意更改会话ID是打开会话劫持漏洞的一种确定方式。如果您确实需要更改会话ID(请不要这样做),请不要假设自己知道如何生成会话ID,并始终使用session_regenerate_id()函数。 - Guss
在我的测试中,这实际上是不起作用的。第二个session_start()调用将重新打开先前打开的会话...所以无论第一个session_start()之后的session_id()是什么。我已经到处搜索和测试了...一旦开始,就不能切换会话。您可以更新会话ID,可以更新名称,但是上下文和数据将保留从第一个session_start()调用开始的状态。 - ajon
你说得对 - 这实际上不起作用。我不确定它以前是否起作用过(虽然我通常很擅长测试我的答案...抱歉)。据我所知,session_start() 将始终重新加载先前启动的会话,即使您更改了会话名称也是如此。在第二个 session_start() 之前更改会话名称仅会创建具有相同会话 ID 的其他会话 cookie(即使在第二个 session_start() 之前使用 session_regenerate_id())。我没有找到不加载第一个会话的方法,尽管我相当确定这是 PHP 中的一个错误。 - Guss

2

我一直在完善这个功能,现在我想分享我的做法。我在子应用程序中使用会话名称切换到父级会话,然后再切回到子应用程序的会话。如果父级会话不存在,该解决方案将创建它。

$current_session_id = session_id();
$current_session_name = session_name();

session_write_close();

$parent_session_name = 'NameOfParentSession';

// Does parent session exist?   
if (isset($_COOKIE[$parent_session_name])) {

    session_id($_COOKIE[$parent_session_name]);
    session_name($parent_session_name);
    session_start();

} else {
    session_name($parent_session_name);
    session_start();

    $success = session_regenerate_id(true);
}

$parent_session_id = session_id();

// Do some stuff with the parent $_SESSION 

// Switch back to app's session
session_write_close();
session_id($current_session_id);
session_name($current_session_name);
session_start();

这对我有用!改回原始会话很重要,否则最后的魔法会话处理代码将被运行,事情会变得奇怪! - Roel van Duijnhoven

1

session_regenerate_id()

手册已经很好地解释了这个问题,但是这里有一些来自手册的例子。

session_start();

$old_sessionid = session_id();

session_regenerate_id();

$new_sessionid = session_id();

echo "Old Session: $old_sessionid<br />";
echo "New Session: $new_sessionid<br />";

print_r($_SESSION);

3
这只改变了会话ID,但会话仍然是相同的。 - hakre

0

这是可能的。但我认为你必须自己处理会话管理:

session_name('foo');
// start first session
session_start();

// …

// close first session
session_write_close();

session_name('bar');
// obtain session id for the second session
if (ini_get('session.use_cookies') && isset($_COOKIE[session_name()])) {
    session_id($_COOKIE[session_naem()]);
} else if (ini_get('session.use_trans_sid') && !ini_get('session.use_only_cookies') && isset($_REQUEST[session_name()])) {
    session_id($_REQUEST[session_naem()]);
}
// start second session
session_start();

// …

但请注意,您可能还需要执行其他会话处理操作,例如设置cookie。我不知道PHP在这种情况下是否也会执行此操作。


0

你应该使用session_id,它可以用来设置/获取会话ID(或名称)。

因此,不要使用session_name(在你的伪代码中),而是使用session_id。


0

Zend_Session 提供了会话 Namespacing。

Zend_Session_Namespace 实例是用于访问 $_SESSION 的命名空间切片的访问器对象。Zend_Session 组件在现有的 PHP ext/session 基础上提供了一个管理和管理接口,并为 Zend_Session_Namespace 提供 API 以持久化会话命名空间。Zend_Session_Namespace 提供了一个标准化的面向对象界面,用于处理持久存在于 PHP 的标准会话机制中的命名空间。支持匿名和经过身份验证(例如“登录”)的会话命名空间。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接