Custom BB Codes

enouwee

Non ex transverso sed deorsum
Reaction score
239
If anyone has the patience to explain me, please :). For example, a thing I would like to know would be how to make the url tag. Because, in the url tag you can pass 2 arguments (link and the actual text) and I am confused at it.

Here's the basic matching code, so you can see, what it does:

PHP:
<?php

$string = '[a url="test"]this[B]a test[/a]';

if (preg_match(',\[(a|img)\s+url="([^"]*)"\](.*?)\[/\1\],i', $string, $matches))
{
        print_r($matches);
}

?>

There are tons of ways to proceed from here. I'd add PREG_OFFSET_CAPTURE to the flags passed to preg_match() and replace the BBCode, including URL and body after a thorough validation using substr_replace().
 

enouwee

Non ex transverso sed deorsum
Reaction score
239
You know, you got me even deeper in the fog xD.

No problem, I bet everything will be much clearer, once you see this. It's very easy, didn't even take 30 minutes to write: :D

PHP:
<?php

$string = 'XX[a url="test"]this[B]a test[/a]YY';
$string .= 'ZZ[img url="my_test"]this an image test[/img]TT';

if (preg_match_all(',\[([a-z]+)\s+url="([^"]*)"\](.*?)\[/\1\],i', $string, $matches, PREG_OFFSET_CAPTURE))
{
        for ($i = count($matches[0]) - 1; $i >= 0; $i--)
        {
                $valid = true;

                $len = strlen($matches[0][$i][0]);
                $pos = $matches[0][$i][1];

                $tag = strtolower($matches[1][$i][0]);
                switch ($tag)
                {
                        case 'a':
                        case 'img':
                                // filter your other valid tags here
                                break;
                        default:
                                $valid = false;
                }

                if ($valid == true)
                {
                        // process URL part
                        $url = $matches[2][$i][0];

                        if (empty($url))
                        {
                                $valid = false;
                        }

                        // do other validation here
                }

                if ($valid == true)
                {
                        // process body part
                        $body = $matches[3][$i][0];

                        if (empty($body))
                        {
                                $valid = false;
                        }

                        // do other validation here
                }

                if ($valid)
                {
                        switch ($tag)
                        {
                                case 'img':
                                        $output = '<img src="' . $url . '" alt="' . $body . '" />';
                                        break;
                                case 'a':
                                        $output = '<a href="' . $url . '">' . $body . '</a>';
                                        break;
                        }
                }
                else
                {
                        $output = '';
                }

                $string = substr_replace($string, $output, $pos, $len);

                print "ITERATION USING MATCH $i:\n";
                print "$string\n\n";
        }

        print "FINAL RESULT:\n$string\n";
}


?>
 

monoVertex

I'm back!
Reaction score
460
Meh, I started to understand these functions better. I made myself a piece of code which is supposed to replace the url tags.

PHP:
$text = preg_replace('/(\[url=) (.*?) (\]) (.*?) (\[\/url\])/i','<a href="$2">$4</a>',$text);

I see no syntax problem, and it's supposed to work... However, the url tags are still displayed as literal on the page...
 

enouwee

Non ex transverso sed deorsum
Reaction score
239
PHP:
$text = preg_replace('/(\[url=) (.*?) (\]) (.*?) (\[\/url\])/i','<a href="$2">$4</a>',$text);

I see no syntax problem, and it's supposed to work... However, the url tags are still displayed as literal on the page...

What are you trying to do? I see a lot of useless spaces in that expression.

If you want to replace something like this:
[url.=THIS_IS_MY_URL]THIS IS MY TEXT[/url.] (ignore . due to parsing problem)

better use an expression like:
PHP:
$text = preg_replace(',\[url=\s*(.*?)\s*\]\s*(.*?)\s*\[/url\],i','<a href="$1">$2</a>',$text);

Note that some captures are useless, as you don't use them and \s* matches any number of whitespaces, including 0.
 

monoVertex

I'm back!
Reaction score
460
Thank you! One more question :D. If there are line breaks inside the tags, they are not parsed. How cam I make the function to ignore line breaks?
 

enouwee

Non ex transverso sed deorsum
Reaction score
239
Thank you! One more question :D. If there are line breaks inside the tags, they are not parsed. How cam I make the function to ignore line breaks?

If you want the "." to match newlines, you have to add a "s" modifier, like:
Code:
/line1.*line2/s
Alternatively, the "m" modifier changes the behaviour of "^" to match every "begin of line" and not only the "begin of the string".

The full list of supported modifiers is:
http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php
 

monoVertex

I'm back!
Reaction score
460
Hmmm... It's not supposed to match new lines, I can have something like this:

Code:
[font.=verdana]test


test
test
test

test
[/verdana]

This is not parsed and the first "test" is not on a new line.

EDIT: Nvm, studied that list and understood, it's all working now, thanks a lot!
 

enouwee

Non ex transverso sed deorsum
Reaction score
239
EDIT: Nvm, studied that list and understood, it's all working now, thanks a lot!

This works like a charm:

PHP:
<?php

$string ='[font=verdana]test


test
test
test

test
[/font]';

print_r(preg_replace('!\[font=(.*?)\](.*?)\[/font\]!is', '<font face="$1">$2</font>', $string));

?>
 

enouwee

Non ex transverso sed deorsum
Reaction score
239
Yeah, I saw that :D. Gotta spread first :(. You are credited on the page, anyway :D.

If you want to implement your BBCode like that, please don't put my name next to it. phyrex1an already said it the previous posts, I'm going to repeat it:
Don't blindly use that preg_replace() thing without any additional validation steps, as your code will be vulnerable to XSS (cross-site scripting) attacks.

You have to filter both inputs, either by limiting the choices or filtering out malicious content. Rather than saying "(.*?)", you'd use "(arial|times|courier)" to set the font family from a given subset. preg_replace_callback() allows you to do post-processing on the matches: a callback function generates the replacement string.

I put a much larger piece of code in #23, which takes the whole input apart and later replaces it (without preg_replace_callback(), but essentially, both do the same). You can transform and validate the fields as you like before they're inserted back into the text.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top