PHP надежный включает в себя обработку ошибок?

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

то есть:.

<?php

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

?>

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

Ответы

Ответ 1

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

@include "fileWithBadSyntax.php";

Что из моих быстрых тестов работает как с ошибками синтаксического анализа, так и с ошибками, вызванными trigger_error().

EDIT: Это совершенно неправильно. См. Секретный ответ, который является правильным, если несколько бесполезным.

Ответ 2

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

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

Этот вопрос остается открытым и НЕ РАЗРЕШЕН.

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

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

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

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

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

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

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

Ответ 6

Изящное обходное решение для 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" );
}

Ответ 7

Смотрите второй ответ, @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      
});

Ответ 8

В файле 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();
 }

Ответ 9

Здесь единственное реальное решение, которое я смог найти:

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 все равно остановится. Вы должны прочитать содержимое, молись, чтобы этот файл не включал() или require() далее, и eval().

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