Сеансы PHP через поддомены


92

Я пытаюсь настроить следующее:

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"

но похоже, что он не передает информацию из одного домена в другой.

[Редактировать]

Я пробовал следующее:

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

Идентификаторы сеанса точно такие же, но когда я выгружаю $_SESSIONпеременную, она не показывает оба ключа, а только тот ключ, который я установил для каждого домена.


Вы также должны включить его в своем коде, см. Http://us2.php.net/manual/en/function.session-set-cookie-params.php
Residuum

1
У меня почти такая же настройка (я установил домен cookie сеанса с помощью вызова "session_set_cookie_params"), и он отлично работает.
Милен А. Радев

Ответы:


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 ().
Дэвид Кэрролл

3
Ага. подтверждено. славный там целую вечность ходил кругами;)
Daithí

1
ПРИМЕЧАНИЕ ... мне пришлось закрыть браузер и перезапустить его, чтобы он заработал на жизненном сервере. Опустите любую ini_set("session.cookie_domain", ".domain.com");причину, по которой он создавал новый идентификатор сеанса при каждом обновлении.
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

10
какая поддержка браузера должна здесь? это действие на стороне сервера.
Куф

4

Была именно эта проблема - я хотел, чтобы значения сеанса, созданные в x.example.local, были доступны в example.local и наоборот.

Во всех найденных мною решениях говорится об изменении домена сеанса с помощью php_value session.cookie_domain .example.local.htaccess (или через php.ini, или через ini_set).

Уловка заключалась в том, что я устанавливал session.cookie_domainдля всех поддоменов (пока нормально), но также и для основного домена. По- session.cookie_domainвидимому, установка на основном домене запрещена.

В основном так это сработало для меня:

  • установите session.cookie_domainдля ВСЕХ ПОДДОМЕНОВ.
  • не устанавливайте его для основного ДОМЕНА

О да, пожалуйста, убедитесь, что у домена есть TLD (в моем случае .local). Протокол Http не позволяет хранить файлы cookie / сеансы в домене без .tld (т.е. localhost не будет работать, но stuff.localhost будет).

РЕДАКТИРОВАТЬ : Также убедитесь, что вы всегда очищаете файлы cookie своего браузера во время тестирования / отладки сеансов на поддоменах. Если вы этого не сделаете, ваш браузер всегда будет отправлять старый файл cookie сеанса, для которого, вероятно, еще не установлен правильный cookie_domain. Сервер восстановит старую сессию, поэтому вы получите ложноотрицательные результаты. (во многих сообщениях упоминается использование session_name ('stuff') для того же эффекта)


3

Я решил это вот так

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

Потому что я работал на localhost

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

не работал , он видит .localhost как верхний уровень вместо .com / .local / ... (я подозреваю)


Также исправлено это для моей машины - Ubuntu 14.04
Деннис

3

Я подтвердил. ответ Джореона правильный. Я не могу комментировать, потому что моей репутации недостаточно, поэтому я размещаю свой комментарий здесь.

Определите константу в файле конфигурации. Если вы хотите его изменить, не нужно изменять целые файлы.

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

Имя сеанса не может состоять только из цифр, должна присутствовать хотя бы одна буква. В противном случае каждый раз создается новый идентификатор сеанса.

Используйте следующий код, чтобы начать использовать сеанс

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

Используйте это, это работает:

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

похоже, что он устанавливает cookie для tld ... или я что-то упускаю?
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

Я понимаю, что вам не нужно что-то вроде OpenID, как предлагает Джоэл, но вы хотите иметь доступ к данным сеанса в нескольких доменах.

Единственная возможность, которую я могу рассматривать как решение этой проблемы, - это сохранить данные сеанса в базе данных и вытащить их из этой базы данных.


Правильно, хотя аутентификация - это часть того, что я хочу сделать, меня также интересуют данные сеанса, которые сохраняются во время работы пользователя.
dragonmantank

0

У меня была аналогичная проблема, однако это решение было для меня хорошим, возможно, поможет другим в будущем

отредактируйте php.ini

session.cookie_domain = ".example.com"

магия здесь

suhosin.session.cryptdocroot = Off

suhosin.cookie.cryptdocroot = Off

https://www.sitepoint.com/community/t/sessions-across-subdomains-domain-com-phpsessid-changes/3013/19


0

Я не могу говорить о других версиях PHP, но в 5.6.6 просто установив session.cookie_domainзначение вphp.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

Я прочитал все ответы выше, я думаю, что мой ответ полезен для людей, которые ищут это в Google:

  • убедитесь, что браузеры отправляют 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


-2

Быстрое и грязное решение - использовать это для перенаправления:

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

это добавит что-то вроде строки ?PHPSESSID=etnm7kbuf5lg0r6tv7je6ehtn4к URL-адресу, который сообщает PHP идентификатор сеанса, который он должен использовать.


3
Это также делает его очень уязвимым для кражи сеанса :) Проблема не в том, что идентификаторы сеанса не совпадают (они есть, см. Мой обновленный пост), а в том, что данные не перемещаются между доменами.
dragonmantank

Согласен, это очень уязвимо, оставляя идентификатор сеанса в строке запроса.
Ян Джеймисон

4
Файлы cookie также отправляются в виде обычного текста, это не открывает никаких возможностей, которые еще не были открыты. Я не говорю, что это хорошее решение, но оно не менее безопасно, чем использование файлов cookie.
sakabako 01

1
Это менее безопасно в том смысле, что пользователи могут (обманом) поделиться своим URL-адресом и, таким образом, поделиться своим активным идентификатором сеанса. Гораздо менее вероятно, что пользователь поделится своим файлом cookie идентификатора сеанса непреднамеренно.
Бастиан тен Клоостер
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.