0

I have an HTML string mixed with PHP codes. so i want to just do evaluation of the codes that it possible and replace it back there. My idea is something like this :

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

and it works fine.

But if my code have an error, like this:

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

instead of just leaving the place blank, it will make the $html string blank.

PHP >5.4

any way to handle it?

Best regards!

Barmar
  • 741,623
  • 53
  • 500
  • 612
MMMahdy-PAPION
  • 915
  • 10
  • 15

2 Answers2

0

you set $html to "" in catch . must change your code like follow :

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

you get fatal error and you must handle somehow that; this is just a test code for you to understand the way:

<?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');
S.Kashizadeh
  • 563
  • 4
  • 14
  • Dear @user122293 your solution not work fine with my case. but your edit and talking about fatal-error helped me to find the problem. so i answer to my question. thanks! – MMMahdy-PAPION Oct 05 '19 at 08:18
0

As @user122293 said, the problem is about difference between fatal errors and other errors.

In PHP <7 fatal errors are not catch-able.

Also, there is no any Exception for fatal errors even in PHP >=7

Now we have some ways (from best to worst):

  • A) Making sure we use PHP 7 or higher and change the code to something like this :
$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;

to output will be:

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

the important part in my case was using Throwable / Error in catch. as the explanation here: https://stackoverflow.com/a/48381661/7514010

  • B) & C) If we have access to exec function. we try the code first, then use it. or even save the file temporary and execute it for test. (Look crazy!)

or

Send the code as a query to a tester and get the result and then run it. (It can not work because some PHP code tags can depend to each other and should evaluate in same script.) Both explained here : https://stackoverflow.com/a/33531067/7514010

  • D) Using register_shutdown_function + crazy way to force PHP 5 to at last have get the html again or even run next lines. Like this example : https://3v4l.org/0R7dq

    • +E) Make a function for parsing manually before eval or include using regex parsing and function_exists or method_exists or etc... or any library.
MMMahdy-PAPION
  • 915
  • 10
  • 15