X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fparser%2FPreprocessor_DOM.php;h=673ac241f32ade97a63d1f77af61785c53cd1147;hb=70f677dbecf54e226560467f9258602a15bb1772;hp=01776cdb47f8e679088bf4306c6c5f70d5f9693d;hpb=c6b902f180a39b12c2f53125a73c79e70b8968e9;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/parser/Preprocessor_DOM.php b/includes/parser/Preprocessor_DOM.php index 01776cdb47..673ac241f3 100644 --- a/includes/parser/Preprocessor_DOM.php +++ b/includes/parser/Preprocessor_DOM.php @@ -6,6 +6,8 @@ class Preprocessor_DOM implements Preprocessor { var $parser, $memoryLimit; + const CACHE_VERSION = 1; + function __construct( $parser ) { $this->parser = $parser; $mem = ini_get( 'memory_limit' ); @@ -23,6 +25,10 @@ class Preprocessor_DOM implements Preprocessor { return new PPFrame_DOM( $this ); } + function newCustomFrame( $args ) { + return new PPCustomFrame_DOM( $this, $args ); + } + function memCheck() { if ( $this->memoryLimit === false ) { return; @@ -59,8 +65,61 @@ class Preprocessor_DOM implements Preprocessor { */ function preprocessToObj( $text, $flags = 0 ) { wfProfileIn( __METHOD__ ); - wfProfileIn( __METHOD__.'-makexml' ); + global $wgMemc, $wgPreprocessorCacheThreshold; + + $xml = false; + $cacheable = strlen( $text ) > $wgPreprocessorCacheThreshold; + if ( $cacheable ) { + wfProfileIn( __METHOD__.'-cacheable' ); + + $cacheKey = wfMemcKey( 'preprocess-xml', md5($text), $flags ); + $cacheValue = $wgMemc->get( $cacheKey ); + if ( $cacheValue ) { + $version = substr( $cacheValue, 0, 8 ); + if ( intval( $version ) == self::CACHE_VERSION ) { + $xml = substr( $cacheValue, 8 ); + // From the cache + wfDebugLog( "Preprocessor", "Loaded preprocessor XML from memcached (key $cacheKey)" ); + } + } + } + if ( $xml === false ) { + if ( $cacheable ) { + wfProfileIn( __METHOD__.'-cache-miss' ); + $xml = $this->preprocessToXml( $text, $flags ); + $cacheValue = sprintf( "%08d", self::CACHE_VERSION ) . $xml; + $wgMemc->set( $cacheKey, $cacheValue, 86400 ); + wfProfileOut( __METHOD__.'-cache-miss' ); + wfDebugLog( "Preprocessor", "Saved preprocessor XML to memcached (key $cacheKey)" ); + } else { + $xml = $this->preprocessToXml( $text, $flags ); + } + } + wfProfileIn( __METHOD__.'-loadXML' ); + $dom = new DOMDocument; + wfSuppressWarnings(); + $result = $dom->loadXML( $xml ); + wfRestoreWarnings(); + if ( !$result ) { + // Try running the XML through UtfNormal to get rid of invalid characters + $xml = UtfNormal::cleanUp( $xml ); + $result = $dom->loadXML( $xml ); + if ( !$result ) { + throw new MWException( __METHOD__.' generated invalid XML' ); + } + } + $obj = new PPNode_DOM( $dom->documentElement ); + wfProfileOut( __METHOD__.'-loadXML' ); + if ( $cacheable ) { + wfProfileOut( __METHOD__.'-cacheable' ); + } + wfProfileOut( __METHOD__ ); + return $obj; + } + + function preprocessToXml( $text, $flags = 0 ) { + wfProfileIn( __METHOD__ ); $rules = array( '{' => array( 'end' => '}', @@ -300,7 +359,9 @@ class Preprocessor_DOM implements Preprocessor { } else { $attrEnd = $tagEndPos; // Find closing tag - if ( preg_match( "/<\/$name\s*>/i", $text, $matches, PREG_OFFSET_CAPTURE, $tagEndPos + 1 ) ) { + 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 = '' . htmlspecialchars( $matches[0][0] ) . ''; @@ -358,7 +419,8 @@ class Preprocessor_DOM implements Preprocessor { 'count' => $count ); $stack->push( $piece ); $accum =& $stack->getAccum(); - extract( $stack->getFlags() ); + $flags = $stack->getFlags(); + extract( $flags ); $i += $count; } } @@ -409,7 +471,8 @@ class Preprocessor_DOM implements Preprocessor { // Unwind the stack $stack->pop(); $accum =& $stack->getAccum(); - extract( $stack->getFlags() ); + $flags = $stack->getFlags(); + extract( $flags ); // Append the result to the enclosing accumulator $accum .= $element; @@ -436,7 +499,8 @@ class Preprocessor_DOM implements Preprocessor { $stack->push( $piece ); $accum =& $stack->getAccum(); - extract( $stack->getFlags() ); + $flags = $stack->getFlags(); + extract( $flags ); } else { # Add literal brace(s) $accum .= htmlspecialchars( str_repeat( $curChar, $count ) ); @@ -536,8 +600,8 @@ class Preprocessor_DOM implements Preprocessor { } $enclosingAccum .= str_repeat( $piece->open, $skippedBraces ); } - - extract( $stack->getFlags() ); + $flags = $stack->getFlags(); + extract( $flags ); # Add XML element to the enclosing accumulator $accum .= $element; @@ -565,24 +629,9 @@ class Preprocessor_DOM implements Preprocessor { $stack->rootAccum .= ''; $xml = $stack->rootAccum; - wfProfileOut( __METHOD__.'-makexml' ); - wfProfileIn( __METHOD__.'-loadXML' ); - $dom = new DOMDocument; - wfSuppressWarnings(); - $result = $dom->loadXML( $xml ); - wfRestoreWarnings(); - if ( !$result ) { - // Try running the XML through UtfNormal to get rid of invalid characters - $xml = UtfNormal::cleanUp( $xml ); - $result = $dom->loadXML( $xml ); - if ( !$result ) { - throw new MWException( __METHOD__.' generated invalid XML' ); - } - } - $obj = new PPNode_DOM( $dom->documentElement ); - wfProfileOut( __METHOD__.'-loadXML' ); wfProfileOut( __METHOD__ ); - return $obj; + + return $xml; } } @@ -766,6 +815,7 @@ class PPFrame_DOM implements PPFrame { /** * Recursion depth of this frame, top = 0 + * Note that this is NOT the same as expansion depth in expand() */ var $depth; @@ -822,7 +872,7 @@ class PPFrame_DOM implements PPFrame { } function expand( $root, $flags = 0 ) { - static $depth = 0; + static $expansionDepth = 0; if ( is_string( $root ) ) { return $root; } @@ -832,10 +882,11 @@ class PPFrame_DOM implements PPFrame { return 'Node-count limit exceeded'; } - if ( $depth > $this->parser->mOptions->mMaxPPExpandDepth ) { + if ( $expansionDepth > $this->parser->mOptions->mMaxPPExpandDepth ) { return 'Expansion depth limit exceeded'; } - ++$depth; + wfProfileIn( __METHOD__ ); + ++$expansionDepth; if ( $root instanceof PPNode_DOM ) { $root = $root->node; @@ -1001,6 +1052,7 @@ class PPFrame_DOM implements PPFrame { $newIterator = $contextNode->childNodes; } } else { + wfProfileOut( __METHOD__ ); throw new MWException( __METHOD__.': Invalid parameter type' ); } @@ -1023,7 +1075,8 @@ class PPFrame_DOM implements PPFrame { } } } - --$depth; + --$expansionDepth; + wfProfileOut( __METHOD__ ); return $outStack[0]; } @@ -1139,6 +1192,18 @@ class PPFrame_DOM implements PPFrame { } } + function getArguments() { + return array(); + } + + function getNumberedArguments() { + return array(); + } + + function getNamedArguments() { + return array(); + } + /** * Returns true if there are no arguments in this frame */ @@ -1174,8 +1239,7 @@ class PPTemplateFrame_DOM extends PPFrame_DOM { var $numberedExpansionCache, $namedExpansionCache; function __construct( $preprocessor, $parent = false, $numberedArgs = array(), $namedArgs = array(), $title = false ) { - $this->preprocessor = $preprocessor; - $this->parser = $preprocessor->parser; + PPFrame_DOM::__construct( $preprocessor ); $this->parent = $parent; $this->numberedArgs = $numberedArgs; $this->namedArgs = $namedArgs; @@ -1214,6 +1278,32 @@ class PPTemplateFrame_DOM extends PPFrame_DOM { return !count( $this->numberedArgs ) && !count( $this->namedArgs ); } + function getArguments() { + $arguments = array(); + foreach ( array_merge( + array_keys($this->numberedArgs), + array_keys($this->namedArgs)) as $key ) { + $arguments[$key] = $this->getArgument($key); + } + return $arguments; + } + + function getNumberedArguments() { + $arguments = array(); + foreach ( array_keys($this->numberedArgs) as $key ) { + $arguments[$key] = $this->getArgument($key); + } + return $arguments; + } + + function getNamedArguments() { + $arguments = array(); + foreach ( array_keys($this->namedArgs) as $key ) { + $arguments[$key] = $this->getArgument($key); + } + return $arguments; + } + function getNumberedArgument( $index ) { if ( !isset( $this->numberedArgs[$index] ) ) { return false; @@ -1253,6 +1343,46 @@ class PPTemplateFrame_DOM extends PPFrame_DOM { } } +/** + * Expansion frame with custom arguments + * @ingroup Parser + */ +class PPCustomFrame_DOM extends PPFrame_DOM { + var $args; + + function __construct( $preprocessor, $args ) { + PPFrame_DOM::__construct( $preprocessor ); + $this->args = $args; + } + + function __toString() { + $s = 'cstmframe{'; + $first = true; + foreach ( $this->args as $name => $value ) { + if ( $first ) { + $first = false; + } else { + $s .= ', '; + } + $s .= "\"$name\":\"" . + str_replace( '"', '\\"', $value->__toString() ) . '"'; + } + $s .= '}'; + return $s; + } + + function isEmpty() { + return !count( $this->args ); + } + + function getArgument( $index ) { + if ( !isset( $this->args[$index] ) ) { + return false; + } + return $this->args[$index]; + } +} + /** * @ingroup Parser */