Сессии PHP, потерянные между страницами – ведут себя по-разному в зависимости от сервера

Я потратил пару месяцев на разработку приложения на моем домене. Это общая концепция. Во время разработки я принимал его сам в своем собственном домене, но недавно подтолкнул его к нашему фактическому. Проблема в том, что сеансы не создаются и не сохраняются между страницами, и я не могу для жизни понять, почему.

Извините за стену кода ниже, но я предпочитаю это теоретическое объяснение.

Давайте начнем с того, как начать сеанс в верхней части каждой страницы:

function sec_session_start() { $session_name = 'login'; $secure = false; $httponly = true; ini_set('session.use_only_cookies', 1); session_set_cookie_params(86400, '/', '.domain.com', $secure, $httponly); session_name($session_name); session_start(); session_regenerate_id(); } 

И затем, как я проверяю, вошел ли пользователь в систему. Я добавил return x; вместо false для отладки. Я добавляю это к URL-адресу переадресации.

 function login_check($mysqli) { if(isset($_SESSION['id'], $_SESSION['login_string'], $_SESSION['type'])) { $id = $_SESSION['id']; $login_string = $_SESSION['login_string']; $user_browser = $_SERVER['HTTP_USER_AGENT']; if($_SESSION['type'] == 1 || $_SESSION['type'] == 2) // Admin user { if ($stmt = $mysqli->prepare("SELECT `password` FROM `users` WHERE `id` = ? LIMIT 1")) { $stmt->bind_param('s', $id); $stmt->execute(); $stmt->store_result(); if($stmt->num_rows == 1) { $stmt->bind_result($password); $stmt->fetch(); $login_check = hash('sha512', $password.$user_browser); if($login_check == $login_string) { return true; } else { return 1; } } else { return 2; } } else { return 3; } } else if($_SESSION['type'] == 3) { // Standard user if($stmt=$mysqli->prepare("SELECT `password` FROM `proj` WHERE `id` = ? LIMIT 1")) { $stmt->bind_param("s", $_SESSION['id']); $stmt->execute(); $stmt->store_result(); if($stmt->num_rows == 1) { $stmt->bind_result($db_key); $stmt->fetch(); $login_check = hash('sha512', $db_key.$user_browser); if($login_check == $login_string) { return true; } else { return 4; } } } } else { return 5; } } else { return 6; } } 

У меня есть две страницы входа, одна для администраторов и одна для пользователей.

Администратор:

 <?php ini_set('display_errors','On'); error_reporting(E_ALL); include_once "../functions.php"; include_once "../db_connect.php"; sec_session_start(); if(login_check($mysqli) === true) { header('Location: ../index.php'); } else { // Login form } 

Пользователи:

 <?php ini_set('display_errors','On'); error_reporting(E_ALL); include_once "../functions.php"; include_once "../db_connect.php"; sec_session_start(); if(login_check($mysqli) === true) { header('Location: ../index.php'); } else { // Login form } 

Совсем идентично, кроме источников файлов, поскольку admin login.php находится в /admin . Несмотря на это, первая отображает форму входа правильно, а вторая перенаправляет вас на index.php (даже когда в инкогнито, тайна для меня), вызывая цикл переадресации (поскольку index.php отправляет его обратно для входа в него) ,

В дополнение к этому, когда я login.php систему с надлежащими учетными данными, он перенаправляет меня на index.php только для перенаправления меня обратно в login.php с кодом ошибки 6 .

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

Любая помощь приветствуется, спасибо

ОБНОВЛЕНИЕ 17 декабря:

После нескольких часов отладки мы пришли к выводу, что проблема связана не с кодом, а с конфигурацией сервера. Простой пример:

 <?php session_start(); echo session_id(); ?> 

Если вы откроете этот файл на рабочем сервере и обновите страницу, он отобразит новый идентификатор сеанса с каждым запросом. Почему-то я не знаю. Я подтвердил, что создан файл сеанса, а также файл cookie. Он содержит правильную информацию и может быть доступен SSH с разрешениями сервера. Поистине странное поведение.

Любые подсказки?

Я прошел через ваш код, и я не нашел ничего, кроме всего лишь 1 вещи.

Вы не должны использовать == для сравнения строк === в порядке.

 $something = 0; echo ('password123' == $something) ? 'true' : 'false'; 

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

  if($login_check == $login_string) 

замените его:

  if($login_check === $login_string) 

Иначе все абсолютно безупречно. Если изменение этой мелочи не решит вашу проблему, просто дайте мне знать.

Совет

Вы подключаетесь к БД до начала сеанса. Я бы рекомендовал вам импортировать вашу функцию, а затем начать сеанс, а затем подключиться к базе данных.

 include_once "../functions.php"; sec_session_start(); include_once "../db_connect.php"; 

Убедитесь, что сеанс уже запущен и убедитесь, что он выполняется только один раз:

С PHP> = 5.4:

 function sec_session_start() { if (session_status() == PHP_SESSION_NONE) { $session_name = 'login'; $secure = false; $httponly = true; ini_set('session.use_only_cookies', 1); session_set_cookie_params(86400, '/', '.domain.com', $secure, $httponly); session_name($session_name); session_start(); session_regenerate_id(); } } 

До PHP 5.4:

 function sec_session_start() { if (session_id() == '') { $session_name = 'login'; $secure = false; $httponly = true; ini_set('session.use_only_cookies', 1); session_set_cookie_params(86400, '/', '.domain.com', $secure, $httponly); session_name($session_name); session_start(); session_regenerate_id(); } } 

Кроме того, почему сеанс нужно восстанавливать каждый раз?

Я испытал подобную проблему несколько месяцев назад на моем рабочем сервере, где заканчивались сессии (например, в ваших случаях сеансы теряются между страницами), и пользователи внезапно вышли из моего сайта. Поэтому после нескольких дней отладки все было сведено к этим трем строкам в файле php.ini .

  • session.gc_divisor
  • session.gc_maxlifetime
  • session.gc_probability

Из руководства ,

  • session.gc_probability в сочетании с session.gc_divisor используется для управления вероятностью запуска программы gc (сборка мусора). По умолчанию 1.

  • session.gc_divisor в сочетании с session.gc_probability определяет вероятность запуска процесса gc (сборка мусора) при каждой инициализации сеанса. Вероятность вычисляется с использованием gc_probability / gc_divisor, например, 1/100 означает, что вероятность каждого процесса GC начинается с 1%. session.gc_divisor по умолчанию – 100.

  • session.gc_maxlifetime указывает количество секунд, после которых данные будут считаться «мусором» и потенциально очищены. Сбор мусора может произойти во время сеанса (в зависимости от session.gc_probability и session.gc_divisor).

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

 session.gc_divisor 1000 1000 session.gc_maxlifetime 1440 1440 session.gc_probability 0 0 

Таким образом, это означает, что сборщик мусора начнет с вероятности session.gc_probability, деленной на session.gc_divisor. И используя значения по умолчанию для этих параметров (соответственно 0 и 1000), вероятность сбора мусора = session.gc_probability / session.gc_divisor, то есть 0/1000 = 0%, что, по моему мнению, неверно, плюс session.gc_maxlifetime показалось мне слишком низким ,

Итак, я решил изменить настройки сеанса в файле php.ini и включил эти значения,

 session.gc_probability = 1 session.gc_divisor = 1000 session.gc_maxlifetime = 28800 

И с тех пор все работает нормально. Поэтому мое предложение для вас, проверьте эти три значения в файле php.ini и при необходимости измените их в соответствии с вашими потребностями.

У меня был аналогичный опыт в прошлом, я точно не помню, как я решаю эту проблему, но из того, что я помню, это связано с кукисами сеансов и переменным порядком в PHP.

найдите эту строку ниже в php.ini,

variables_order = "GPCS"

так или иначе, изменение порядка этих варов повлияло на сеанс PHP.

если по каким-либо изменениям, как и я, вы не можете изменить настройки на сервере, вы также можете попробовать дублировать cookie сессии с помощью обычного файла cookie, выполнив следующие действия:

 session_start(); set_cookie(session_name(), session_id()); 

и другое примечание, у другого браузера также есть другое поведение в cookie сеанса, например: сафари. на сафари, я должен дублировать файл cookie, независимо от переменной последовательности.

Надеюсь, поможет

Я также столкнулся с этой проблемой, но это была установка ssl, которая изменила ссылку на базовый файл с https, а файл отправки был без ссылки ssl. Также мне пришла в голову продолжительность сеанса. Помимо этого, мой провайдер хостинга может объяснить это.