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

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

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

Кто-то прокомментировал, что это случилось с ними, потому что их первичный ключ должен был быть CHAR (32) вместо INT (11) . PK в этом приложении – это 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)); } 

Пойду по достоинству оценят любые советы по этому поводу!

EDIT: PHP работает как модуль Apache (Server API: обработчик Apache 2.0). Я не думаю, что есть какие-то ускорители PHP, но я просто не знаю, как это сказать. Ни один из перечисленных в Википедии не находится в phpinfo ().

Насколько я могу судить, MPM – это предки. Это первое, что я когда-либо рассматривал в MPM:

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

Проблема

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

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

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

  • Скорее всего, этого достаточно, если вы знаете все параметры 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 в качестве замены для даты (). Проверьте свой веб-сервер, если вы можете получить что-то более точное, чем секунды в журнале ошибок. Напишите свою собственную реализацию «хвоста», которая даст вам более точную отметку времени … Уменьшите нагрузку на систему, чтобы вам не пришлось выбирать из этого большого количества данных (попробуйте другое время суток, загрузка пользователей на разные серверы, …)

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

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

Расскажите нам, что вы нашли. Мне интересно ;-).

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

Примечание: … Неизвестно в строке 0 – Как найти правильную строку, это НЕ «строка 0»,

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

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

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

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

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

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

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

До :

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

После :

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

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

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

 // 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 (). То, что я убрал из опыта, таково:

  1. PHP поддерживает стек обработчиков ошибок, который становится все глубже / выше при каждом вызове set_error_handler ().
  2. Bad Stuff может произойти, если вы нажимаете обработчики ошибок на стек и не очищаетесь после себя, прежде чем программа выйдет «нормально».

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

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

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

один простой способ произвести эту ошибку – старый сервер с 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).
по крайней мере, так я получил эту досадную ошибку, которую так сложно отлаживать.

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

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

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

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

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