Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F1828
Bug1310.patch
Public
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Authored By
•
bzimport
Nov 21 2014, 8:11 PM
2014-11-21 20:11:40 (UTC+0)
Size
5 KB
Referenced Files
None
Subscribers
None
Bug1310.patch
View Options
Index: tests/phpunit/includes/parser/NestingTest.php
===================================================================
--- tests/phpunit/includes/parser/NestingTest.php (revision 0)
+++ tests/phpunit/includes/parser/NestingTest.php (revision 0)
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @group Parser
+ */
+class NestingTest extends MediaWikiTestCase {
+
+ function provideCases() {
+ return array(
+ array( "<foo>123</foo>", "foo", "123", array() ),
+ array( "<foo>foo</foo>", "foo", "foo", array() ),
+ array( "A<foo>foo</Foo>B", "foo", "foo", array() ),
+ array( "A<foo a=1 b='foo'>123<foo>456</foo>789</foo>B", "foo", "123<foo>456</foo>789", array( "a" => "1", "b" => "foo" ) ),
+ array( "<foo<foo", "foo", null, null ),
+
+ array(
+ "<ref name=\"citation:1\">" .
+ "<ref name=\"Other2001\"/>" .
+ "<ref name=\"YetAnother2004\"/>" .
+ "</ref>",
+ "ref", "<ref name=\"Other2001\"/><ref name=\"YetAnother2004\"/>", array( "name" => "citation:1" )
+ ),
+
+ array( "<ref name='x' foo ><ref/></ref >", "ref", "<ref/>", array( "name" => "x", "foo" => "foo" ) )
+
+
+ );
+ }
+
+ function provideNotWorkingCases() {
+ return array(
+ array( "<foo a='<foo>'>123</foo>", "foo", null, null ),
+ array( "<foo foo='123'>123<!--</foo>-->456</foo>", "foo", "123456", array( "foo" => "123" ) ),
+ );
+ }
+
+ var $mInnerText;
+ var $mParams;
+
+ /**
+ * @dataProvider provideCases
+ */
+ function testCases( $wikiText, $tag, $expectedInnerText, $expectedParams ) {
+ global $wgParserConf;
+ $parser = new Parser( $wgParserConf );
+
+ $parser->setHook( $tag, array( $this, 'tagCallback' ) );
+ $parserOutput = $parser->parse( $wikiText, Title::newFromText( 'Test' ), new ParserOptions );
+
+ $this->assertEquals( $expectedInnerText, $this->mInnerText );
+ $this->assertEquals( $expectedParams, $this->mParams );
+
+ $parser->mPreprocessor = null; # Break the Parser <-> Preprocessor cycle
+ }
+
+ function tagCallback( $innerText, $params, $parser ) {
+ $this->mInnerText = $innerText;
+ $this->mParams = $params;
+
+ return "dummy";
+ }
+}
Index: includes/parser/Preprocessor_DOM.php
===================================================================
--- includes/parser/Preprocessor_DOM.php (revision 110110)
+++ includes/parser/Preprocessor_DOM.php (working copy)
@@ -413,18 +413,51 @@
$close = '';
} else {
$attrEnd = $tagEndPos;
- // Find closing tag
- if ( preg_match( "/<\/" . preg_quote( $name, '/' ) . "\s*>/i",
- $text, $matches, PREG_OFFSET_CAPTURE, $tagEndPos + 1 ) )
- {
- $inner = substr( $text, $tagEndPos + 1, $matches[0][1] - $tagEndPos - 1 );
- $i = $matches[0][1] + strlen( $matches[0][0] );
- $close = '<close>' . htmlspecialchars( $matches[0][0] ) . '</close>';
- } else {
- // No end tag -- let it run out to the end of the text.
+
+ // we know that one start tag was already found
+ $numOfStartTags = 1;
+ $numOfEndTags = 0;
+ $offset = $tagEndPos;
+ $pattern = "/<" . preg_quote( $name, '/' ) . "[^>]*>" . "|" . "<\/" . preg_quote( $name, '/' ) . "\s*>/i";
+
+ while( $numOfStartTags != $numOfEndTags ) {
+ // match start tag or end tag
+ if( preg_match( $pattern, $text, $matches, PREG_OFFSET_CAPTURE, $offset + 1 ) === 0 ) {
+ // nothing found
+ break;
+ }
+
+ // what is it, start or end tag?
+ if( substr( $matches[ 0 ][ 0 ], 0, 2 ) === "</" ) {
+ $numOfEndTags++;
+ } else {
+ $numOfStartTags++;
+ }
+
+ $previousMatches = $matches;
+ $offset = $matches[ 0 ][ 1 ];
+ }
+
+ if( $numOfEndTags === 0 ) {
+ // no end tag, swallow everything
$inner = substr( $text, $tagEndPos + 1 );
$i = strlen( $text );
$close = '';
+
+ } else {
+
+ if( $numOfStartTags === $numOfEndTags ) {
+ // match made in heaven, all start tags have end tags
+ $inner = substr( $text, $tagEndPos + 1, $offset - ( $tagEndPos + 1 ) );
+ $i = $offset + strlen( $matches[0][0] );
+ $close = '<close>' . htmlspecialchars( $matches[0][0] ) . '</close>';
+
+ } else {
+ // not balanced, at least one start tag is orphan
+ $inner = substr( $text, $tagEndPos + 1, $offset - ( $tagEndPos + 1 ) );
+ $i = $offset + strlen( $previousMatches[0][0] );
+ $close = '<close>' . htmlspecialchars( $previousMatches[0][0] ) . '</close>';
+ }
}
}
// <includeonly> and <noinclude> just become <ignore> tags
File Metadata
Details
Attached
Mime Type
text/x-diff
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1407
Default Alt Text
Bug1310.patch (5 KB)
Attached To
Mode
T3310: Recursive tags in extensions.
Attached
Detach File
Event Timeline
Log In to Comment