Revert "Make line breaks in <blockquote> behave like <div> (bug 6200)." See bug...
[lhc/web/wiklou.git] / includes / parser / Parser.php
index 28cde7f..8fdf407 100644 (file)
@@ -54,7 +54,6 @@
  * @warning $wgUser or $wgTitle or $wgRequest or $wgLang. Keep them away!
  *
  * @par Settings:
- * $wgLocaltimezone
  * $wgNamespacesWithSubpages
  *
  * @par Settings only within ParserOptions:
@@ -363,6 +362,9 @@ class Parser {
                $this->startParse( $title, $options, self::OT_HTML, $clearState );
 
                $this->mInputSize = strlen( $text );
+               if ( $this->mOptions->getEnableLimitReport() ) {
+                       $this->mOutput->resetParseStartTime();
+               }
 
                # Remove the strip marker tag prefix from the input, if present.
                if ( $clearState ) {
@@ -493,22 +495,64 @@ class Parser {
                # Information on include size limits, for the benefit of users who try to skirt them
                if ( $this->mOptions->getEnableLimitReport() ) {
                        $max = $this->mOptions->getMaxIncludeSize();
-                       $PFreport = "Expensive parser function count: {$this->mExpensiveFunctionCount}/{$this->mOptions->getExpensiveParserFunctionLimit()}\n";
-                       $limitReport =
-                               "NewPP limit report\n" .
-                               "Preprocessor visited node count: {$this->mPPNodeCount}/{$this->mOptions->getMaxPPNodeCount()}\n" .
-                               "Preprocessor generated node count: " .
-                                       "{$this->mGeneratedPPNodeCount}/{$this->mOptions->getMaxGeneratedPPNodeCount()}\n" .
-                               "Post-expand include size: {$this->mIncludeSizes['post-expand']}/$max bytes\n" .
-                               "Template argument size: {$this->mIncludeSizes['arg']}/$max bytes\n" .
-                               "Highest expansion depth: {$this->mHighestExpansionDepth}/{$this->mOptions->getMaxPPExpandDepth()}\n" .
-                               $PFreport;
+
+                       $cpuTime = $this->mOutput->getTimeSinceStart( 'cpu' );
+                       if ( $cpuTime !== null ) {
+                               $this->mOutput->setLimitReportData( 'limitreport-cputime',
+                                       sprintf( "%.3f", $cpuTime )
+                               );
+                       }
+
+                       $wallTime = $this->mOutput->getTimeSinceStart( 'wall' );
+                       $this->mOutput->setLimitReportData( 'limitreport-walltime',
+                               sprintf( "%.3f", $wallTime )
+                       );
+
+                       $this->mOutput->setLimitReportData( 'limitreport-ppvisitednodes',
+                               array( $this->mPPNodeCount, $this->mOptions->getMaxPPNodeCount() )
+                       );
+                       $this->mOutput->setLimitReportData( 'limitreport-ppgeneratednodes',
+                               array( $this->mGeneratedPPNodeCount, $this->mOptions->getMaxGeneratedPPNodeCount() )
+                       );
+                       $this->mOutput->setLimitReportData( 'limitreport-postexpandincludesize',
+                               array( $this->mIncludeSizes['post-expand'], $max )
+                       );
+                       $this->mOutput->setLimitReportData( 'limitreport-templateargumentsize',
+                               array( $this->mIncludeSizes['arg'], $max )
+                       );
+                       $this->mOutput->setLimitReportData( 'limitreport-expansiondepth',
+                               array( $this->mHighestExpansionDepth, $this->mOptions->getMaxPPExpandDepth() )
+                       );
+                       $this->mOutput->setLimitReportData( 'limitreport-expensivefunctioncount',
+                               array( $this->mExpensiveFunctionCount, $this->mOptions->getExpensiveParserFunctionLimit() )
+                       );
+                       wfRunHooks( 'ParserLimitReportPrepare', array( $this, $this->mOutput ) );
+
+                       $limitReport = "NewPP limit report\n";
+                       foreach ( $this->mOutput->getLimitReportData() as $key => $value ) {
+                               if ( wfRunHooks( 'ParserLimitReportFormat',
+                                       array( $key, $value, &$limitReport, false, false )
+                               ) ) {
+                                       $keyMsg = wfMessage( $key )->inLanguage( 'en' )->useDatabase( false );
+                                       $valueMsg = wfMessage( array( "$key-value-text", "$key-value" ) )
+                                               ->inLanguage( 'en' )->useDatabase( false );
+                                       if ( !$valueMsg->exists() ) {
+                                               $valueMsg = new RawMessage( '$1' );
+                                       }
+                                       if ( !$keyMsg->isDisabled() && !$valueMsg->isDisabled() ) {
+                                               $valueMsg->params( $value );
+                                               $limitReport .= "{$keyMsg->text()}: {$valueMsg->text()}\n";
+                                       }
+                               }
+                       }
+                       // Since we're not really outputting HTML, decode the entities and
+                       // then re-encode the things that need hiding inside HTML comments.
+                       $limitReport = htmlspecialchars_decode( $limitReport );
                        wfRunHooks( 'ParserLimitReport', array( $this, &$limitReport ) );
 
                        // Sanitize for comment. Note '‐' in the replacement is U+2010,
                        // which looks much like the problematic '-'.
                        $limitReport = str_replace( array( '-', '&' ), array( '‐', '&amp;' ), $limitReport );
-
                        $text .= "\n<!-- \n$limitReport-->\n";
 
                        if ( $this->mGeneratedPPNodeCount > $this->mOptions->getMaxGeneratedPPNodeCount() / 10 ) {
@@ -1544,7 +1588,7 @@ class Parser {
         * Replace external links (REL)
         *
         * Note: this is all very hackish and the order of execution matters a lot.
-        * Make sure to run maintenance/parserTests.php if you change this code.
+        * Make sure to run tests/parserTests.php if you change this code.
         *
         * @private
         *
@@ -2682,71 +2726,50 @@ class Parser {
                $ts = wfTimestamp( TS_UNIX, $this->mOptions->getTimestamp() );
                wfRunHooks( 'ParserGetVariableValueTs', array( &$this, &$ts ) );
 
-               # Use the time zone
-               global $wgLocaltimezone;
-               if ( isset( $wgLocaltimezone ) ) {
-                       $oldtz = date_default_timezone_get();
-                       date_default_timezone_set( $wgLocaltimezone );
-               }
-
-               $localTimestamp = date( 'YmdHis', $ts );
-               $localMonth = date( 'm', $ts );
-               $localMonth1 = date( 'n', $ts );
-               $localMonthName = date( 'n', $ts );
-               $localDay = date( 'j', $ts );
-               $localDay2 = date( 'd', $ts );
-               $localDayOfWeek = date( 'w', $ts );
-               $localWeek = date( 'W', $ts );
-               $localYear = date( 'Y', $ts );
-               $localHour = date( 'H', $ts );
-               if ( isset( $wgLocaltimezone ) ) {
-                       date_default_timezone_set( $oldtz );
-               }
-
                $pageLang = $this->getFunctionLang();
 
                switch ( $index ) {
                        case 'currentmonth':
-                               $value = $pageLang->formatNum( gmdate( 'm', $ts ) );
+                               $value = $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'm' ) );
                                break;
                        case 'currentmonth1':
-                               $value = $pageLang->formatNum( gmdate( 'n', $ts ) );
+                               $value = $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'n' ) );
                                break;
                        case 'currentmonthname':
-                               $value = $pageLang->getMonthName( gmdate( 'n', $ts ) );
+                               $value = $pageLang->getMonthName( MWTimestamp::getInstance( $ts )->format( 'n' ) );
                                break;
                        case 'currentmonthnamegen':
-                               $value = $pageLang->getMonthNameGen( gmdate( 'n', $ts ) );
+                               $value = $pageLang->getMonthNameGen( MWTimestamp::getInstance( $ts )->format( 'n' ) );
                                break;
                        case 'currentmonthabbrev':
-                               $value = $pageLang->getMonthAbbreviation( gmdate( 'n', $ts ) );
+                               $value = $pageLang->getMonthAbbreviation( MWTimestamp::getInstance( $ts )->format( 'n' ) );
                                break;
                        case 'currentday':
-                               $value = $pageLang->formatNum( gmdate( 'j', $ts ) );
+                               $value = $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'j' ) );
                                break;
                        case 'currentday2':
-                               $value = $pageLang->formatNum( gmdate( 'd', $ts ) );
+                               $value = $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'd' ) );
                                break;
                        case 'localmonth':
-                               $value = $pageLang->formatNum( $localMonth );
+                               $value = $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'm' ) );
                                break;
                        case 'localmonth1':
-                               $value = $pageLang->formatNum( $localMonth1 );
+                               $value = $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'n' ) );
                                break;
                        case 'localmonthname':
-                               $value = $pageLang->getMonthName( $localMonthName );
+                               $value = $pageLang->getMonthName( MWTimestamp::getLocalInstance( $ts )->format( 'n' ) );
                                break;
                        case 'localmonthnamegen':
-                               $value = $pageLang->getMonthNameGen( $localMonthName );
+                               $value = $pageLang->getMonthNameGen( MWTimestamp::getLocalInstance( $ts )->format( 'n' ) );
                                break;
                        case 'localmonthabbrev':
-                               $value = $pageLang->getMonthAbbreviation( $localMonthName );
+                               $value = $pageLang->getMonthAbbreviation( MWTimestamp::getLocalInstance( $ts )->format( 'n' ) );
                                break;
                        case 'localday':
-                               $value = $pageLang->formatNum( $localDay );
+                               $value = $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'j' ) );
                                break;
                        case 'localday2':
-                               $value = $pageLang->formatNum( $localDay2 );
+                               $value = $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'd' ) );
                                break;
                        case 'pagename':
                                $value = wfEscapeWikiText( $this->mTitle->getText() );
@@ -2892,44 +2915,44 @@ class Parser {
                                $value = ( wfUrlencode( $this->mTitle->getSubjectNsText() ) );
                                break;
                        case 'currentdayname':
-                               $value = $pageLang->getWeekdayName( gmdate( 'w', $ts ) + 1 );
+                               $value = $pageLang->getWeekdayName( MWTimestamp::getInstance( $ts )->format( 'w' ) + 1 );
                                break;
                        case 'currentyear':
-                               $value = $pageLang->formatNum( gmdate( 'Y', $ts ), true );
+                               $value = $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'Y' ), true );
                                break;
                        case 'currenttime':
                                $value = $pageLang->time( wfTimestamp( TS_MW, $ts ), false, false );
                                break;
                        case 'currenthour':
-                               $value = $pageLang->formatNum( gmdate( 'H', $ts ), true );
+                               $value = $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'H' ), true );
                                break;
                        case 'currentweek':
                                # @bug 4594 PHP5 has it zero padded, PHP4 does not, cast to
                                # int to remove the padding
-                               $value = $pageLang->formatNum( (int)gmdate( 'W', $ts ) );
+                               $value = $pageLang->formatNum( (int)MWTimestamp::getInstance( $ts )->format( 'W' ) );
                                break;
                        case 'currentdow':
-                               $value = $pageLang->formatNum( gmdate( 'w', $ts ) );
+                               $value = $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'w' ) );
                                break;
                        case 'localdayname':
-                               $value = $pageLang->getWeekdayName( $localDayOfWeek + 1 );
+                               $value = $pageLang->getWeekdayName( MWTimestamp::getLocalInstance( $ts )->format( 'w' ) + 1 );
                                break;
                        case 'localyear':
-                               $value = $pageLang->formatNum( $localYear, true );
+                               $value = $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'Y' ), true );
                                break;
                        case 'localtime':
-                               $value = $pageLang->time( $localTimestamp, false, false );
+                               $value = $pageLang->time( MWTimestamp::getLocalInstance( $ts )->format( 'YmdHis' ), false, false );
                                break;
                        case 'localhour':
-                               $value = $pageLang->formatNum( $localHour, true );
+                               $value = $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'H' ), true );
                                break;
                        case 'localweek':
                                # @bug 4594 PHP5 has it zero padded, PHP4 does not, cast to
                                # int to remove the padding
-                               $value = $pageLang->formatNum( (int)$localWeek );
+                               $value = $pageLang->formatNum( (int)MWTimestamp::getLocalInstance( $ts )->format( 'W' ) );
                                break;
                        case 'localdow':
-                               $value = $pageLang->formatNum( $localDayOfWeek );
+                               $value = $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'w' ) );
                                break;
                        case 'numberofarticles':
                                $value = $pageLang->formatNum( SiteStats::articles() );
@@ -2960,7 +2983,7 @@ class Parser {
                                $value = wfTimestamp( TS_MW, $ts );
                                break;
                        case 'localtimestamp':
-                               $value = $localTimestamp;
+                               $value = MWTimestamp::getLocalInstance( $ts )->format( 'YmdHis' );
                                break;
                        case 'currentversion':
                                $value = SpecialVersion::getVersion();
@@ -3296,8 +3319,9 @@ class Parser {
                        $ns = NS_TEMPLATE;
                        # Split the title into page and subpage
                        $subpage = '';
-                       $part1 = $this->maybeDoSubpageLink( $part1, $subpage );
-                       if ( $subpage !== '' ) {
+                       $relative = $this->maybeDoSubpageLink( $part1, $subpage );
+                       if ( $part1 !== $relative ) {
+                               $part1 = $relative;
                                $ns = $this->mTitle->getNamespace();
                        }
                        $title = Title::newFromText( $part1, $ns );
@@ -3775,13 +3799,8 @@ class Parser {
         * @return Array ( File or false, Title of file )
         */
        function fetchFileAndTitle( $title, $options = array() ) {
-               if ( isset( $options['broken'] ) ) {
-                       $file = false; // broken thumbnail forced by hook
-               } elseif ( isset( $options['sha1'] ) ) { // get by (sha1,timestamp)
-                       $file = RepoGroup::singleton()->findFileFromKey( $options['sha1'], $options );
-               } else { // get by (name,timestamp)
-                       $file = wfFindFile( $title, $options );
-               }
+               $file = $this->fetchFileNoRegister( $title, $options );
+
                $time = $file ? $file->getTimestamp() : false;
                $sha1 = $file ? $file->getSha1() : false;
                # Register the file as a dependency...
@@ -3799,6 +3818,27 @@ class Parser {
                return array( $file, $title );
        }
 
+       /**
+        * Helper function for fetchFileAndTitle.
+        *
+        * Also useful if you need to fetch a file but not use it yet,
+        * for example to get the file's handler.
+        *
+        * @param Title $title
+        * @param array $options Array of options to RepoGroup::findFile
+        * @return File or false
+        */
+       protected function fetchFileNoRegister( $title, $options = array() ) {
+               if ( isset( $options['broken'] ) ) {
+                       $file = false; // broken thumbnail forced by hook
+               } elseif ( isset( $options['sha1'] ) ) { // get by (sha1,timestamp)
+                       $file = RepoGroup::singleton()->findFileFromKey( $options['sha1'], $options );
+               } else { // get by (name,timestamp)
+                       $file = wfFindFile( $title, $options );
+               }
+               return $file;
+       }
+
        /**
         * Transclude an interwiki link.
         *
@@ -4537,7 +4577,7 @@ class Parser {
         * @return string
         */
        function pstPass2( $text, $user ) {
-               global $wgContLang, $wgLocaltimezone;
+               global $wgContLang;
 
                # Note: This is the timestamp saved as hardcoded wikitext to
                # the database, we use $wgContLang here in order to give
@@ -4545,19 +4585,11 @@ class Parser {
                # than the one selected in each user's preferences.
                # (see also bug 12815)
                $ts = $this->mOptions->getTimestamp();
-               if ( isset( $wgLocaltimezone ) ) {
-                       $tz = $wgLocaltimezone;
-               } else {
-                       $tz = date_default_timezone_get();
-               }
+               $timestamp = MWTimestamp::getLocalInstance( $ts );
+               $ts = $timestamp->format( 'YmdHis' );
+               $tzMsg = $timestamp->format( 'T' );  # might vary on DST changeover!
 
-               $unixts = wfTimestamp( TS_UNIX, $ts );
-               $oldtz = date_default_timezone_get();
-               date_default_timezone_set( $tz );
-               $ts = date( 'YmdHis', $unixts );
-               $tzMsg = date( 'T', $unixts );  # might vary on DST changeover!
-
-               # Allow translation of timezones through wiki. date() can return
+               # Allow translation of timezones through wiki. format() can return
                # whatever crap the system uses, localised or not, so we cannot
                # ship premade translations.
                $key = 'timezone-' . strtolower( trim( $tzMsg ) );
@@ -4566,8 +4598,6 @@ class Parser {
                        $tzMsg = $msg->text();
                }
 
-               date_default_timezone_set( $oldtz );
-
                $d = $wgContLang->timeanddate( $ts, false, false ) . " ($tzMsg)";
 
                # Variable replacement
@@ -5016,6 +5046,7 @@ class Parser {
         * @return string HTML
         */
        function renderImageGallery( $text, $params ) {
+               wfProfileIn( __METHOD__ );
                $ig = new ImageGallery();
                $ig->setContextTitle( $this->mTitle );
                $ig->setShowBytes( false );
@@ -5067,38 +5098,81 @@ class Parser {
                                continue;
                        }
 
+                       # We need to get what handler the file uses, to figure out parameters.
+                       # Note, a hook can overide the file name, and chose an entirely different
+                       # file (which potentially could be of a different type and have different handler).
+                       $options = array();
+                       $descQuery = false;
+                       wfRunHooks( 'BeforeParserFetchFileAndTitle',
+                               array( $this, $title, &$options, &$descQuery ) );
+                       # Don't register it now, as ImageGallery does that later.
+                       $file = $this->fetchFileNoRegister( $title, $options );
+                       $handler = $file ? $file->getHandler() : false;
+
+                       wfProfileIn( __METHOD__ . '-getMagicWord' );
+                       $paramMap = array(
+                               'img_alt' => 'gallery-internal-alt',
+                               'img_link' => 'gallery-internal-link',
+                       );
+                       if ( $handler ) {
+                               $paramMap = $paramMap + $handler->getParamMap();
+                               // We don't want people to specify per-image widths.
+                               // Additionally the width parameter would need special casing anyhow.
+                               unset( $paramMap['img_width'] );
+                       }
+
+                       $mwArray = new MagicWordArray( array_keys( $paramMap ) );
+                       wfProfileOut( __METHOD__ . '-getMagicWord' );
+
                        $label = '';
                        $alt = '';
                        $link = '';
+                       $handlerOptions = array();
                        if ( isset( $matches[3] ) ) {
                                // look for an |alt= definition while trying not to break existing
                                // captions with multiple pipes (|) in it, until a more sensible grammar
                                // is defined for images in galleries
 
+                               // FIXME: Doing recursiveTagParse at this stage, and the trim before
+                               // splitting on '|' is a bit odd, and different from makeImage.
                                $matches[3] = $this->recursiveTagParse( trim( $matches[3] ) );
                                $parameterMatches = StringUtils::explode( '|', $matches[3] );
-                               $magicWordAlt = MagicWord::get( 'img_alt' );
-                               $magicWordLink = MagicWord::get( 'img_link' );
 
                                foreach ( $parameterMatches as $parameterMatch ) {
-                                       if ( $match = $magicWordAlt->matchVariableStartToEnd( $parameterMatch ) ) {
-                                               $alt = $this->stripAltText( $match, false );
-                                       }
-                                       elseif ( $match = $magicWordLink->matchVariableStartToEnd( $parameterMatch ) ) {
-                                               $linkValue = strip_tags( $this->replaceLinkHoldersText( $match ) );
-                                               $chars = self::EXT_LINK_URL_CLASS;
-                                               $prots = $this->mUrlProtocols;
-                                               //check to see if link matches an absolute url, if not then it must be a wiki link.
-                                               if ( preg_match( "/^($prots)$chars+$/u", $linkValue ) ) {
-                                                       $link = $linkValue;
-                                               } else {
-                                                       $localLinkTitle = Title::newFromText( $linkValue );
-                                                       if ( $localLinkTitle !== null ) {
-                                                               $link = $localLinkTitle->getLocalURL();
+                                       list( $magicName, $match ) = $mwArray->matchVariableStartToEnd( $parameterMatch );
+                                       if ( $magicName ) {
+                                               $paramName = $paramMap[$magicName];
+
+                                               switch( $paramName ) {
+                                               case 'gallery-internal-alt':
+                                                       $alt = $this->stripAltText( $match, false );
+                                                       break;
+                                               case 'gallery-internal-link':
+                                                       $linkValue = strip_tags( $this->replaceLinkHoldersText( $match ) );
+                                                       $chars = self::EXT_LINK_URL_CLASS;
+                                                       $prots = $this->mUrlProtocols;
+                                                       //check to see if link matches an absolute url, if not then it must be a wiki link.
+                                                       if ( preg_match( "/^($prots)$chars+$/u", $linkValue ) ) {
+                                                               $link = $linkValue;
+                                                       } else {
+                                                               $localLinkTitle = Title::newFromText( $linkValue );
+                                                               if ( $localLinkTitle !== null ) {
+                                                                       $link = $localLinkTitle->getLocalURL();
+                                                               }
+                                                       }
+                                                       break;
+                                               default:
+                                                       // Must be a handler specific parameter.
+                                                       if ( $handler->validateParam( $paramName, $match ) ) {
+                                                               $handlerOptions[$paramName] = $match;
+                                                       } else {
+                                                               // Guess not. Append it to the caption.
+                                                               wfDebug( "$parameterMatch failed parameter validation" );
+                                                               $label .= '|' . $parameterMatch;
                                                        }
                                                }
-                                       }
-                                       else {
+
+                                       else {
                                                // concatenate all other pipes
                                                $label .= '|' . $parameterMatch;
                                        }
@@ -5107,9 +5181,11 @@ class Parser {
                                $label = substr( $label, 1 );
                        }
 
-                       $ig->add( $title, $label, $alt, $link );
+                       $ig->add( $title, $label, $alt, $link, $handlerOptions );
                }
-               return $ig->toHTML();
+               $html = $ig->toHTML();
+               wfProfileOut( __METHOD__ );
+               return $html;
        }
 
        /**