Forum Moderators: coopster

Message Too Old, No Replies

custom BB code problem

         

Readie

4:15 am on Feb 12, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



On my fabled admin panel, with it's news post writer that I keep referencing, I use some custom BB code for a few basic format tools. I use the following code:

$symb = array();
$symb[0] = '/&/';
$symb[1] = "/[\/\\\\]'/";
$symb[2] = '/[\/\\\\]"/';
$symb[3] = '/</';
$symb[4] = '/>/';
...snip - lots of symbols here like (vowel) acute etc...
$symb[75] = "/'/";
$symb[76] = '/"/';
$symb[77] = '/[\r\n]{4,}/m';
$symb[78] = '/[\r\n]{2,}/m';
$symb[79] = '/\[b\]/';
$symb[80] = '/\[\/b\]/';
$symb[81] = '/\[i\]/';
$symb[82] = '/\[\/i\]/';
$symb[83] = '/\[u\]/';
$symb[84] = '/\[\/u\]/';
$symb[85] = '/\[img\]/';
$symb[86] = '/\[\/img\]/';
$symb[87] = '/\[url=\(/';
$symb[88] = '/\[urlblank=\(/';
$symb[89] = '/\)\]/';
$symb[90] = '/\[\/url\]/';

$repl = array();
$repl[0] = '&#38;';
$repl[1] = '&#39;';
$repl[2] = '&#34;';
$repl[3] = '&#60;';
$repl[4] = '&#62;';
...snip...
$repl[75] = '&#39;';
$repl[76] = '&#34;';
$repl[77] = '</p><p>';
$repl[78] = '<br />';
$repl[79] = '<b>';
$repl[80] = '</b>';
$repl[81] = '<i>';
$repl[82] = '</i>';
$repl[83] = '<u>';
$repl[84] = '</u>';
$repl[85] = '<img border="0" src="';
$repl[86] = '" />';
$repl[87] = '<a href="';
$repl[88] = '<a target="_blank" href="';
$repl[89] = '">';
$repl[90] = '</a>';

ksort($symb);
ksort($repl);


And then apply the BB code like so:

$content = preg_replace($symb, $repl, mysql_result($result,0,"content"));

Now, it recently occured to me that this presents a bit of a problem. If someone only enters the first part of the BB code, and either fails to enter the second part, or enters it incorrectly, it could rather mess up the rest of the page content.

I would be apreciative if someone could offer advice on how to combat this problem short of a massive number of 'if statements'

TheMadScientist

10:16 am on Feb 12, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



[ quote ]

Well, let me think about it for a minute...
[ quote ]
My guess is they ran into something similar here [ /small ] it's just a hunch, but I'm guessing there's a way to do it and I really typed this post and previewing it to see what they were doing here now, because they've updated the software lately and right now all I can say is 'wow, they did a good job'.

What you're asking is difficult to do, and it's very difficult to do efficiently, because it's quite a bit like checking HTML for proper formatting and my guess is they're using some AJAXY type stuff here to do it...

Copy, paste, preview this post without the spaces in the tags to see what I'm saying, then remove one of the opening quote tags and preview again or type and preview your own miss formatted post a few times with different tags unclosed.

In thinking about it, the simplest way is probably to check for a closed tag any time there's an opening tag and if a closing tag is not found ignore the opening tag, which requires a bunch of if statements, or a loop with an if... I can't think of an easier way to do it, but maybe someone else can.

Readie

8:24 pm on Feb 12, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Ok, I tried the following function, but it doesn't work :/ I'll post it here incase I've made a mistake I can't see

And yeah scientist - I've seen the failsafes and error highlighting they have here and I must say I'm impressed too.

function bb_code($input) {
$bb_a_a = array();
$bb_a_a[0] = '[\[b\]]{1}';
$bb_a_a[1] = '[\[i\]]{1}';
$bb_a_a[2] = '[\[u\]]{1}';
$bb_a_a[3] = '[\[url=\(]{1}';
$bb_a_a[4] = '[\[urlblank=\(]{1}';
$bb_a_a[5] = '[\[img\]]{1}';

$bb_a_b = array();
$bb_a_b[0] = '';
$bb_a_b[1] = '';
$bb_a_b[2] = '';
$bb_a_b[3] = '[\)\]]{1}';
$bb_a_b[4] = '[\)\]]{1}';
$bb_a_b[5] = '';

$bb_a_c = array();
$bb_a_c[0] = '[\[\/b\]]{1}/';
$bb_a_c[1] = '[\[\/i\]]{1}/';
$bb_a_c[2] = '[\[\/u\]]{1}/';
$bb_a_c[3] = '[\[\/url\]]{1}/';
$bb_a_c[4] = '[\[\/url\]]{1}/';
$bb_a_c[5] = '[\[\/img\]]{1}/';

$bb_b_a = array();
$bb_b_a[0] = '<b>';
$bb_b_a[1] = '<i>';
$bb_b_a[2] = '<u>';
$bb_b_a[3] = '<a href="';
$bb_b_a[4] = '<a target="blank" href="';
$bb_b_a[5] = '<img border="0" src="';

$bb_b_b = array();
$bb_b_b[0] = '';
$bb_b_b[1] = '';
$bb_b_b[2] = '';
$bb_b_b[3] = '">';
$bb_b_b[4] = '">';
$bb_b_b[5] = '';

$bb_b_c = array();
$bb_b_c[0] = '</b>';
$bb_b_c[1] = '</i>';
$bb_b_c[2] = '</u>';
$bb_b_c[3] = '</a>';
$bb_b_c[4] = '</a>';
$bb_b_c[5] = '" />';

ksort($bb_a_a);
ksort($bb_a_b);
ksort($bb_a_c);
ksort($bb_b_a);
ksort($bb_b_b);
ksort($bb_b_c);

$count = count($bb_a_a);

for($i = 0; $i < $count; $i++) {
$bb_c[$i] = $bb_a_a[$i] . '[^' . $bb_a_b[$i] . '][^' . $bb_a_c[$i] . ']' . $bb_a_a[$i];
if((preg_match('/$bb_a_a[$i]/', $input) && preg_match('/$bb_a_b[$i]/', $input) && preg_match('/$bb_a_c[$i]/', $input)) && !preg_match('/$bb_c[$i]/', $input)) {
preg_replace('/$bb_a_a[$i]/', $bb_b_a[$i], $input);
if($bb_a_b[$i] != "") {
preg_replace('/$bb_a_b[$i]/', $bb_b_b[$i], $input);
}
preg_replace('/$bb_a_c[$i]/', $bb_b_c[$i], $input);
}
}
return $input;
}

Readie

2:38 am on Feb 13, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Ok, I have thought of a (very contingent on replies though) way to do this.

If I use the code:

function bb_code($input) {
$bb_a = array();
$bb_a[0] = '/^\[b\].*\[\/b\]/';
$bb_a[1] = '/^\[i\].*\[\/i\]/';
$bb_a[2] = '/^\[u\].*\[\/u\]/';
$bb_a[3] = '/^\[img\].*\[\/img\]/';
$bb_a[4] = '/^\[url=\(.*\)\].*\[\/url\]/';
$bb_a[5] = '/^\[urlblank=\(.*\)\].*\[\/url\]/';
$count = count($bb_a);

for($i = 0; $i < $count; $i++) {
$recs = preg_match_all($bb_a[$i], $input);
if($recs && $recs != 0) {
for($ii = 0; $ii < $recs; $ii++) {
/* Stuck here! */
}
}
}

}


Is there anyway for me to capture the value of the [DOT-ASTERIX(es)] ( .* ) within the inner nested for loop?

Readie

5:50 am on Feb 13, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I believe this may be the first triple post I've ever done...

Anyways, using the following script I've (nearly) got it working correctly (for simple open and close tags), I'm just having a great deal of trouble with the regex. I need it to say
Find: ([u]) (anything but [u]) ([/u])
But it's not liking all my attempts at writing that (it's picking up on the first open and first close it can find) - so if anyone could help me out there I'd be very much obliged.

function bb_code($input) {
$bb_a = array();
$bb_a[0] = '/^[\[b\]][^\[b\]][\[\/b\]]/';
$bb_a[1] = '/^[\[i\]][^\[i\]][\[\/i\]]/';
$bb_a[2] = '/^[\[u\]][^\[u\]][\[\/u\]]/';

$count = count($bb_a);

$bb_b_a = array();
$bb_b_a[0] = '[ b ]';
$bb_b_a[1] = '[u]';
$bb_b_a[2] = '[ i ]';

$bb_b_b = array();
$bb_b_b[0] = '<b>';
$bb_b_b[1] = '<u>';
$bb_b_b[2] = '<i>';

$bb_c_a = array();
$bb_c_a[0] = '[ /b ]';
$bb_c_a[1] = '[/u]';
$bb_c_a[2] = '[ /i ]';

$bb_c_b = array();
$bb_c_b[0] = '</b>';
$bb_c_b[1] = '</u>';
$bb_c_b[2] = '</i>';

$char = array();
$char[0] = '\\';
$char[1] = '^';
$char[2] = '$';
$char[3] = '.';
$char[4] = '|';
$char[5] = '?';
$char[6] = '*';
$char[7] = '+';
$char[8] = '(';
$char[9] = ')';
$char[10] = '[';
$char[11] = ']';
$char[12] = '/';
$char[13] = '{';
$char[14] = '}';

$char_o = array();
$char_o[0] = '/\/\\\\/';
$char_o[1] = '/\^/';
$char_o[2] = '/\$/';
$char_o[3] = '/\./';
$char_o[4] = '/\|/';
$char_o[5] = '/\?/';
$char_o[6] = '/\*/';
$char_o[7] = '/\+/';
$char_o[8] = '/\(/';
$char_o[9] = '/\)/';
$char_o[10] = '/\[/';
$char_o[11] = '/\]/';
$char_o[12] = '/\//';
$char_o[13] = '/\{/';
$char_o[14] = '/\}/';

$char_r = array();
$char_r[0] = '&#92;';
$char_r[1] = '&#94;';
$char_r[2] = '&#36;';
$char_r[3] = '&#46;';
$char_r[4] = '&#124;';
$char_r[5] = '&#63;';
$char_r[6] = '&#42;';
$char_r[7] = '&#43;';
$char_r[8] = '&#40;';
$char_r[9] = '&#41;';
$char_r[10] = '&#91;';
$char_r[11] = '&#93;';
$char_r[12] = '&#47;';
$char_r[13] = '&#123;';
$char_r[14] = '&#125;';

ksort($char);
ksort($char_o);
ksort($char_r);

$c_count = count($char);

$input = preg_replace($char_o, $char_r, $input);

for($i = 0; $i < $count; $i++) {
$bb_b_a[$i] = preg_replace($char_o, $char_r, $bb_b_a[$i]);
$bb_b_a[$i] = '/' . $bb_b_a[$i] . '/';
$bb_b_b[$i] = preg_replace($char_o, $char_r, $bb_b_b[$i]);
$bb_c_a[$i] = preg_replace($char_o, $char_r, $bb_c_a[$i]);
$bb_c_a[$i] = '/' . $bb_c_a[$i] . '/';
$bb_c_b[$i] = preg_replace($char_o, $char_r, $bb_c_b[$i]);
$splits = preg_split($bb_a[$i], $input);
foreach($splits as $split) {
$split_s = preg_replace($bb_b_a[$i], $bb_b_b[$i], $split);
$split_s = preg_replace($bb_c_a[$i], $bb_c_b[$i], $split_s);
$split = '/' . $split . '/';
$input = preg_replace($split, $split_s, $input);
}
}
for($i = 0; $i < $c_count; $i++) {
$char_r[$i] = '/' . $char_r[$i] . '/';
}
$input = preg_replace($char_r, $char, $input);
return $input;
}

Readie

3:24 am on Feb 14, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Woohoo! Persistence always pays off in the end.

After many trials and tribulations I managed to come up with the following function. It removes open tags with no closers, closing tags with no openers and replaces the 2 closest together matching tags.

function bb_code($input) {

$bb_a_a[0] = '[ b]';
$bb_a_a[1] = '[u]';
$bb_a_a[2] = '[ i]';
$bb_a_a[3] = '[img]';

$bb_a_b[0] = '<b>';
$bb_a_b[1] = '<u>';
$bb_a_b[2] = '<i>';
$bb_a_b[3] = '<img border="0" src="';

$bb_b_a[0] = '[ /b]';
$bb_b_a[1] = '[/u]';
$bb_b_a[2] = '[ /i]';
$bb_b_a[3] = '[/img]';

$bb_b_b[0] = '</b>';
$bb_b_b[1] = '</u>';
$bb_b_b[2] = '</i>';
$bb_b_b[3] = '">';

$bb_b_c[0] = '/\[\/b\]/';
$bb_b_c[1] = '/\[\/u\]/';
$bb_b_c[2] = '/\[\/i\]/';
$bb_b_c[3] = '/\[\/img\]/';

$count = count($bb_a_a);

for($i = 0; $i < $count; $i++) {
$inse = explode($bb_a_a[$i], $input);
$icount = count($inse);
$input = '';
for($ii = 0; $ii < $icount; $ii++) {
if(preg_match($bb_b_c[$i], $inse[$ii])) {
$match = explode($bb_b_a[$i], $inse[$ii]);
$matchnum = count($match);
if($matchnum <= 2) {
$inse[$ii] = preg_replace($bb_b_c[$i], $bb_b_b[$i], $inse[$ii]);
$inse[$ii] = $bb_a_b[$i] . $inse[$ii];
} else {
$ins = explode($bb_b_a[$i], $inse[$ii]);
$iicount = count($ins);
$inse[$ii] = $bb_a_b[$i] . $ins[0] . $bb_b_b[$i];
for($iii = 1; $iii < $iicount; $iii++) {
$inse[$ii] .= $ins[$iii];
}
}
}
$input .= $inse[$ii];
}
}
return $input;
}


With the following code (minus spaces on b and i bb tags)

$content = '[ b][ b]Oranges [ i]and[ /b][img] lot\'s[ /i] of [u]apples[/u][ /i][img]/imag[ /i]es/down.png[/img].';
$content = bb_code($content);
echo $content;


Outputs the following:

<b>Oranges <i>and</b> lot's</i> of <u>apples</u><img border="0" src="/images/down.png">.


My apologies for the masses of code I've posted in this thread by the way :)

Now I just need to work out the "3 piece" BB code function to accompany this one

Readie

6:38 am on Feb 14, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Writing this may have taken an unhealthy length of time infront of the computer, writing this may have made me swear at the screen a lot, writing this may have nearly reduced me to tears, but I've finally finished writing this, and it work's beautifully, and I'm high-fiving myself inside my head :D

[size=1]function bb_code($input) {

$bb_a_a[0] = '[ b]';
$bb_a_a[1] = '[u]';
$bb_a_a[2] = '[ i]';
$bb_a_a[3] = '[img]';

$bb_a_b[0] = '<b>';
$bb_a_b[1] = '<u>';
$bb_a_b[2] = '<i>';
$bb_a_b[3] = '<img border="0" src="';

$bb_b_a[0] = '[ /b]';
$bb_b_a[1] = '[/u]';
$bb_b_a[2] = '[ /i]';
$bb_b_a[3] = '[/img]';

$bb_b_b[0] = '</b>';
$bb_b_b[1] = '</u>';
$bb_b_b[2] = '</i>';
$bb_b_b[3] = '">';

$bb_b_c[0] = '/\[\/b\]/';
$bb_b_c[1] = '/\[\/u\]/';
$bb_b_c[2] = '/\[\/i\]/';
$bb_b_c[3] = '/\[\/img\]/';

$count = count($bb_a_a);

for($i = 0; $i < $count; $i++) {
$inse = explode($bb_a_a[$i], $input);
$icount = count($inse);
$input = '';
for($ii = 0; $ii < $icount; $ii++) {
if(preg_match($bb_b_c[$i], $inse[$ii])) {
$match = explode($bb_b_a[$i], $inse[$ii]);
$matchnum = count($match);
if($matchnum <= 2) {
$inse[$ii] = preg_replace($bb_b_c[$i], $bb_b_b[$i], $inse[$ii]);
$inse[$ii] = $bb_a_b[$i] . $inse[$ii];
} else {
$ins = explode($bb_b_a[$i], $inse[$ii]);
$iicount = count($ins);
$inse[$ii] = $bb_a_b[$i] . $ins[0] . $bb_b_b[$i];
for($iii = 1; $iii < $iicount; $iii++) {
$inse[$ii] .= $ins[$iii];
}
}
}
$input .= $inse[$ii];
}
}

$bb_c_a[0] = '[url=(';
$bb_c_a[1] = '[urlblank=(';

$bb_c_b[0] = '<a href="';
$bb_c_b[1] = '<a target="_blank" href="';

$bb_d_a[0] = ')]';
$bb_d_a[1] = ')]';

$bb_d_b[0] = '">';
$bb_d_b[1] = '">';

$bb_d_c[0] = '/\)\]/';
$bb_d_c[1] = '/\)\]/';

$bb_e_a[0] = '[/url]';
$bb_e_a[1] = '[/url]';

$bb_e_b[0] = '</a>';
$bb_e_b[1] = '</a>';

$bb_e_c[0] = '/\[\/url\]/';
$bb_e_c[1] = '/\[\/url\]/';

$count = count($bb_c_a);

for($i = 0; $i < $count; $i++) {
$inse = explode($bb_c_a[$i], $input);
$icount = count($inse);
$input = '';
for($ii = 0; $ii < $icount; $ii++) {
if(preg_match($bb_e_c[$i], $inse[$ii])) {
$ins = explode($bb_e_a[$i], $inse[$ii]);
$iicount = count($ins);
$inse[$ii] = '';
for($iii = 0; $iii < $iicount; $iii++) {
if(preg_match($bb_d_c[$i], $ins[$iii])) {
$match = explode($bb_d_a[$i], $ins[$iii]);
$matchnum = count($match);
if($matchnum <= 2) {
$ins[$iii] = preg_replace($bb_d_c[$i], $bb_d_b[$i], $ins[$iii]);
$ins[$iii] = $bb_c_b[$i] . $ins[$iii];
} else {
$in = explode($bb_d_a[$i], $ins[$iii]);
$iiicount = count($in);
$ins[$iii] = $bb_c_b[$i] . $in[0] . $bb_d_b[$i];
for($iiii = 1; $iiii < $iiicount; $iiii++) {
$ins[$iii] .= $in[$iiii];
}
}
$ins[$iii] = $ins[$iii] . $bb_e_b[$i];
}
$inse[$ii] .= $ins[$iii];
}
}
$input .= $inse[$ii];
}
}
return $input;
}[/size]

Readie

4:08 pm on Feb 14, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Ok, if anyone decides to use this code, be aware there's a slight logical flaw in the second clump of code (for the 3-piece BB code)

First, the urlblank needs to be closed with a tag that differs from the url closing tag.

Second, the following code:

if(preg_match($bb_d_c[$i], $ins[$iii])) {


Needs to be:

if(preg_match($bb_d_c[$i], $ins[$iii]) && $iii == 0) {


Otherwise the similar syntax for url and urlblank (
[xx=()]
) produces some... Interesting... results

And finally, it is, in my opinion, worth adding the following in just above the return command:

for($i = 0; $i < $count; $i++) {
$input = preg_replace($bb_e_c[$i], '', $input);
}
return $input;


To remove closing tags with no opener.