跨子域的PHP会话


92

我正在尝试设置以下内容:

auth.example.com
sub1.example.com
sub2.example.com

如果用户访问sub1.example.comsub2.example.com且他们尚未登录,则他们将被重定向到auth.example.com并可以登录。

sub1.example.comsub2.example.com是两个独立的应用程序,但使用相同的凭据。

我尝试在php.ini中设置以下内容:

session.cookie_domain = ".example.com"

但它似乎并未将信息从一个域传递到另一个域。

[编辑]

我尝试了以下方法:

sub1.example.com/test.php

session_set_cookie_params(0, '/', '.example.com');
session_start();
print session_id() . "<br>";
$_SESSION['Regsitered'] = 1;
echo '<a href="http://auth.example.com/test.php">Change Sites</a>'

auth.example.com/test.php

session_set_cookie_params(0, '/', '.example.com');
session_start();
print session_id() . "<br>";
$_SESSION['Checked'] = 1;
print_r($_SESSION);

会话ID完全相同,但是当我转储$_SESSION变量时,它不会显示两个键,而不会显示我在每个域下设置的任何键。



1
我几乎有相同的设置(我通过调用“ session_set_cookie_params”来设置会话cookie域),并且工作正常。
Milen A. Radev

这是一个很好的功能,可以正常工作 stackoverflow.com/questions/2835486/…–
boksiora

Answers:


134

我不知道问题是否仍然存在,但是我遇到了同样的问题,并在调用之前设置了会话名称来解决了该问题session_set_cookie_params()

$some_name = session_name("some_name");
session_set_cookie_params(0, '/', '.example.com');
session_start();

我没有做任何更改,php.ini但现在一切正常。


10
我确认,它可以解决问题。我很累,无法在那里得到答案:stackoverflow.com/questions/4948340/…。但是我在这里找到的。
罗马

5
完美的作品!一直为此寻找年龄。是$some_name = session_name("some_name");做到了。谢谢你并支持。
Kit

4
添加session_name("domain");也是我所缺少的成分。缺少有关这些会话设置的php.net文档。php.net上有一些社区帖子,指出必须先定义session.name,然后才能应用对session_set_cookie_params()的更改。
David Carroll

3
是的 确认。不错的人在那里
转悠

1
注意...必须关闭我的浏览器并重新启动才能使其在生命服务器上正常工作。排除任何ini_set("session.cookie_domain", ".domain.com");导致每次刷新都创建新会话ID的原因。
Daithí

24

尽管Cookie设置正确,但可以神秘地阻止会话数据在子域上读取的一件事.example.com是PHP Suhosin补丁。按照问题中的示例,您可以正确配置所有内容,但它根本无法正常工作。

关闭以下Suhosin会话设置,即可恢复正常工作:

suhosin.session.cryptua = Off 
suhosin.session.cryptdocroot = Off

5

尝试使用:

session.cookie_domain = "example.com"

代替:

session.cookie_domain = ".example.com"

请注意开始时缺少的时间段。

但是请小心使用此功能,因为并非所有浏览器都支持此功能。


9
不支持哪些浏览器?
gawpertron 2011年

10
这里需要什么浏览器支持?这是服务器端的操作。
2014年

4

遇到了这个确切的问题-我希望在x.example.local上创建的会话值在example.local上可用,反之亦然。

我发现所有解决方案都说可以通过php_value session.cookie_domain .example.local在.htaccess中使用(或通过php.ini或ini_set)更改Session域 。

我要抓住的是我session.cookie_domain为所有子域设置了(到目前为止还可以),但也为主域设置了。session.cookie_domain在主域上设置显然是禁止的。

基本上,它对我有用:

  • session.cookie_domain为所有子域设置。
  • 不要为主要DOMAIN设置

哦,是的,请确保该域具有TLD(在我的情况下是.local)。Http协议不允许将cookie /会话存储在没有.tld的域中(即localhost无法正常工作,但stuff.localhost可以正常工作)。

编辑:还要确保在测试/调试跨子域的会话时始终清除浏览器cookie。如果不这样做,您的浏览器将始终发送旧的会话cookie,该会话cookie可能尚未设置正确的cookie_domain。服务器将恢复旧的会话,因此您将得到错误的负面结果。(在很多帖子中都提到使用session_name('stuff')具有完全相同的效果)


3

我这样解决了

ini_set('session.cookie_domain', '.testdomain.example');
session_start();

因为我在本地主机上工作

ini_set('session.cookie_domain', '.localhost');

无法正常工作,它会将.localhost视为顶层,而不是.com / .local / ...(我怀疑)


还为我的机器修复了该问题-Ubuntu 14.04
dennis

3

我已经确认了 约永的答案是正确的。我无法发表评论,因为我的声誉还不够,所以我在这里发表评论。

在配置文件中定义常量。如果要更改它,则无需修改整个文件。

define('ROOT_DOMAIN',   'mysite.example');
define('PHP_SESSION_NAME', 'MYSITE'); 

会话名称不能仅由数字组成,必须至少包含一个字母。否则,每次都会生成一个新的会话ID。

使用以下代码开始使用会话

session_name(PHP_SESSION_NAME);
session_set_cookie_params(0, '/', '.' . ROOT_DOMAIN);
session_start();

我正在使用此功能:

function load_session() {
    if (session_status() == PHP_SESSION_NONE) {
        session_name(PHP_SESSION_NAME);
        session_set_cookie_params(0, '/', '.' . ROOT_DOMAIN);
        session_start();
    } elseif (session_name() != PHP_SESSION_NAME) {
        session_destroy();
        session_name(PHP_SESSION_NAME);
        session_set_cookie_params(0, '/', '.' . ROOT_DOMAIN);
        session_start();
    }
}
load_session(); // put it in anywhere you want to use session

2

在每个域/子域上使用它:

session_name('name');
ini_set('session.cookie_domain', '.example.com');
ini_set('session.save_path', '/var/lib/php/session');
session_start();

session.save_path根据您的情况,路径可能会有所不同,但每个域/子域上的路径都应该相同。默认情况下并不总是如此。


1

使用this,它的工作原理是:

ini_set('session.cookie_domain', 
    substr($_SERVER['SERVER_NAME'],strpos($_SERVER['SERVER_NAME'],"."),100));

这看起来像是为tld设置cookie ...还是我缺少了什么?
chacham15

1

子域和根域Cookie会话结合使用

资源:http//php.net//manual/tr/function.session-set-cookie-params.php

我已经测试过作品

sub.example.com/sessionadd.php?id=123

example.com/sessionview.php // 123

-代码

<?php 
$currentCookieParams = session_get_cookie_params(); 

$rootDomain = '.example.com'; 

session_set_cookie_params( 
    $currentCookieParams["lifetime"], 
    $currentCookieParams["path"], 
    $rootDomain, 
    $currentCookieParams["secure"], 
    $currentCookieParams["httponly"] 
); 

session_name('mysessionname'); 
session_start(); 

setcookie($cookieName, $cookieValue, time() + 3600, '/', $rootDomain); 
?>

0

我的想法是,您不希望像乔尔(Joel)建议的那样使用OpenID之类的东西,但是您希望可以跨多个域访问会话数据。

我可以想到的唯一解决方案是将会话数据存储在数据库中,然后将其从该数据库中取出。


正确,虽然身份验证是我要做的一部分,但我也对在用户工作时存储的会话数据感兴趣。
2009年


0

我不能说其他版本的PHP,但是在5.6.6中,只需session.cookie_domainphp.ini文件中就可以使iPage上的所有子域共享同一组会话变量。

请确保从浏览器中删除与您的域相关的所有现有Cookie,以进行测试。

session.cookie_domain = '.yourdomainname.example'

哦,不知道有什么区别,但是我也在使用会话自动启动。

session.auto_start = 1

0

只需尝试使用上面的session_start()方法下面的代码

$sess_life_time = 21600; //in seconds
$sess_path = "/";
$sess_domain = ".example.com";
$sess_secure = true; // if you have secured session
$sess_httponly = true; // httponly flag

session_set_cookie_params($sess_life_time, $sess_path, $sess_domain, $sess_secure, $sess_httponly);

0

我已经阅读了上面的所有答案,我认为我的答案对使用此工具的人很有帮助:

  • 确保浏览器将会话Cookie发送回(域和子域的)服务器,并将会话Cookie域设置为.example.com

  • 确保PHP找到正确的“目标”来还原会话变量:

    • 如果域和子域指向同一台计算机(可能是不同的虚拟主机),请确保session_save_path所有域都相同(我已测试)
    • 如果域和子域指向不同的计算机,则公共存储(如数据库)最适合保存和还原会话数据(我尚未测试)。使用session_set_save_handler做到这一点。

0

我知道这很旧,但是对同一个盒子上的多个域和子域来说,这对我来说很好用。

<?php
define('site_domain','example.com');
session_set_save_handler('_open',
                         '_close',
                         '_read',
                         '_write',
                         '_destroy',
                         '_clean');

function _open(){

    global $_sess_db;

$db_user = 'user';
$db_pass = 'pass';
$db_host = 'localhost';

if ($_sess_db = mysql_connect($db_host, $db_user, $db_pass)){

    return mysql_select_db('database', $_sess_db);

}

return false;

}

function _close(){

    global $_sess_db;
    return mysql_close($_sess_db);

}

function _read($id){

    global $_sess_db;
    $id = mysql_real_escape_string($id);
    $domain = mysql_real_escape_string(site_domain);
    $agent = mysql_real_escape_string(isset($_SERVER['HTTP_USER_AGENT']));

    $sql = "SELECT data
    FROM sessions
    WHERE id = '$id' AND domain = '$domain' AND agent = '$agent'";

     if ($result = mysql_query($sql, $_sess_db)){

         if (mysql_num_rows($result)){
             $record = mysql_fetch_assoc($result);
             return $record['data'];
        }

    }

    return '';

}

function _write($id, $data){

    global $_sess_db;
    $access = time();

    $id = mysql_real_escape_string($id);
    $access = mysql_real_escape_string($access);
    $data = mysql_real_escape_string($data);
    $domain = mysql_real_escape_string(site_domain);
    $agent = mysql_real_escape_string(isset($_SERVER['HTTP_USER_AGENT']));

    $sql = "REPLACE INTO sessions
    VALUES ('$id', '$access', '$data', '$domain', '$agent')";

    return mysql_query($sql, $_sess_db);

}

function _destroy($id){

    global $_sess_db;
    $id = mysql_real_escape_string($id);
    $domain = mysql_real_escape_string(site_domain);
    $agent = mysql_real_escape_string(isset($_SERVER['HTTP_USER_AGENT']));

    $sql = "DELETE FROM sessions
    WHERE id = '$id' AND domain = '$domain' AND agent = '$agent'";

    return mysql_query($sql, $_sess_db);

}

function _clean($max){

    global $_sess_db;
    $old = time() - $max;
    $old = mysql_real_escape_string($old);
    $domain = mysql_real_escape_string(site_domain);
    $agent = mysql_real_escape_string(isset($_SERVER['HTTP_USER_AGENT']));

    $sql = "DELETE FROM sessions
    WHERE  access < '$old' AND domain = '$domain' AND agent = '$agent'";

    return mysql_query($sql, $_sess_db);

}

?>


6
您在回答什么问题?以及如何改善/增强其他9个答案?
random_user_name 2012年


-2

一种快速而肮脏的解决方案是将其用于重定向:

header( $url.'?'.session_name().'='.session_id() );

这会?PHPSESSID=etnm7kbuf5lg0r6tv7je6ehtn4在URL 的末尾添加一些内容,从而告诉PHP应该使用的会话ID。


3
这也使它极易遭受会话盗窃:)问题不是会话ID不匹配(它们是,请参阅我更新的帖子),而是数据在域之间不移动。
2009年

同意,这非常容易受到攻击,将会话ID保留在查询字符串中。
伊恩·贾米森

4
Cookies也以纯文本形式发送,这不会打开任何尚未打开的途径。我并不是说这是一个很好的解决方案,但它的安全性不亚于使用cookie。
sakabako

1
从用户可能(被诱使)共享其URL并因此共享其活动会话ID的意义上说,这种方法不太安全。用户不太可能不经意地共享其会话ID cookie。
巴斯蒂安(Bastiaan)10 Klooster,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.