Jackson Roberts
Jackson Roberts

Reputation: 31

How do I insert html code into a php regex?

So I am currently in the middle of making a forums software. Something that I wanted for that forums software was a custom template engine. For the most part I have created the template engine, but I am having a small issue with the regex that I use for my IF, ELSEIF, and FOREACH statements.

The issue that I am having is that when I put a chunk of html code in to my regex, nothing will work. Here is an example: https://regex101.com/r/jlawz3/1.

Here is the PHP code that checks for the regex.

        $isMatchedAgain = preg_match_all('/{IF:(.*?)}[\s]*?(.*?)[\s]*?{ELSE}[\s]*?(.*?)[\s]*?{ENDIF}/', $this->template, $elseifmatches);
        for ($i = 0; $i < count($elseifmatches[0]); $i++) {
            $condition = $elseifmatches[1][$i];
            $trueval   = $elseifmatches[2][$i];
            $falseval  = (isset($elseifmatches[3][$i])) ? $elseifmatches[3][$i] : false;
            $res = eval('return ('.$condition.');');
            if ($res===true) {
                $this->template = str_replace($elseifmatches[0][$i],$trueval,$this->template);
            } else {
                $this->template = str_replace($elseifmatches[0][$i],$falseval,$this->template);
            }
        }

Upvotes: 0

Views: 78

Answers (2)

Jackson Roberts
Jackson Roberts

Reputation: 31

So after a bit of research, I have figured out that the issue I was facing could be solved by adding /ims to the end of my regex statement. So now my regex statement looks like:

/{IF:(.*?)}[\s]*?(.*?)[\s]*?{ELSE}[\s]*?(.*?)[\s]*?{ENDIF}/ims

Upvotes: 0

SirPilan
SirPilan

Reputation: 4837

You can do it like this:

function render($content) {
    $match = preg_match_all('/{IF:\((.*?)\)}(.*?){ELSE}(.*?)({ENDIF})/s', $content, $matches, PREG_OFFSET_CAPTURE);

    if (!$match) {
        return $content;
    }
    
    $beforeIf = substr($content, 0, $matches[0][0][1]);
    $afterIf = substr($content, $matches[4][0][1] + strlen('{ENDIF}'));
    $evalCondition = eval('return (' . $matches[1][0][0] . ');');
    
    if ($evalCondition) {
        $ifResult = $matches[2][0][0];
    } else {
        $ifResult = $matches[3][0][0];
    }
    
    return
        $beforeIf .
        $ifResult .
        render($afterIf);
}

Working example.

This is a first step. This wont work for example if you have an if within an if.

Talking about mentioned security risk. Since we are using eval (nickname EVIL - for a reason). You should never ever ever process user-input through eval - or use eval at all - there is always a better solution.

For me it looks like you want to give users the ability to write "code" in their posts. If this is the case you can have a look at something like bbcode.

Whatever you do be sure to provide the desired functionality. Taking your example:

!isset($_SESSION['loggedin'])

You could do something like this:

{IS_LOGGED_IN}
    Output whatever you want :)
{/IS_LOGGED_IN}

Your renderer would look specificly for this tag and act accordingly.

Upvotes: 1

Related Questions