PHP健壮包括处理错误吗?
我有一个PHP应用程序“index.PHP”,出于各种原因,需要在另一个脚本上使用PHP健壮包括处理错误吗?,php,exception,include,Php,Exception,Include,我有一个PHP应用程序“index.PHP”,出于各种原因,需要在另一个脚本上使用include\u once运行其他PHP脚本。另一个脚本不是很稳定,那么是否有某种方法可以安全地执行一次include_,而不会停止调用程序 i、 e: (我知道这是个多么糟糕的主意,等等,请放心,这不是生产环境的东西。)您可以 @include "fileWithBadSyntax.php"; 在我的快速测试中,它既适用于解析错误,也适用于使用trigger_error()抛出的错误 编辑:这是完全错误的
include\u once
运行其他PHP脚本。另一个脚本不是很稳定,那么是否有某种方法可以安全地执行一次include_,而不会停止调用程序
i、 e:
(我知道这是个多么糟糕的主意,等等,请放心,这不是生产环境的东西。)您可以
@include "fileWithBadSyntax.php";
在我的快速测试中,它既适用于解析错误,也适用于使用trigger_error()抛出的错误
编辑:这是完全错误的。请参阅Sleek的答案,这是正确的,尽管有些无益。是否可以更改您的体系结构并将“badfile.php”转换为web服务?您可以通过网络调用它并解析或包含其输出,而不是将其直接包含到代码库中。这将使您绕过解析错误,如果您对badfile.php的环境进行了适当的限制(使用安全模式,或以有限的权限运行单独的web服务器进程),还可以避免潜在的恶意代码。您可以执行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";
}
?>
在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();
}
这些答案都不起作用。如果包含的文件中存在解析错误,则排名靠前的脚本(表示为@include())仍将终止第一个脚本
您不能eval()它,也不能尝试/捕获它,调用include或require的所有方法都将终止脚本中的所有执行
这个问题仍然悬而未决
这是PHP中的一个bug,至少从2006年起,这个功能就消失了。他们将这个bug归类为“伪造的”,因为他们声称,include()和requires()发生在编译时
如果您在运行时生成include()和/或require()的字符串参数,或者对包含运行include()的代码的字符串执行eval(),则此窗口将关闭。以下是我能够找到的唯一真正的解决方案:
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()仍将停止。您必须阅读内容,祈祷相关文件不包含()或进一步要求(),然后评估它
真正的解决方案是什么?跳过PHP:/ 找不到包含文件的优雅解决方法
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" );
}
功能安全要求($incfile,$showfn=1){
$a=explode(“:”,get_include_path());
$a[]=”;
$b=0;
foreach($a为$p){
如果(!empty($p))$p=“/”;
$f=$p.$incfile;
如果(文件_存在($f)){
$b=1;
打破
}
}
如果(!$b)
退出(“无法继续,需要文件”。
(($showfn)“$incfile:”)不可用或服务器已超时
);
要求一次(“f”);
}
唯一真正的解决方案(虽然不是最优雅的解决方案,但很有效)是调用另一个php解释器来解析和执行脚本,只需检查它是否产生解析错误或未检测到错误的消息,以过滤错误消息,如php parse error Bla。类似于此代码:
<?php
function ChkInc($file){
return file_exists($file) && (substr(exec("php -l $file"), 0, 28) == "No syntax errors detected in");
}
?>
这个想法来源于PHP文档中的函数手册页。见第二个答案,@selk是对的,你不能捕获requires/includes
我对自动加载require的解决方案是使用error\u get\u last,因此只需将其添加到基本文件中(这将处理来自requires/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
});
是否执行此任务,是否可以使用此方法捕获错误详细信息?此方法将使所有错误保持沉默。请参阅KyleFarris的答案,以了解将捕获错误并可选择性地使其保持沉默的方法(即自定义错误处理)事实上,Kyle的答案是更有力的,只是某人投票赞成,我不敢相信我写了它。如果它不是被接受的答案,我会删除它。一个解析错误将停止PHP在被包含的文件的中间,它不会返回到<代码> catch < /Cord>块。@ Pix0R:这当然是可行的,但是取决于它的项目范围。Wordpress肯定有办法做到这一点。如果你激活一个有语法错误或产生警告/致命错误的插件,它会告诉你并继续脚本(禁用插件并显示错误消息)。例如:“插件无法激活,因为它触发了致命错误。”虽然我相信它是通过iframe欺骗实现的,但这并不理想。但我不确定。Graben的答案,使用带有-f
标志的解释器命令行,会起作用。它速度慢,看起来像是一个黑客,但它确实完成了任务。对于提到的bug报告,有没有值得一读的评论。这是唯一的方法,currently.使用if
返回true或false?这听起来像是疯了吗?将解决方案转换为一行代码有什么错:return(substr(exec(“php-l$file”),0,28)=“中未检测到语法错误”);
?ChkInc(/tmp;rm-rf/);添加了文件_existscheck for skill comment,但在一个像样的应用程序中达到此功能时,用户输入验证应该已经完成。很好,但仍然无法通过。假设在验证文件存在后删除该文件。。。。
<?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
});