如何处理 preg-replace-callback 中的 eval 错误

How handle eval errors inside of preg-replace-callback

我有一个 HTML 字符串 PHP 代码 混合。所以我只想对可能的代码进行评估,然后将其替换回去。我的想法是这样的:

$html='Hi it <b>PAPION</b>. Now timestamp is <?php echo time(); ?>. have a good time.';
$html = preg_replace_callback('/(<\?php)(.*?)(\?>)/ims',function($matches){
    try {
        ob_start();
        eval($matches[2]); 
        return ob_get_clean();
    } catch(Exception $e) {
        return "";
    }
}, $html);

而且效果很好。

但是如果我的代码有错误,像这样:

$html='Hi it <b>PAPION</b>. Now timestamp is <?php echo xxtime(); ?>. have a good time.';
$html = preg_replace_callback('/(<\?php)(.*?)(\?>)/ims',function($matches){
    try {
        ob_start();
        eval($matches[2]); 
        return ob_get_clean();
    } catch(Exception $e) {
        return "";
    }
}, $html);

而不是只将该位置留空,它会使 $html 字符串留空。

PHP >5.4

有什么办法处理吗?

此致!

您在 catch 中将 $html 设置为 "" 。必须像下面这样更改您的代码:

$html='Hi it <b>PAPION</b>. Now timestamp is <?php echo xxtime(); ?>. have a good time.';

preg_match('/(<\?php)(.*?)(\?>)/ims', $html, $matches);

$html = str_replace($matches[2], getEvalOutput($matches[2]), html);

echo "html is ".$html;

function getEvalOutput($matche){
    try {
        ob_start();
        eval($matche); 
        return ob_get_clean();
    } catch(Exception $e) {
        return " ERROR happened";
    }
}

你遇到致命错误,你必须以某种方式处理它;这只是一个测试代码,供您理解方式:

<?php 

$phpCode = "
<?php
set_error_handler('myErrorHandler');
register_shutdown_function('fatalErrorShutdownHandler');
function myErrorHandler($code, $message, $file, $line) {
    echo $message;
}
function fatalErrorShutdownHandler()
{
  $last_error = error_get_last();
  if ($last_error['type'] === E_ERROR) {
    // fatal error
    myErrorHandler(E_ERROR, $last_error['message'], $last_error['file'], $last_error['line']);
  }
}
$html='Hi it <b>PAPION</b>. Now timestamp is <?php echo xxtime(); ?>. have a good time.';
$html = preg_replace_callback('/(<\?php)(.*?)(\?>)/ims',function($matches){
    try {
        ob_start();
        eval($matches[2]); 
        return ob_get_clean();
    } catch(Exception $e) {
    }
}, $html);
echo $html;";

file_put_contents('a.php', $phpCode);
$x = exec( 'php a.php');
echo $x;
/* delete the file */
unlink('a.php');

正如@user122293 所说,问题是关于致命错误 和其他错误之间的区别。

在 PHP 中 <7 个致命错误无法捕获。

此外,即使在 PHP >=7

中也没有任何致命错误的异常

现在我们有一些方法(从最好到最差):

  • A) 确保我们使用 PHP 7 或更高版本并将代码更改为如下内容:
$html='Hi it is <b>PAPION</b>. Now timestamp is <?php echo time(); ?>. have a good time. a can be: <?php a=b*2 ?>. and wrong timestamp is <?php xxxxtime(); ?>.';
      $html = preg_replace_callback('/(<\?php)(.*?)(\?>)/ims',function($matches){
        try {
            ob_start();
            eval($matches[2]); 
            return ob_get_clean();
        } catch(Throwable $e) {
            return "";
        }
    }, $html);
    echo $html;

输出将是:

Hi it is PAPION. Now timestamp is 1570282086. have a good time. a can be: . and wrong timestamp is .

在我的案例中,重要的部分是在 catch 中使用 Throwable / Error。作为此处的解释:

  • B) & C) 如果我们可以访问 exec 函数。我们先尝试代码,然后再使用它。甚至临时保存文件并执行它进行测试。 (看起来很疯狂!)

将代码作为查询发送给测试人员并获得结果,然后 运行 它。 (它不能工作,因为一些 PHP 代码标签可以相互依赖并且应该在同一个脚本中计算。) 两者都在这里解释:

  • D)使用register_shutdown_function+疯逼的方式PHP 5 最后得到 html 甚至 运行 下一行。 像这个例子: https://3v4l.org/0R7dq

    • +E) 在 eval 之前创建一个用于手动解析的函数,或者包括使用 regex 解析和 function_existsmethod_exists 等等...或任何图书馆。