mirror of
https://github.com/phpbb/phpbb.git
synced 2025-04-20 07:42:09 +02:00
[ticket/13880] Automatically remove quotes that are nested too deep
PHPBB3-13880
This commit is contained in:
parent
7d7b536874
commit
817db2f135
@ -791,28 +791,6 @@ class bbcode_firstpass extends bbcode
|
||||
else if (preg_match('#^quote(?:="(.*?)")?$#is', $buffer, $m) && substr($out, -1, 1) == '[')
|
||||
{
|
||||
$this->parsed_items['quote']++;
|
||||
|
||||
// the buffer holds a valid opening tag
|
||||
if ($config['max_quote_depth'] && sizeof($close_tags) >= $config['max_quote_depth'])
|
||||
{
|
||||
if ($config['max_quote_depth'] == 1)
|
||||
{
|
||||
// Depth 1 - no nesting is allowed
|
||||
$error_ary['quote_depth'] = $user->lang('QUOTE_NO_NESTING');
|
||||
}
|
||||
else
|
||||
{
|
||||
// There are too many nested quotes
|
||||
$error_ary['quote_depth'] = $user->lang('QUOTE_DEPTH_EXCEEDED', (int) $config['max_quote_depth']);
|
||||
}
|
||||
|
||||
$out .= $buffer . $tok;
|
||||
$tok = '[]';
|
||||
$buffer = '';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
array_push($close_tags, '/quote:' . $this->bbcode_uid);
|
||||
|
||||
if (isset($m[1]) && $m[1])
|
||||
@ -1277,6 +1255,12 @@ class parse_message extends bbcode_firstpass
|
||||
return $update_this_message ? $this->warn_msg : $return_message;
|
||||
}
|
||||
|
||||
// Remove quotes that are nested too deep
|
||||
if ($config['max_quote_depth'] > 0)
|
||||
{
|
||||
$this->remove_nested_quotes($config['max_quote_depth']);
|
||||
}
|
||||
|
||||
// Check for "empty" message. We do not check here for maximum length, because bbcode, smilies, etc. can add to the length.
|
||||
// The maximum length check happened before any parsings.
|
||||
if ($mode === 'post' && utf8_clean_string($this->message) === '')
|
||||
@ -1855,6 +1839,50 @@ class parse_message extends bbcode_firstpass
|
||||
$poll['poll_max_options'] = ($poll['poll_max_options'] < 1) ? 1 : (($poll['poll_max_options'] > $config['max_poll_options']) ? $config['max_poll_options'] : $poll['poll_max_options']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove nested quotes at given depth in current parsed message
|
||||
*
|
||||
* @param integer $max_depth Depth limit
|
||||
* @return null
|
||||
*/
|
||||
public function remove_nested_quotes($max_depth)
|
||||
{
|
||||
// Capture all [quote] and [/quote] tags
|
||||
preg_match_all('(\\[/?quote(?:=[^]]+)?:' . $this->bbcode_uid . '\\])', $this->message, $matches, PREG_OFFSET_CAPTURE);
|
||||
|
||||
// Iterate over the quote tags to mark the ranges that must be removed
|
||||
$depth = 0;
|
||||
$ranges = array();
|
||||
$start_pos = 0;
|
||||
foreach ($matches[0] as $match)
|
||||
{
|
||||
if ($match[0][1] === '/')
|
||||
{
|
||||
--$depth;
|
||||
if ($depth == $max_depth)
|
||||
{
|
||||
$end_pos = $match[1] + strlen($match[0]);
|
||||
$length = $end_pos - $start_pos;
|
||||
$ranges[] = array($start_pos, $length);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++$depth;
|
||||
if ($depth == $max_depth + 1)
|
||||
{
|
||||
$start_pos = $match[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array_reverse($ranges) as $range)
|
||||
{
|
||||
list($start_pos, $length) = $range;
|
||||
$this->message = substr_replace($this->message, '', $start_pos, $length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter function for passing the plupload object
|
||||
*
|
||||
|
@ -1579,11 +1579,21 @@ if (!sizeof($error) && $preview)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove quotes that would become nested too deep before decoding the text
|
||||
$generate_quote = ($mode == 'quote' && !$submit && !$preview && !$refresh);
|
||||
if ($generate_quote && $config['max_quote_depth'] > 0)
|
||||
{
|
||||
$tmp_bbcode_uid = $message_parser->bbcode_uid;
|
||||
$message_parser->bbcode_uid = $post_data['bbcode_uid'];
|
||||
$message_parser->remove_nested_quotes($config['max_quote_depth'] - 1);
|
||||
$message_parser->bbcode_uid = $tmp_bbcode_uid;
|
||||
}
|
||||
|
||||
// Decode text for message display
|
||||
$post_data['bbcode_uid'] = ($mode == 'quote' && !$preview && !$refresh && !sizeof($error)) ? $post_data['bbcode_uid'] : $message_parser->bbcode_uid;
|
||||
$message_parser->decode_message($post_data['bbcode_uid']);
|
||||
|
||||
if ($mode == 'quote' && !$submit && !$preview && !$refresh)
|
||||
if ($generate_quote)
|
||||
{
|
||||
if ($config['allow_bbcode'])
|
||||
{
|
||||
|
@ -59,4 +59,85 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case
|
||||
'Your subject contains the following unsupported characters'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox max_quote_depth is applied to the text populating the posting form
|
||||
*/
|
||||
public function test_quote_depth_form()
|
||||
{
|
||||
$text = '0[quote]1[quote]2[/quote]1[/quote]0';
|
||||
$expected = array(
|
||||
0 => '[quote="admin"]0[quote]1[quote]2[/quote]1[/quote]0[/quote]',
|
||||
1 => '[quote="admin"]00[/quote]',
|
||||
2 => '[quote="admin"]0[quote]11[/quote]0[/quote]',
|
||||
3 => '[quote="admin"]0[quote]1[quote]2[/quote]1[/quote]0[/quote]',
|
||||
);
|
||||
|
||||
$this->login();
|
||||
$topic = $this->create_topic(2, 'Test Topic 1', 'Test topic');
|
||||
$post = $this->create_post(2, $topic['topic_id'], 'Re: Test Topic 1', $text);
|
||||
$quote_url = "posting.php?mode=quote&f=2&t={$post['topic_id']}&p={$post['post_id']}&sid={$this->sid}";
|
||||
|
||||
$this->admin_login();
|
||||
foreach ($expected as $quote_depth => $expected_text)
|
||||
{
|
||||
$this->set_quote_depth($quote_depth);
|
||||
$crawler = self::request('GET', $quote_url);
|
||||
$this->assertContains($expected_text, $crawler->filter('textarea#message')->text());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox max_quote_depth is applied to the submitted text
|
||||
*/
|
||||
public function test_quote_depth_submit()
|
||||
{
|
||||
$text = 'depth:0[quote]depth:1[quote]depth:2[quote]depth:3[/quote][/quote][/quote]';
|
||||
$contains = array(
|
||||
0 => array('depth:0', 'depth:1', 'depth:2', 'depth:3'),
|
||||
1 => array('depth:0', 'depth:1'),
|
||||
2 => array('depth:0', 'depth:1', 'depth:2'),
|
||||
3 => array('depth:0', 'depth:1', 'depth:2', 'depth:3'),
|
||||
);
|
||||
$not_contains = array(
|
||||
0 => array(),
|
||||
1 => array('depth:2', 'depth:3'),
|
||||
2 => array('depth:3'),
|
||||
3 => array(),
|
||||
);
|
||||
|
||||
$this->login();
|
||||
$this->admin_login();
|
||||
$topic = $this->create_topic(2, 'Test Topic 1', 'Test topic');
|
||||
|
||||
for ($quote_depth = 0; $quote_depth <= 2; ++$quote_depth)
|
||||
{
|
||||
$this->set_quote_depth($quote_depth);
|
||||
|
||||
$post = $this->create_post(2, $topic['topic_id'], 'Re: Test Topic 1', $text);
|
||||
$url = "viewtopic.php?p={$post['post_id']}&sid={$this->sid}";
|
||||
|
||||
$crawler = self::request('GET', $url);
|
||||
$text_content = $crawler->filter('#p' . $post['post_id'])->text();
|
||||
foreach ($contains[$quote_depth] as $contains_text)
|
||||
{
|
||||
$this->assertContains($contains_text, $text_content);
|
||||
}
|
||||
foreach ($not_contains[$quote_depth] as $not_contains_text)
|
||||
{
|
||||
$this->assertNotContains($not_contains_text, $text_content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function set_quote_depth($depth)
|
||||
{
|
||||
$crawler = self::request('GET', 'adm/index.php?sid=' . $this->sid . '&i=acp_board&mode=post');
|
||||
$form = $crawler->selectButton('Submit')->form();
|
||||
$values = $form->getValues();
|
||||
$values['config[max_quote_depth]'] = $depth;
|
||||
$form->setValues($values);
|
||||
$crawler = self::submit($form);
|
||||
$this->assertEquals(1, $crawler->filter('.successbox')->count());
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user