Подтвердить что ты не робот

Baffled: PHP Неустранимая ошибка: Исключение брошено без рамки стека в Unknown в строке 0?

Я обнаружил, что одной из распространенных причин ошибки является исключение, создаваемое в обработчике исключений. Я совершенно уверен, что этого не происходит в приложении, которое я пытаюсь отладить... Но я поместил все строки обработки инициализации в начало index.php в try/catch. *

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

Кто-то заметил, что это случилось с ними, потому что их первичный ключ должен был быть CHAR (32) вместо INT (11). ПК в этом приложении все INT.

Другие предложения заключаются в том, что это может быть проблема с PHP 5.3.3, исправленная в 5.3.6, полный диск, и необходимость типизировать значение SimpleXML. Мы используем PHP 5.3.3, но в этом случае обновление должно быть последним средством. Так было не всегда.

ОБНОВЛЕНИЕ/ПРИМЕЧАНИЕ: я на самом деле не могу воспроизвести ошибку самостоятельно, только вижу, что это происходит в журналах, см. Ниже параграф, где я считаю, что ошибка происходит...

* Из журналов ошибок кажется вероятным, что по крайней мере одно место, где это происходит, - index.php. Я делаю это только потому, что это указано в некоторых записях по ссылке URL. Код try/catch в настоящее время находится только вокруг "верхней" части инициализации скрипта, ниже которой в основном вывод HTML. В выводе есть некоторый PHP-код (хотя и довольно простой), поэтому мне может понадобиться проверить это. Вот часть catch, которая не производит никаких выводов в журналах:

} catch (Exception $e) {
    error_log(get_class($e)." thrown. Message: ".$e->getMessage(). "  in " . $e->getFile() . " on line ".$e->getLine());
    error_log('Exception trace stack: ' . print_r($e->getTrace(),1));
}

Буду очень признателен за любые советы по этому вопросу!

РЕДАКТИРОВАТЬ: PHP работает как модуль Apache (серверный API: обработчик Apache 2.0). Я не думаю, что используются какие-либо ускорители PHP, но я просто не знаю, как это сказать. Ни один из перечисленных в Википедии не находится в phpinfo().

Насколько я могу судить, MPM - это prefork. Это первый раз, когда я заглянул в MPM:

# ./httpd -l
Compiled in modules:
  core.c
  prefork.c
  http_core.c
  mod_so.c
4b9b3361

Ответ 1

Проблема

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

Воспроизводите проблему

Поскольку вы уже устранили общие причины, вам нужно будет воспроизвести ошибку. Если вы знаете, какой параметр вызовет ошибку, вам будет легко найти ошибку.

  • Скорее всего, этого достаточно, если вы знаете все параметры POST/GET.
  • Если вы не можете воспроизвести только с этим, вам нужно знать дополнительные заголовки запросов. Такие как пользовательский агент, accept-encoding,...
  • Если вы все еще не можете воспроизвести, это становится очень сложным: ошибка может зависеть от состояния (сеанса), текущего времени, IP-адреса источника и т.д.

Метод пользовательского журнала

Давайте начнем просто: Чтобы получить все параметры, вы можете написать в самом начале затронутого php файла что-то вроде:

file_put_contents("/path/to/some/custom_error_log", date()."\n".print_r(get_defined_vars(), true), FILE_APPEND | LOCK_EX);

Не забывайте, что файл custom_error_log должен быть доступен для записи в ваше приложение php. Затем, когда ошибка возникает в журнале ошибок, найдите соответствующие строки в файле custom_error_log. Надеемся, что не требуется много запросов в секунду, чтобы вы все еще могли идентифицировать запрос. Возможно, некоторые дополнительные параметры в журнале ошибок, такие как source ip, могут помочь вам идентифицировать запрос (если ваш журнал ошибок показывает это). Из этих данных восстановите запрос с теми же параметрами POST/GET.

Метод tcpdump

Следующая опция, которая очень проста, но требует, чтобы у вас был root-доступ на вашей целевой машине, нужно установить tcpflow. Затем создайте папку, cd в эту папку и просто выполните (с правами root) tcpflow "port 80". Опция (порт 80) является выражением фильтра pcap. Чтобы увидеть все, что вы можете сделать с этим, см. man pcap-filter. Существует много того, что могут делать эти выражения фильтра.

Теперь tcpflow выполнит запись всех подключений tcp на порт 80, восстановит полный обмен данными, объединив пакеты, принадлежащие одному соединению, и дамп этих данных в файл, создав два новых файла на одно соединение, один для входящих данных и один для исходящих данные. Теперь найдите файлы для соединения, которые вызвали ошибку, снова на основе временной метки в вашем журнале ошибок и последней измененной меткой времени файлов. Затем вы получаете полные заголовки HTTP-запросов. Теперь вы можете полностью восстановить HTTP-запрос, включая настройку того же accept-encoding, user-agent и т.д. Вы даже можете напрямую передать запрос в netcat, переиздавая точный запрос. Помните, хотя некоторые аргументы, подобные sessionid, могут быть на вашем пути. Если php обнаруживает, что срок действия сеанса истек, вы можете просто перенаправить на логин или что-то еще неожиданное. Возможно, вам придется обмениваться такими вещами, как идентификатор сеанса.

Стыковка большего количества вещей

Если ничто из этого не помогает, и вы не можете воспроизвести ошибку на вашем компьютере, вы можете попытаться высмеять все, что сложно издеваться. Например, адрес источника ip. Это может сделать некоторые трюки необходимыми, но это возможно: вы можете подключиться к вашему серверу с помощью ssh с параметром "-w", создавая интерфейс туннеля. Затем назначьте оскорбительный адрес ip на свой собственный компьютер и задайте правила маршрута (route add host), чтобы использовать туннель для конкретного ip. Если вы можете подключить два компьютера непосредственно друг к другу, вы можете даже сделать это без туннеля.

Не пытайтесь высмеивать сеанс, который должен быть интересен. Вы можете прочитать все переменные сеанса, используя метод с print_r (get_defined_vars()). Затем вам нужно создать сеанс с точно такими же переменными.

Запросить пользователя

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

Если ничто из этого не помогает

Если ничто из этого не помогает... ну... Тогда это становится тяжело трудным. IP-вещь уже маловероятна. Это может быть библиотека GEO-IP, которая вызывает ошибку в IP-адресах из определенного региона, но все это довольно маловероятно. Если ни одно из вышеперечисленных действий не помогло вам воспроизвести проблему, вы, вероятно, просто не нашли правильный запрос во всех данных, созданных custom_log_file-call/tcpflow. Постарайтесь увеличить свои шансы, получив более точную метку времени. Вы можете использовать microtime() в php в качестве замены для даты(). Проверьте свой веб-сервер, если вы можете получить что-то более точное, чем секунды в журнале ошибок. Напишите свою собственную реализацию "хвоста", которая даст вам более точную отметку времени... Уменьшите нагрузку на систему, чтобы вам не пришлось выбирать из этого большого количества данных (попробуйте другое время суток, загрузка пользователей на разные серверы,...)

обведите проблему, как только вы сможете воспроизвести

Теперь, как только вы сможете воспроизвести, нужно пройтись по парку, чтобы найти реальную причину. Вы можете найти параметр, который вызывает ошибку, путем проб и ошибок или путем сравнения ее с другими запросами, вызвавшими ошибку, также для поиска сходств. И тогда вы можете увидеть, что делает этот параметр, какие библиотеки ему доступны и т.д. Вы можете отключить каждый компонент по одному, который использует этот параметр, пока вы больше не сможете воспроизвести его. Затем вы получили свой компонент и можете погрузиться в проблему глубже.

Расскажите, что вы нашли. Мне любопытно, -).

Ответ 2

У меня тоже была такая ошибка. Выяснилось, что я вернул объект sql в свой класс сеанса (который использовался session_handler) вместо того, чтобы ничего не возвращать или, по крайней мере, не являться объектом sql. Сначала загляните в свои методы _write и _read, если вы тоже вернете некоторые неправильные вещи.

Примечание:... Неизвестно в строке 0 - Как найти правильную строку, это НЕ "строка 0"

Ответ 3

Вместо того, чтобы обертывать код в блоке try/catch, что происходит, когда вы регистрируете обработчик исключений? Очевидно, что ваш блок try/catch не перехватывает исключение, что приводит к ошибкам, зарегистрированным в Apache. Регистрируя обработчик, вы можете быть уверены, что любое неперехваченное исключение обрабатывается.

Кроме того, если вы используете пространства имен в своем приложении, убедитесь, что вы пишете \Exception в своем блоке catch (или включаете класс Exception с помощью инструкции использования).

Ответ 4

Это может быть немного поздно, но одна проблема, которую я обнаружил при перемещении сайта с локального на удаленный сервер. Я использовал Concrete5 cms, разработал мой сайт локально (Windows 8 в xampp), а затем загрузился на удаленный сервер, на котором запущен Cent 0S

Windows mysql по умолчанию нечувствителен к регистру и создает базу данных в нижнем регистре. Как только это было загружено на удаленный сервер, я получил "Исключение, которое было выбрано без рамки стека в Unknown в строке 0?"

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

Ответ 5

Для нас эта ошибка возникла из-за непреднамеренного сериализации объектов SimpleXML.

Если вы используете объекты SimpleXML с 5.3.3, убедитесь, что вы выбрали значения node для того, что вам нужно (например, строка), если вы сериализуете значения в сеансе.

До

  $token = $response->Token->Value;
  /* token saved in session, results in line 0 error */

После:

$token = (string) $response->Token->Value;
  /* token saved in session, no error */

Ответ 6

Я понимаю, что на этот вопрос уже был дан ответ, но я добавлю это, поскольку он может кому-то помочь:

Мне удалось (непреднамеренно) произвести ошибки без фрейма стека из функции, которая использовала свой собственный обработчик ошибок для поддержания контроля над выполнением при вызове потенциально "опасной" функции, например:

// Assume the function my_error_handler() has been defined to convert any
// PHP Errors, Warnings, or Notices into Exceptions.

function foo() {
    // maintain control if danger() crashes outright:
    set_error_handler('my_error_handler');

    try {
        // Do some stuff.

        $r = danger();
    } catch (Exception $e) {
        $r = 'Bad Stuff, Man!';
    }

    restore error_handler();
    return $r;
}

"Неотслеживаемый сбой" произойдет в конце выполнения программы, если логика в "Do some stuff" возвращается из foo() напрямую, минуя вызов функции restore_error_handler(). То, что я убрал из опыта, таково:

  • PHP поддерживает стек обработчиков ошибок, который становится все глубже/выше при каждом вызове set_error_handler().
  • Плохие вещи могут произойти, если вы нажимаете обработчики ошибок на стек и не очищаете себя, прежде чем программа выйдет "нормально".

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

Итак, как бы я отследил это, зная, что я знаю сейчас? Поскольку я не знаю, как можно напрямую проверять "стек" обработчика ошибок PHP, я думаю, что имеет смысл использовать объект Singleton для инкапсуляции всех операций set/restore для обработчиков ошибок PHP. По крайней мере, тогда можно было бы проверить состояние Singleton до выхода из программы в обычном режиме, и если обнаружены "оборванные" обработчики ошибок для генерации разумного сообщения об ошибке/предупреждении до того, как PHP выйдет из строя.

Ответ 7

У меня была такая же ошибка: появилась поддержка сервера с centos 5 до centos 6 и понижение PHP с 5.4 до 5.3. Фактической проблемой был PHP apc, не настроенный должным образом. Проверьте свою APC. Я использовал Symfony2, поэтому вы можете найти некоторую помощь в Symfony Невозможно выделить память для пула

Ответ 8

один простой способ произвести эту ошибку - старый сервер с register_globals = On. то вам нужны только две строки кода:

<?php
    $_SESSION["my_var"] = "string";
    $my_var = new MyClass(); //could be any class, i guess
?>

как только вы перезагрузите эту страницу один раз, вы получите сообщение об ошибке Exception thrown without a stack frame in Unknown on line 0. похоже, что существует конфликт между экземпляром класса и переменной (session).
по крайней мере, так я получил эту досадную ошибку, которую так сложно отлаживать.

Ответ 9

У меня была полная ошибка. Очень пространственный случай: если вы подключите крюк неназванной функции (замыкания) к точке крюка объекта. После этого вы попытаетесь сериализовать этот объект.

Ответ 10

Эта проблема возникла для меня, когда я сменил пространство имен на нескольких пакетах Symfony. Удаление файлов в каталоге кеша Symfony устранило проблему.

Ответ 11

Вероятно, у вас есть коррумпированная/несогласованная таблица в базе данных. Попробуйте сбросить базу данных. Если вы получите сообщение об ошибке времени. Отремонтируйте эту таблицу и проблему следует уйти.

Именно по этой причине работает чистая установка. Чистая установка просто чиста.

mysqlcheck должен работать, но если он не отображается и проблема все еще делает выше.

Ответ 12

У меня была та же ошибка после неправильного заполнения свойства Fillable модели Illuminate Eloquent. Обратите внимание на последние 3 элемента массива, в одном отсутствует кома.

protected $fillable = [
    'budget',        
    'routestatus' ,
    'userroutenumber'
    'totalmovingseconds',
    'totalidleseconds'
];