Search code examples
phperror-handlingevalpreg-replace-callback

How handle eval errors inside of preg-replace-callback


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!


Solution

  • 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.