如何处理 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_exists 或 method_exists 等等...或任何图书馆。
我有一个 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_exists 或 method_exists 等等...或任何图书馆。