Надежный ли PHP для обработки ошибок? - PullRequest
14 голосов
/ 06 октября 2009

У меня есть приложение PHP «index.php», которое по разным причинам должно запускать другие сценарии PHP с использованием include_once для этого другого сценария. Этот другой скрипт не очень стабилен, так есть ли какой-нибудь способ сделать сейф include_once, который не остановит вызывающего?

т.е:.

<?php

safely_include_once('badfile.php'); // MAY throw syntax error, parse error, other badness
echo "I can continue execution after error";

?>

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

Ответы [ 9 ]

36 голосов
/ 02 июля 2010

Ни один из этих ответов не будет работать. Голосующий с наибольшим числом голосов, который говорит @include (), все равно завершит работу первого сценария, если во включенном файле есть ошибка синтаксического анализа.

Вы не можете выполнить eval (), вы не можете попробовать / перехватить его, и каждый способ вызова include или require прекратит все выполнение в скрипте.

Этот вопрос остается открытым и неразрешенным.

http://bugs.php.net/bug.php?id=41810

Это ошибка в PHP, и эта функциональность отсутствует по крайней мере с 2006 года. Они классифицировали ошибку как «поддельную», потому что, по их утверждению, include () и require () происходят во время компиляции.

Это выходит из окна, если вы генерируете строковые аргументы для include () и / или require () в RUNTIME или выполняете eval () над строкой, содержащей код, который выполняет include ().

10 голосов
/ 10 декабря 2012

Единственное реальное решение, которое считается не самым элегантным, но работающим, - это вызвать другого интерпретатора php, который анализирует и выполняет скрипт, просто проверяя, не приводит ли он к ошибке синтаксического анализа или сообщению об отсутствии ошибок для фильтрации сообщений об ошибках например PHP Parse Error, блаблабла. как этот код делает:

<?php
function ChkInc($file){
   return file_exists($file) && (substr(exec("php -l $file"), 0, 28) == "No syntax errors detected in");
}
?>

Эта идея появилась из gillis 'комментария к include странице руководства по функциям в PHP doc.

6 голосов
/ 06 октября 2009

Вы можете просто

@include "fileWithBadSyntax.php";

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

РЕДАКТИРОВАТЬ : Это совершенно неправильно. См. Ответ украдкой, который является правильным, хотя и несколько бесполезным.

2 голосов
/ 22 ноября 2010

Изящный обходной путь для include-file-not-found ....

function safe_require( $incfile, $showfn=1 ) {
  $a = explode( ":", get_include_path() ) ;
  $a[] = "";
  $b = 0;
  foreach( $a as $p ) {
    if( !empty( $p )) $p .= "/";
    $f = $p.$incfile;
    if( file_exists( $f )) {
      $b = 1;
      break;
    }
  }
  if( !$b ) 
    exit( "Cannot proceed, required file " . 
          (($showfn) ? $incfile : "" ) . " is unavailable or server has timed out." 
        );
  require_once( "$f" );
}
2 голосов
/ 06 октября 2009

Вы можете сделать блок try / catch

<?php
try {
    include("someFile.php");
} catch (Exception $e) {
    // Should probably write it to a log file, but... for brevity's sake:
    echo 'Caught exception: ',  $e->getMessage(), "\n";
}
?>

Теперь он будет включать файл, только если нет ошибки. Если есть ошибка, он просто пропустит этот материал и запишет исключение (например, в комментариях, желательно в файл журнала или что-то в этом роде).

Для получения дополнительной информации: http://us2.php.net/manual/en/language.exceptions.php

2 голосов
/ 06 октября 2009

Можно ли изменить вашу архитектуру и превратить "badfile.php" в веб-сервис? Вместо того, чтобы включать его непосредственно в вашу кодовую базу, вы вызываете его по сети и анализируете или включаете его вывод. Это поможет вам избежать ошибок синтаксического анализа, вы также можете избежать потенциально вредоносного кода, если у вас соответствующим образом ограничена среда badfile.php (используется safe_mode или запущен отдельный процесс веб-сервера с ограниченными правами).

0 голосов
/ 07 декабря 2018

См. Второй ответ, @sneak прав, вы не можете поймать требует / включает.

Моим решением для автозагрузки require было использование error_get_last, поэтому просто добавьте это в базовый файл (тогда он будет обрабатывать ошибки синтаксического анализа из require / include, включенных такими вещами, как классы auto-load / child:

<?php 
    register_shutdown_function( "fatal_handler" );
    function fatal_handler() 
    {
        $error = error_get_last();  
        if($error !== NULL) 
        {
            if(isset($error['type']) && ($error['type'] === E_ERROR  || $error['type'] === 1 || $error['type'] === 2 || $error['type'] === 3 || $error['type'] === 4))
            {
                // do what you need to do here to make safe, I just log and use that log (to make sure other tests dont run in my case)
                Some_Class::logErrorToFile('fatal_error:' . json_encode($error));
                file_put_contents('somp_file_path_that_all_other_classes_check', 'fatal_error:' . json_encode($error));
            }
            else
            {
                Some_Class::logErrorToFile('error:' . json_encode($error)); 
            }
        }
        return;
    }

spl_autoload_register(function ($classname) {
    $classPath = str_replace("_", "/", $classname);
    $path = dirname(__FILE__) . '/../'.$classPath.'.php';
    require_once($path);  // fatal errors are logged for this runtime require, will not actually stop execution for this case, but we can handle how we deal with that now      
});
0 голосов
/ 05 июля 2010

Вот единственное реальное решение, которое мне удалось найти:

function safe_include($fn) {
        $fc = file_get_contents($fn);
        if(!eval($fc)) {
                return 0;
        }
        return 1;
}

Обратите внимание, что приведенный выше код означает, что вы должны извлечь вступительные заявления из файлов, которые вы хотите включить, или сделать следующее:

eval("?>" . $fc)

Проблема в том, что вы не можете вызывать require () или include () или их варианты _once () в любой момент и ожидать, что они не завершат все , включая любые обработчики ошибок. PHP полностью прекратит обработку всего, когда он обнаружит ошибку разбора.

Единственным исключением из этого является строка внутри eval (). Однако проблема в том, что вы не можете сделать это:

eval('require($fn);'); 

... потому что require () внутри строки eval'd будет все еще stop. Вы должны прочитать содержание, молиться о том, чтобы данный файл не включал () и не требовал () далее, и eval ().

Реальное решение? Пропустить PHP. : /

0 голосов
/ 07 октября 2009

В badfile.php вы можете заставить его возвращать значение:

<?php
//inestable instructions.


return true; ?>

тогда в основном файле вы можете сделать:

 <?php

 if (require($badFile)) {
     //if it was true continue with normal execution
 } else {
     echo "Error: ". error_get_last();
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...