Сеансы 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 / ... (я подозреваю)

xtds
источник
Также исправлено это для моей машины - 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); 
?>
Безграничный isa
источник
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
user3232196
источник
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);
mohsin.mr
источник
0

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

  • убедитесь, что браузеры отправляют cookie сеанса обратно на серверы (домена и поддоменов), установите домен cookie сеанса как .example.com.

  • Убедитесь, что PHP нашел правильную «цель» для восстановления переменной сеанса:

    • Если домен и поддомены указывают на один и тот же компьютер (возможно, на разные виртуальные хосты), убедитесь, что они session_save_pathодинаковы для всех (я тестировал)
    • Если домен и поддомены указывают на разные машины, общее хранилище (например, база данных) лучше всего подходит для сохранения и восстановления данных сеанса (я еще не тестировал). Используйте session_set_save_handlerдля этого.
user953985
источник
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
0

Использование:

session_name("put_a_session_name");
session_start([
  "cookie_domain" => ".example.com",
  "cookie_path" => "/"
]);
Шакил Ахмед
источник
-2

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

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

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

сакабако
источник
3
Это также делает его очень уязвимым для кражи сеанса :) Проблема не в том, что идентификаторы сеанса не совпадают (они есть, см. Мой обновленный пост), а в том, что данные не перемещаются между доменами.
dragonmantank
Согласен, это очень уязвимо, оставляя идентификатор сеанса в строке запроса.
Ян Джеймисон
4
Файлы cookie также отправляются в виде обычного текста, это не открывает никаких возможностей, которые еще не были открыты. Я не говорю, что это хорошее решение, но оно не менее безопасно, чем использование файлов cookie.
sakabako 01
1
Это менее безопасно в том смысле, что пользователи могут (обманом) поделиться своим URL-адресом и, таким образом, поделиться своим активным идентификатором сеанса. Гораздо менее вероятно, что пользователь поделится своим файлом cookie идентификатора сеанса непреднамеренно.
Бастиан тен Клоостер