0

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);
            }
        }
  • 1
    _...I have created the template engine..._ Why reinventing the wheel? Just take some TE like smarty or slim and do your stuff without any concerns about the code. Remember you want to make a "forum software" - NOT a template engine ;) – B001ᛦ Jul 25 '20 at 21:10
  • Two reasons really, first of all, in the forums software, if I allow the users to use php within the template, then it will pose a great security risk to it. And the other reason is because I want to create a template engine. The main reason I program is to learn different ways to do things, so I am making a template engine to learn how I would go about it. – Jackson Roberts Jul 25 '20 at 21:13
  • 1
    The only correct answer to this question (which has been asked ....a lot) is, "Don't". If you dont trust us, see this highly voted question https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags Dont do it. Use the the right tools for the job.... or post the forum link here so we all know to avoid it lest our personal details fall victim to your hubris. – Wesley Smith Jul 25 '20 at 23:01

2 Answers2

1

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.

SirPilan
  • 4,649
  • 2
  • 13
  • 26
  • While I very much value your input, all you have done is work around my my example. With the block of php code you provided, I will not be able to do what I could with mine. You remove the loop to find all matches and replace them which won't work with my system. I also need to be able to put in any condition with any amount of html code in between which is my issue. I cannot put a large chunk of html code because the <>'s will break it. And it is a template engine, not posts, so bbcode will not do what I want, this isn't markup. – Jackson Roberts Jul 26 '20 at 00:50
  • So you want to have multiple ifs in a single `$content` right? I've updated the answer. – SirPilan Jul 26 '20 at 00:55
  • The `$content` is a file with html contents in it, but there is also my template engine tags in there. So yes, I will need to be able to have multiple ifs in a single `$content`. I will also need to be able to have as many lines of html code within the if statement as possible. – Jackson Roberts Jul 26 '20 at 00:58
  • You can add as much ifs and html as you like now :) - just not use ifs within an if - ill keave that for you. – SirPilan Jul 26 '20 at 01:01
  • I bet, happy coding :) Try your best, if you get stuck feel free to create a new question. – SirPilan Jul 26 '20 at 01:06
  • Honestly, you are the only one who has encouraged me on this site. Everyone else has either said "Just use a premade template engine" or "Just use PHP". Thank you and I will. – Jackson Roberts Jul 26 '20 at 01:07
  • There are a lot of people here which act like "do this for me". If you try, and show you tried, people are happy to help. A template engine is a good exercise - but indeed wouldnt use it for production, since established ones are way safer and more performant - since prooven over time and by many people. – SirPilan Jul 26 '20 at 01:17
  • Pilan, you will be happy to hear that after a bit of tinkering around, I figured out what I needed to do to fix my issue. turns out all I had to do was add /ims to the end of my regex statement and everything worked =D – Jackson Roberts Jul 26 '20 at 01:40
  • It won’t allow me to accept my answer until tomorrow. – Jackson Roberts Jul 26 '20 at 13:52
0

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
  • Thanks for sharing, sadly this does not solve the [if within if](https://regex101.com/r/zWBVAC/1) issue :/ - tip, you cant solve nested elements with a single regex. Furthermore: you only need the `s` option :) – SirPilan Jul 26 '20 at 02:03
  • Thank you for informing me. But I will do some tinkering with the regex statement to accommodate for if within if statements – Jackson Roberts Jul 26 '20 at 02:07