PHP强大包括处理错误?

时间:2009-10-06 18:48:22

标签: php exception include

我有一个PHP应用程序“index.php”,由于各种原因,需要在其他脚本上使用include_once来运行其他PHP脚本。那个其他脚本不是很稳定,有没有办法做一个不会停止调用者的安全include_once

即:

<?php

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

?>

(我知道这可能是个坏主意,等等,请放心,这不是生产环境的事情。)

9 个答案:

答案 0 :(得分:36)

这些答案都不起作用。如果在包含的文件中存在解析错误,那么对@include()说的最高投票者仍将终止第一个脚本。

你不能eval()它,你不能尝试/捕获它,并且每种调用include或require的方式都将在脚本中终止所有执行。

这个问题仍然是开放的,没有解决。

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

这是PHP中的一个错误,至少自2006年以来这个功能一直缺失。他们将错误归类为“虚假”,因为他们声称,包括()和require()在编译时发生。

如果要在RUNTIME生成include()和/或require()的字符串参数,或者在包含运行include()的代码的字符串上执行eval(),则会出现窗口。

答案 1 :(得分:10)

唯一真正的解决方案,不是最优雅的解决方案,而是工作是调用另一个解析和执行脚本的PHP解释器,除了检查它是否产生解析错误或检测到无错误消息以过滤错误消息像PHP Parse Error blablabla。像这样的代码:

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

这个想法来自PHP文档的gillis' commentinclude功能手册页。

答案 2 :(得分:6)

你可以

@include "fileWithBadSyntax.php";

根据我的快速测试,它适用于解析错误或使用trigger_error()抛出的错误。

编辑:这是完全错误的。看看潜行的答案,这是正确的,如果有点无益的话。

答案 3 :(得分:2)

是否可以更改您的体系结构并将“badfile.php”转换为Web服务?您可以通过网络调用它并解析或包含其输出,而不是将其直接包含在您的代码库中。这将解决您的解析错误,如果您的badfile.php环境受到适当限制(使用safe_mode,或运行具有有限权限的单独Web服务器进程),您还可以避免潜在的恶意代码。

答案 4 :(得分:2)

您可以尝试/捕捉阻止

<?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

答案 5 :(得分:2)

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" );
}

答案 6 :(得分:0)

请参阅第二个答案,@ sneak是正确的,您不能理解要求/包含。

我对自动加载要求的解决方案是使用error_get_last,因此只需将其添加到基本文件中即可(此操作将处理来自诸如自动加载/子类之类的require / include的解析错误:

<?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      
});

答案 7 :(得分:-1)

在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();
 }

答案 8 :(得分:-3)

这是我能找到的唯一真正的解决方案:

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);'); 

...因为eval'd字符串中的require()仍然停止。你必须阅读内容,祈祷有问题的文件不包括()或require(),eval()它。

真正的解决方案?跳过PHP。 :/