Компьютерное

Блокировка сессии PHP и ошибка тайм-аута cURL

Хотя на первый взгляд PHP-сессии кажутся довольно простыми, недооценка их сложности может привести к некоторым трудным для отслеживания проблемам.

Одна из таких вещей — механизм блокировки сессии. Их цель — защитить данные сессии от перезаписи другими экземплярами сценария или другими сценариями, работающими одновременно.

Когда вы вызываете session_start () (или сразу после запуска сценария, если включена опция session.auto_start), файл сессии блокируется от записи, и по умолчанию он разблокируется только после остановки сценария. Это означает, что любой другой сценарий, пытающийся одновременно получить доступ к этому файлу сессии, должен ждать, пока файл сессии не будет разблокирован.

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

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

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

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

Если вы ищете быстрое решение и думаете: «Я просто сохраню свои сессии в memcached», вы будете разочарованы. Конфигурация memcached по умолчанию использует ту же, безопасную логику, как описано выше: сессии блокируются, как только их использует один вызов PHP.

Если вы используете расширение Memcached в PHP, вы можете установить для memcached.sess_locking значение «off», чтобы избежать блокировки сеанса. Gо умолчанию выставленно «on», что делает его действующим как обычный обработчик сессии.

Если вы используете Redis, вам повезло (нет), потому что обработчик сессий redis еще не поддерживает блокировку. С Redis в качестве бэкэнда хранилища сессий не будет блокировок. (зато будет куча геммороя. Об этом есть в статье, ссылку на которую я давал выше. см. PHP Session locking: the problem it’s trying to fix)

Если вы используете MySQL в качестве бэкэнда сессии (как это делает Drupal), у вас есть своя реализация, просто потому что нет расширения PHP, которое позволяло бы использовать MySQL в качестве хранилища сессий. Поэтому где-то в вашем PHP-коде есть вызов функции session_set_save_handler (), который описывает, какой класс или метод отвечает за чтение и запись данных вашей сессии. Это означает, что ваша реализация решает, будут ли сессии блокироваться или нет, как говорится — всё в ваших руках.

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

Вот пример кода (caller.php):

session_start();

$_SESSION['var1'] = 'value1';

// ...

$curl = curl_init('http://samedomain.com/remote.php');
curl_setopt($curl, CURLOPT_COOKIE, http_build_query($_COOKIE));
curl_exec($curl);
curl_close($curl);

Сначала все выглядит хорошо. Вашему remote.php нужны куки, поэтому вы отправляете их. Это грязный трюк, и вы никогда не должны его использовать, но некоторые люди так делают. Дьявол же кроется в деталях.

Если вы внимательно посмотрите на свои куки, вы заметите, что они содержат значение идентификатора сессии ($ _COOKIE [‘PHPSESSID’]). Скрипт remote.php принимает идентификатор сессии как свой собственный и пытается получить доступ к тому же файлу сессии, но не может, потому что caller.php все еще работает, поэтому файл сессии заблокирован.

Теперь у нас есть мексиканское противостояние: caller.php ждет ответа от local.php, который, в свою очередь, ждет caller.php, чтобы разблокировать файл сессии. Это может быть решено с помощью тайм-аута cURL, но по умолчанию оно не определено. Так что, если вы явно не установили его, вам нужно подождать, пока caller.php достигнет max_execution_time. И если лимит высок (или полностью отключен), у вас есть проблема.

Прежде всего, вы никогда не должны запускать cURL без установленного времени ожидания:

curl_setopt ($ curl, CURLOPT_TIMEOUT, 5);


Это не решит проблему, но, по крайней мере, вы получите возможность правильно обработать ошибку cURL.

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

Давайте посмотрим окончательный код сейчас:

session_start();

$_SESSION['var1'] = 'value1';

session_write_close();

// ...

$curl = curl_init('http://samedomain.com/remote.php');
curl_setopt($curl, CURLOPT_COOKIE, http_build_query($_COOKIE));
curl_setopt($curl, CURLOPT_TIMEOUT, 5);
$result = curl_exec($curl);

curl_close($curl);

Вот и всё. Просто вызовите функцию session_write_close () и расслабьтесь. Или попробуйте исправить другие проблемы в своих проектах, что на самом деле кажется более вероятным. А еще лучше — попробуйте в конце-концов выспаться ;)

Mirivlad

Скромный труженик консоли и окошек.

Share
Published by
Mirivlad

Recent Posts

Реверс-инжиниринг электроники и ПО

Реверс инжиниринг электроники и программного обеспечения — увлекательная и важная дисциплина, играющая ключевую роль в…

4 месяца ago

Что лучше Apple iPhone 14 или iPhone 13: сравниваем модели

Рынок смартфонов не стоит на месте и каждый год пополняется новыми моделями. Компания Apple традиционно…

4 месяца ago

Как открыть интернет-магазин с нуля в 2024 году?

Запуск онлайн-бизнеса может показаться сложной задачей, но на самом деле этот процесс можно существенно упростить,…

6 месяцев ago

Как проверить текст на уникальность?

Если Вы хотите продвинуть свой сайт в поисковых системах, одним из самых важных аспектов является…

9 месяцев ago

ТОП лучших смартфонов Samsung 2024 года: рейтинг по цене и качеству

Корейская компания Samsung зарекомендовала себя на потребительском рынке как производитель флагманов, так и бюджетных смартфонов.…

1 год ago

Как навсегда удалить профиль в Instagram?

В то время как множество пользователей регистрируются в Инстаграм, другие ищут способы как удалить аккаунт…

2 года ago