Без заголовка

Один из проектов, в разработке которого я участвовал в недавнем времени, расчитывался на огромную посещаемость (забегая вперёд, скажу - проект действительно стал исключительно посещаемым), в связи с чем пришлось разрабатывать и использовать технические решения, позволяющие проекту не "падать" под огромными нагрузками.

В частности, была разработана система кеширования, которую можно охарактерировать как "всё по максимуму в в HTML, остальное - включаем через SSI и фреймы". Поскольку на сайте используются пользовательские сессии, сложилась ситуация, когда сессию должны могли инициировать и скрипты (язык программирования - PHP, основной сервер - Apache 1.x), включенные через SSI. Тут надо заметить, что из-за жёсткого требования заказчика - в строке запроса не должны присутствовать PHPSID и т.п (на сайте используются ЧПУ), использование trans_sid исключалось.

Trans_sid использовать нельзя, скрипты, включенные через SSI заголовок выдать не могут и, следовательно, проставить сессию в cookie - тоже. Сначала я, было, решил полностью отказаться от SSI и работать исключительно с iframe, но подумал - нельзя ли Apache заставить генерировать идентификатор сессии самостоятельно?

Оказалось - можно. Первое, что пришло в голову - использовать модуль mod_unique_id к Apache - я слышал об этом модуле, но никогда его не использовал. Внимательно прочитав инструцию к модулю, я понял, что это совсем не то, что нужно - модуль генерирует уникальный идентификатор для каждого запроса:

This module provides a magic token for each request which is guaranteed to be unique across "all" requests under very specific conditions. The unique identifier is even unique across multiple machines in a properly configured cluster of machines.


Внимательно пролистав список официальных модулей Apache, я нашёл в списке mod_usertrack - модуль, маркирующий пользователей при помощи cookie. Обычно он используется для того, чтобы различать пользователей в логах веб-сервера, но для нас главно то, что он маркирует пользователей идентификатором, который можно прочитать.

Проведя испытания, я столкнулся с вполне ожидаемыми трудностями - во время первого запроса, когда сервер только что отослал cookie клиенту, в переменной PHP \_COOKIE$ пусто - cookie ещё не пришли от клиента назад и, соотвественно, не были записаны в эту переменную.

В PHP есть функция apache_response_headers, возвращающая массив всех заголовков, выдаваемых в HTTP-запросе в данный момент. Естественно, в числе этих заголовков нашёлся и тот, что отвечает за простановку cookie. Функция, читающая такой заголовок и cookie, может выглядеть, например, так:
function U_sid()
{
	// Если идентификатор уже есть в cookie, возвращаем его
    if (isset($_COOKIE['Apache'])) return $_COOKIE['Apache'];

    // Иначе - ищем его в ответе Apache
    $responce = apache_response_headers();
    foreach (preg_split('/s*;s*/', @$responce['Set-Cookie']) as $chunk)
    {
        list($key, $value) = explode('=', $chunk, 2);
        if ($key == 'Apache') return $value;
    }

    return null;
}
"Apache" - это имя cookie, которое проставляет Apache. Далее - всё просто, в php.ini отключаем "session.use_trans_sid" и "session.use_cookies", чтобы запретить PHP создавать сессии, в .htaccess помещаем директивы модуля mod_usertrack:

CookieFormat Compact
CookieTracking on
CookieStyle Cookie

А в библиотечный файл (или наши файлы PHP, поближе к началу), вызов необходимых, для создания сессии, функций:
// Узнаём идентификатор сессии
if (($sid = U_sid()) !== null)
{
    // Если он не null, создаём сессию
    session_id($sid);
    session_start();
}
В итоге мы получаем cookie-сессию, которая создаётся даже в файле, включенном через SSI.
27 октября 2004 19:00

Ваше имя или адрес блога (можно OpenID):

Текст вашего комментария, не HTML: