Uploaded image for project: 'phpBB'
  1. phpBB
  2. PHPBB-9720

BBcodes not parsed if message grows over 100000 characters while BBcode-UID is appended

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: Minor Minor
    • 3.2.0
    • 3.0.7-PL1
    • BBCode Engine, Posting
    • None
    • PHP 5.3.1, MySQL 5.1.41, Opera 10.54 / Firefox 3.0.5

      Problem: If e.g. we have a posting text of 76524 characters which includes 359 pairs of [URL=..][IMG] tags and then is encapsulated in one [U] tag phpBB will fail to parse the [U] tag.

      Reason: while processing the text each tag gets a UID appended, so the text grows - and at some point exceeds 100000 characters. After this point no more tags get parsed, since all preg_xxx() functions won't give any result (because internally PREG fails). Most PHP settings default to have a PREG backtrace limit of 100000 characters and phpBB never calls preg_last_error() to check for failures (note: failures, not regexp pattern errors).

      Workaround: in "/includes/message_parser.php" function parse_bbcode()'s core goes like this:

      foreach ($bbcode_data['regexp'] as $regexp => $replacement)
      {
      	// The pattern gets compiled and cached by the PCRE extension,
      	// it should not demand recompilation
      	if (preg_match($regexp, $this->message))
      	{
      		$this->message = preg_replace($regexp, $replacement, $this->message);
      		$bitfield->set($bbcode_data['bbcode_id']);
      	}
      }

      To check for PREG failures we can already check preg_match() since this also fails once the text length exceeds the limit. If we only check for a backtrack limit failure we can try to increase the limit for a couple of times. How often and in which steps we increment the limit might be subject of another discussion:

      foreach ($bbcode_data['regexp'] as $regexp => $replacement)
      {
      	$iSet= 0;  // How often did we set a new limit
      	while( $iSet< 10 ) {  // On default values like 100000 the highest new limit would be 250000
      		// The pattern gets compiled and cached by the PCRE extension,
      		// it should not demand recompilation
      		if (preg_match($regexp, $this->message))
      		{
      			$this->message = preg_replace($regexp, $replacement, $this->message);
      			$bitfield->set($bbcode_data['bbcode_id']);
      		}
       
      		if( preg_last_error()== PREG_BACKTRACK_LIMIT_ERROR ) {  // Only check for backtrack limit failure
      			ini_set( 'pcre.backtrack_limit', (int)ini_get( 'pcre.backtrack_limit' )+ 15000 );  // Get current limit and increase
      			$iSet++;  // Do not overkill the server
      		} else break;  // No fail, exit loop
      	}
      }

            Marc Marc
            AmigoJack AmigoJack
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: