NaughtySquid NaughtySquid - 1 year ago 57
PHP Question

How to remove all bbcode quote blocks by a specific user from a text?

I'm looking to remove quotes made with BBCode in PHP, like this example:

[quote=testuser]
[quote=anotheruser]a sdasdsa dfv rdfgrgre gzdf vrdg[/quote]
sdfsd fdsf dsf sdf[/quote]
the rest of the post text


I'm looking at doing a blocking system, so users don't have to see content from those they don't want to. So say "testuser" is blocked, they don't want that entire quoted part, including the second quote nested inside as that's part of the main quote.

So the post would be left with only:


the rest of the post text


I'm wondering on the best way to do it this. I was hoping regex, but it's more complicated that I thought, I have this attempt:

/\[quote\=testuser\](.*)\[\/quote\]/is


However, that then captures all end quote tags.

Is there an alternative method that's fast, or a good fix for my regex?

To sum up: Remove the initial quote from the blocked user and everything inside that quote, but nothing else outside it.

Answer Source

This is no simple process as far as I can tell. Here are my steps...

  1. Use preg_split() to divide input string 3 ways: opening quote tags, closing quote tags, and other. I am splitting on the opening and closing tags, but using DELIM_CAPTURE to keep them in the output array and in the original position/order. NO_EMPTY is used so that there are no useless iterations in the foreach loop to follow.
  2. Loop through the generated array and search for the user's name to be omitted.
  3. When a quote by the targeted user is found, store the starting index of that element, and set $open to 1.
  4. Whenever a new opening quote tag is found $open is incremented.
  5. Whenever a new closing quote tag is found $open is decremented.
  6. As soon as $open reaches 0, the $start and end indices are fed to range() to generate an array filled with numbers between the two points.
  7. array_flip(), of course, moves the values to keys.
  8. array_diff_key() removes the range of points from the array generated by preg_split().
  9. If all things go smoothly, implode() will glue the substrings back together retaining only the desired components.

Code: (Demo)

$omit='testuser';
/*$bbcode='[quote=testuser]
[quote=anotheruser]a sdasdsa dfv rdfgrgre gzdf vrdg[/quote]
sdfsd fdsf dsf sdf[/quote]
the rest of the test';*/

$bbcode='[quote=mickmackusa]Keep this[/quote]
[quote=testuser]Don\'t keep this because 
    [quote=mickmackusa]said don\'t do it[/quote]
    ... like that\'s a good reason
    [quote=NaughtySquid] It\'s tricky business, no?[/quote]
    [quote=nester][quote=nesty][quote=nested][/quote][/quote][/quote]
[/quote]
Let\'s remove a second set of quotes
[quote=testuser]Another quote block[/quote]
[quote=mickmackusa]Let\'s do a third quote inside of my quote...
[quote=testuser]Another quote block[/quote]
[/quote]
This should be good, but
What if [quote=testuser]quotes himself [quote=testuser] inside of his own[/quote] quote[/quote]?';

$substrings=preg_split('~(\[/?quote[^]]*\])~',$bbcode,NULL,PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);

foreach($substrings as $index=>$substring){
    if(!isset($start) && $substring=="[quote={$omit}]"){  // protect against nested quotes by the same user
        $start=$index;  // begin range of points to be omitted
        $opens=1;       // count how many open tags have been found
    }elseif(isset($start)){
        if(strpos($substring,'[quote=')!==false){  // check for any opening tag
            ++$opens;  // increment
        }elseif(strpos($substring,'[/quote]')!==false){  // check for any closing tag
            --$opens;  // decrement
            if($opens==0){  // if started tag sequence is balanced and closed
                $substrings=array_diff_key($substrings,array_flip(range($start,$index)));  // modify the original array
                unset($start);  // clear $start so the process can repeat
            }elseif($opens<0){  // check for imbalance in the quote tags
                echo 'Uh oh, something went wrong (too many end tags)';
            }
        }
    }
}
if($opens){  // check for imbalance in the quote tags
    echo 'Uh oh, something went wrong (not enough end tags)';
}else{
    var_export(trim(implode($substrings)));
}

Output:

'[quote=mickmackusa]Keep this[/quote]

Let\'s remove a second set of quotes

[quote=mickmackusa]Let\'s do a third quote inside of my quote...

[/quote]
This should be good, but
What if ?'
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download