Как узнать, активен ли сеанс?

В запросе есть несколько разных способов определить, был ли запущен сеанс, например:

$isSessionActive = (session_id() != "");

Или:

$isSessionActive = defined('SID');

Однако, оба они не работают, если вы начинаете сеанс, а затем закрываете его; session_id() вернет прежний идентификатор сеанса, а SID будет определен. Аналогично, вызов session_start() в этот момент будет генерировать E_NOTICE, если у вас уже есть сеанс. Есть ли разумный способ проверить, активен ли сеанс в настоящий момент, не прибегая к буферизации вывода, оператору запирания (@session_start()) или чему-то еще в равной степени хакерским?

EDIT: я написал патч, чтобы попытаться включить эту функциональность в PHP: http://bugs.php.net/bug.php?id=52982

EDIT 8/29/2011: новая функция добавлена ​​в PHP 5.4, чтобы исправить это: "Открыть статус сеанса с помощью новой функции session_status"

// as of 8/29/2011
$isSessionActive = (session_status() == PHP_SESSION_ACTIVE);

EDIT 12/5/11: session_status() в руководстве по PHP.

Ответ 2

Я работал над этим, добавляя пару функций-оболочек вокруг различных функций создания/закрытия сеанса/уничтожения. В основном:

function open_session() {
     session_start();
     $_SESSION['is_open'] = TRUE;
}

function close_session() {
   session_write_close();
   $_SESSION['is_open'] = FALSE;
}

function destroy_session() {
   session_destroy();
   $_SESSION['is_open'] = FALSE;
}

function session_is_open() {
   return($_SESSION['is_open']);
}

Hackish, но выполнил то, что мне нужно.

Ответ 3

Я тоже сталкиваюсь с этим, и настройка в $_SESSION для меня не является вариантом. Для PHP 5.3.8:

  • Если какой-либо сеанс запущен с запросом, define('SID') вернет FALSE, а также $_SESSION не будет установлен.
  • Это не зависит от того, используется ли session_id() для установки идентификатора сеанса или нет.
  • После определения первого session_start(), SID и $_SESSION установлен пустой массив.
  • session_destroy() отключает session_id(), тогда это пустая строка. SID будет оставаться определенным (и установить для него предыдущее значение, которое может быть пустой строкой). $_SESSION остается неизменным. Он получит reset/заселен в следующий раз session_start.

С этими состояниями, особенно в качестве session_id() можно вызвать между ними, чтобы установить идентификатор для следующего сеанса, невозможно безопасно определить состояние сеанса с помощью SID, $_SESSION и session_id().

"Попытка" с помощью session_start() (например, с @) может оказаться не очень полезной, так как это изменит статус сеанса и изменит содержимое $_SESSION (и добавит заголовок set-cookie, если файл cookie был а не часть запроса). Это было неуместно в моем случае.

Пока я запускал тесты, я сталкивался с этим поведением, что вы не можете попытаться изменить настройку ini session.serialize_handler, когда сеанс активен, даже если вы установите его на одно и то же значение. То же самое верно для session.use_trans_sid Docs, который является более легким. Это привело меня к следующей функции:

/**
 * @return bool
 */
function session_is_active()
{
    $setting = 'session.use_trans_sid';
    $current = ini_get($setting);
    if (FALSE === $current)
    {
        throw new UnexpectedValueException(sprintf('Setting %s does not exists.', $setting));
    }
    $result = @ini_set($setting, $current); 
    return $result !== $current;
}

Насколько я вижу, ошибка проверяет только активный статус сеанса (не отключен), поэтому это не должно возвращать ложный положительный результат при отключении сеансов.

Чтобы эта функция была совместима с PHP 5.2, она нуждается в небольшой модификации:

/**
 * @return bool
 */
function session_is_active()
{
    $setting = 'session.use_trans_sid';
    $current = ini_get($setting);
    if (FALSE === $current)
    {
        throw new UnexpectedValueException(sprintf('Setting %s does not exists.', $setting));
    }
    $testate = "mix$current$current";
    $old = @ini_set($setting, $testate);
    $peek = @ini_set($setting, $current);
    $result = $peek === $current || $peek === FALSE;
    return $result;
}

Некоторая песочница.

Ответ 4

Следующий код только сбрасывает один session_id() для меня, а не два

session_start();
echo session_id();
session_destroy();
echo session_id();

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

session_start();
$_SESSION['intialized'] = 'This will not print';
$_SESSION = array(); // Unset all variables
session_destroy();
echo $_SESSION['initialized']; // No output

Ответ 5

Здесь хорошее падение в замене, которое не сломается, когда вы перейдете к 5.4:

if(!function_exists('session_status')){
    function session_active(){
        return defined('SID');   
    }
}else{
    function session_active(){
        return (session_status() == PHP_SESSION_ACTIVE);   
    }        
}

Ответ 6

Кен, если сеанс уничтожен, массив $_SESSION не должен быть доступен... или, по крайней мере, ваши значения должны быть отменены. Итак, в теории (untested) вы должны иметь возможность проверить массив на значение, чтобы знать, установлено ли что-либо в данный момент.

Ответ 7

Существует несколько мест, которые необходимо проверить, чтобы проверить, что сеанс активен:

1 cookie существует и не истек 2-й механизм хранения основной сессии (файловая система или база данных) имеет запись, соответствующую файлу cookie.