跨子域的PHP会话

跨子域的PHP会话,php,authentication,session,cross-domain,Php,Authentication,Session,Cross Domain,我正在尝试设置以下内容: auth.example.com sub1.example.com sub2.example.com 如果用户访问sub1.example.com或sub2.example.com但未登录,他们将被重定向到auth.example.com,并可以登录 sub1.example.com和sub2.example.com是两个独立的应用程序,但使用相同的凭据 我尝试在php.ini中设置以下内容: session.cookie_domain = ".example.com

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

auth.example.com
sub1.example.com
sub2.example.com
如果用户访问
sub1.example.com
sub2.example.com
但未登录,他们将被重定向到
auth.example.com
,并可以登录

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

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

session.cookie_domain = ".example.com"
但它似乎没有将信息从一个域传递到另一个域

[编辑]

我尝试了以下方法:

auth.example.com
sub1.example.com
sub2.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>'
session_set_cookie_params(0, '/', '.example.com');
session_start();
print session_id() . "<br>";
$_SESSION['Checked'] = 1;
print_r($_SESSION);
会话ID完全相同,但当我转储
$\u session
变量时,它不会同时显示两个键,只是显示我在每个域下设置的任何键。

尝试使用:

session.cookie_domain = "example.com"
而不是:

session.cookie_domain = ".example.com"
注意开头缺少的句号


不过,要小心使用它,因为并非所有浏览器都支持它。

我的想法是,您不希望像Joel建议的那样使用OpenID,而是希望能够跨多个域访问会话数据


我能想到的解决该问题的唯一方法是将sessiondata存储在数据库中,然后将其从该数据库中取出。

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

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

这将在URL中添加类似于
?PHPSESSID=etnm7kbuf5lg0r6tv7je6ehtn4的内容,它告诉PHP它应该使用的会话id。

我不知道问题是否仍然存在,但我遇到了同样的问题,并在调用
会话设置cookie\u参数()之前设置了会话名称解决了这个问题。

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

使用这个,它可以工作:

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

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

关闭以下Suhosin会话设置,即可恢复业务:

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

我知道这是旧的,但这对我来说很好,在同一个框中有多个域和子域

<?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);

}
我是这样解决的

ini_set('session.cookie_domain', '.testdomain.example');
session_start();
因为我在本地主机上工作

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

不工作,它将.localhost视为顶级,而不是.com/.local/。。。(我怀疑)

我已经阅读了上面的所有答案,我认为我的答案对谷歌搜索的人很有帮助:

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

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

    • 如果域和子域指向同一台机器(可能是不同的虚拟主机),请确保
      session\u save\u path
      对所有人都是相同的(我测试过)
    • 如果域和子域指向不同的计算机,那么公共存储(如数据库)最适合保存和恢复会话数据(我还没有测试)。使用
      session\u set\u save\u处理程序执行此操作

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

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

会话的路径。保存路径对于您的情况可能不同,但每个域/子域上的路径应相同。默认情况下并不总是如此。

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

我找到的所有解决方案都表示通过使用更改会话域
php\u value session.cookie\u domain.example.local
in.htaccess(或通过php.ini或通过ini\u集)

问题是我正在为所有子域(到目前为止还可以)以及主域设置
会话.cookie\u域。在主域上设置
session.cookie\u域
显然是一个禁忌

基本上就是我的工作方式:

  • 为所有子域设置
    会话.cookie\u域
  • 不要为主域设置它
哦,是的,请确保域具有TLD(在我的情况下是。local)。Http协议不允许在没有.tld的域中存储Cookie/会话(即localhost不起作用,但stuff.localhost会起作用)


编辑:在跨子域测试/调试会话时,还要确保始终清除浏览器cookie。如果您不这样做,您的浏览器将始终发送可能尚未设置正确cookie\u域的旧会话cookie。服务器将恢复旧会话,因此您将得到假阴性结果。(在许多帖子中提到使用session\u name('stuff')达到完全相同的效果)

只需尝试使用下面的代码
session\u 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);

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

资源:

我测试过你的作品

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

example.com/sessionview.php // 123
--代码


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

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

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

我也有过类似的问题,不过,这个解决方案对我来说是好的,也许将来会帮助别人

编辑php.ini文件

session.cookie_domain=“.example.com”

魔法就在这里

suhosin.session.cryptdocroot = Off

suhosin.cookie.cryptdocroot = Off

我不能代表其他版本的PHP,但在5.6.6中,只需在
PHP.ini
文件中设置
session.cookie\u domain
值,就可以让iPage上的所有子域共享同一组
suhosin.session.cryptdocroot = Off

suhosin.cookie.cryptdocroot = Off
session.cookie_domain = '.yourdomainname.example'
session.auto_start = 1
session_name("put_a_session_name");
session_start([
  "cookie_domain" => ".example.com",
  "cookie_path" => "/"
]);