Ошибка Alternating class not found при использовании обработчика сеанса

#php #session

#php #сессия

Вопрос:

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

 session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy', 'sess_gc');
 

У меня есть этот фрагмент кода…

 $qid = "select count(*) as total
        from zen_sessions
        where sesskey = '" . $key . "'";

if(!class_exists('DB'))
    require_once dirname(dirname(__FILE__)).'/class/DB.class.php';
var_dump(new DB());                      //this is line 109
$total = DB::select_one($qid);
 

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

 Fatal error: Class 'DB' not found in /path/to/file/session_functions.php on line 109
 

Я не могу понять, как это не приведет к сбою при require вместо var_dump и почему только иногда?

Заранее спасибо за любую информацию.

редактировать — ответ на комментарий / вопрос:

Результат следующего кода

 var_dump(class_exists('DB', false)); 
var_dump(is_file(dirname(__DIR__).'/class/DB.class.php')); 
 

является:

 bool(false) bool(true) 
 

перед попыткой потребовать его и тот же результат после require (или true true, когда он не выдает мне ошибку)
Выглядит примерно так:

 bool(true) bool(true) object(DB)#3 (0) { } 
 

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

Edit2 — новые результаты.

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

Примечание:

Обработчик «write» не выполняется до тех пор, пока выходной поток не будет закрыт. Таким образом, вывод из отладочных инструкций в обработчике «write» никогда не будет виден в браузере. Если требуется отладочный вывод, рекомендуется вместо этого записать отладочный вывод в файл.

Редактировать 3 — Примечание для ясности:

DB Класс должен был быть загружен автоматически (и везде в приложении) class_exists , и require просто существуют для целей тестирования.

Редактировать 4 — Трассировка стека

Я решил попробовать создать исключение, когда класс не найден, чтобы увидеть трассировку стека, вот что я получаю

 Fatal error: Uncaught exception 'Exception' with message 'DB Class Not Found.' 
in /path/to/file/session_functions.php:108 
Stack trace: #0 [internal function]: sess_write('074dabb967260e9...', 'securityToken|s...') 
#1 {main} thrown in /path/to/file/session_functions.php on line 108 
 

Комментарии:

1. Что, если вы сделаете class_exists('DB', false) вместо этого? var_dump(is_file(dirname(dirname(__FILE__)).'/class/DB.class.php')); __DIR__ вместо dirname(__FILE__)

2. @zerkms смотрите мою правку. Практически тот же результат.

3. внимание , ваш код уязвим для атак с использованием sql-инъекций!

4. @DanielA. Белый Это довольно большой скачок, когда вы не знаете, откуда $key он исходит. Спасибо за беспокойство.

5. Используете ли вы «пространства имен»? Начните с первых принципов с кода, который не работает… Часто выполняйте ‘class_check’ для ‘DB’. Начиная сразу после того момента, когда, по вашему мнению, он должен был быть загружен. Затем переместите эту проверку в сторону кода, вызывающего беспокойство. Выдайте исключение, если класс ‘DB’ не найден. Всегда убедитесь, что классы явно загружены, прежде чем использовать их. Либо используйте «автозагрузчик», либо «include_once». Всегда загружайте класс безоговорочно, если он используется при большинстве запусков программы.

Ответ №1:

Единственное, что я могу придумать, что может быть причиной этого, это из уведомления в PHP docs для session_set_save_handler:

Предупреждение

Текущий рабочий каталог изменяется с помощью некоторых САПИ, если сеанс закрыт при завершении скрипта. Можно закрыть сеанс раньше с помощью session_write_close() .

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

Я бы попробовал добавить session_write_close(); где-нибудь в вашу функцию и посмотреть, исправит ли это.

По общему признанию, не уверен, почему is_file в этом случае будет возвращено true, но, возможно, стоит попробовать.

Комментарии:

1. Это сделало это! Спасибо! Все еще не уверен, почему, но убедившись, что он закрывает его, когда я знаю, что область действия заставляла его работать каждый раз.

2. Все еще не уверен, что именно происходит, стоило бы узнать, что именно вызывает это.

Ответ №2:

Хотя я не могу быть уверен, но я уверен, что ошибка где-то в другом месте, и она просто проецируется, как вы ее описали.

Для тестирования и отладки вашего кода вам необходимо использовать отладчик, подобный PDT. Но тогда проблема в том, что вам нужно отладить часть вашего кода, которая находится вне досягаемости отладчика, средства записи сеанса! Чтобы преодолеть эту проблему, вы можете использовать session_write_close . Вы можете поместить его где-нибудь в конце вашего загрузчика, или, если у вас его нет, вы можете сделать это следующим образом:

 <?php
function shutdown_function()
{
    session_write_close();
}

register_shutdown_function('shutdown_function');
 

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

Ответ №3:

попробуй:

 $save_handler = new DB();
session_set_save_handler($save_handler, true);
 

затем сопоставьте функции чтения, записи и т. Д. Внутри вашего класса. я столкнулся с аналогичной проблемой (причудливые случайные ошибки о том, что класс не найден), реализуя обходной путь пользовательского обработчика сохранения другого пользователя для HHVM с redis, и вот как я это исправил. если вы используете HipHopVirtualMachine (или, возможно, какой-либо другой тип JIT-компилятора или кэша приложений), иногда ваш проект может кэшировать некоторые функции без обновления, создавая странные ошибки, подобные этой. обычно перезапуска демона fastcgi и добавления пробелов в один из ваших файлов достаточно, чтобы заставить его повторно интерпретировать ваш проект.

Комментарии:

1. Класс DB не является обработчиком сохранения. Он просто используется в функции для вызова базы данных. Функция, в которой находится этот код, является sess_write функцией.

2. Спасибо за ваше понимание. Поскольку это отлично работает примерно в 6 других проектах. Это единственный, который дает мне такую подгонку. Я изучу это, а также могу провести рефакторинг, чтобы использовать реализацию класса SessionHandlerInterface вместо функций.