X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FOutputPage.php;h=36e5871365487ca6be8f6cd5de30985ce7b4d5e3;hb=7cb597d5136207ec2a1e5ce9ca1e52740ffddba3;hp=f6a4a1a86950b02046564606be3da73f6336df6c;hpb=c733ea591082facc708293bf68f25c83ade6219e;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/OutputPage.php b/includes/OutputPage.php index f6a4a1a869..36e5871365 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -1,6 +1,5 @@ mParserOptions = ParserOptions::newFromUser( $temp = NULL ); $this->mSquidMaxage = 0; $this->mScripts = ''; + $this->mETag = false; } function addHeader( $name, $val ) { array_push( $this->mHeaders, $name.': '.$val ) ; } @@ -68,6 +67,10 @@ class OutputPage { function addScript( $script ) { $this->mScripts .= $script; } function getScript() { return $this->mScripts; } + function setETag($tag) { $this->mETag = $tag; } + function setArticleBodyOnly($only) { $this->mArticleBodyOnly = $only; } + function getArticleBodyOnly($only) { return $this->mArticleBodyOnly; } + function addLink( $linkarr ) { # $linkarr should be an associative array of attributes. We'll escape on output. array_push( $this->mLinktags, $linkarr ); @@ -89,14 +92,12 @@ class OutputPage { */ function checkLastModified ( $timestamp ) { global $wgLang, $wgCachePages, $wgUser; - $timestamp=wfTimestamp(TS_MW,$timestamp); - if( !$wgCachePages ) { - wfDebug( "CACHE DISABLED\n", false ); + if ( !$timestamp || $timestamp == '19700101000000' ) { + wfDebug( "CACHE DISABLED, NO TIMESTAMP\n" ); return; } - if( preg_match( '/MSIE ([1-4]|5\.0)/', $_SERVER["HTTP_USER_AGENT"] ) ) { - # IE 5.0 has probs with our caching - wfDebug( "-- bad client, not caching\n", false ); + if( !$wgCachePages ) { + wfDebug( "CACHE DISABLED\n", false ); return; } if( $wgUser->getOption( 'nocache' ) ) { @@ -104,30 +105,33 @@ class OutputPage { return; } - $lastmod = gmdate( 'D, j M Y H:i:s', wfTimestamp(TS_UNIX, max( $timestamp, $wgUser->mTouched ) ) ) . ' GMT'; + $timestamp=wfTimestamp(TS_MW,$timestamp); + $lastmod = wfTimestamp( TS_RFC2822, max( $timestamp, $wgUser->mTouched ) ); if( !empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) { # IE sends sizes after the date like this: # Wed, 20 Aug 2003 06:51:19 GMT; length=5202 # this breaks strtotime(). $modsince = preg_replace( '/;.*$/', '', $_SERVER["HTTP_IF_MODIFIED_SINCE"] ); - $ismodsince = wfTimestamp( TS_MW, strtotime( $modsince ) ); + $modsinceTime = strtotime( $modsince ); + $ismodsince = wfTimestamp( TS_MW, $modsinceTime ? $modsinceTime : 1 ); wfDebug( "-- client send If-Modified-Since: " . $modsince . "\n", false ); wfDebug( "-- we might send Last-Modified : $lastmod\n", false ); - if( ($ismodsince >= $timestamp ) and $wgUser->validateCache( $ismodsince ) ) { + if( ($ismodsince >= $timestamp ) && $wgUser->validateCache( $ismodsince ) ) { # Make sure you're in a place you can leave when you call us! header( "HTTP/1.0 304 Not Modified" ); $this->mLastModified = $lastmod; $this->sendCacheControl(); wfDebug( "CACHED client: $ismodsince ; user: $wgUser->mTouched ; page: $timestamp\n", false ); $this->disable(); + @ob_end_clean(); // Don't output compressed blob return true; } else { wfDebug( "READY client: $ismodsince ; user: $wgUser->mTouched ; page: $timestamp\n", false ); $this->mLastModified = $lastmod; } } else { - wfDebug( "We're confused.\n", false ); + wfDebug( "client did not send If-Modified-Since header\n", false ); $this->mLastModified = $lastmod; } } @@ -162,7 +166,7 @@ class OutputPage { function setHTMLTitle( $name ) {$this->mHTMLtitle = $name; } function setPageTitle( $name ) { global $action, $wgContLang; - $name = $wgContLang->autoConvert($name); + $name = $wgContLang->convert($name, true); $this->mPagetitle = $name; if(!empty($action)) { $taction = $this->getPageTitleActionText(); @@ -174,7 +178,7 @@ class OutputPage { } function getHTMLTitle() { return $this->mHTMLtitle; } function getPageTitle() { return $this->mPagetitle; } - function setSubtitle( $str ) { $this->mSubtitle = $str; } + function setSubtitle( $str ) { $this->mSubtitle = /*$this->parse(*/$str/*)*/; } // @bug 2514 function getSubtitle() { return $this->mSubtitle; } function isArticle() { return $this->mIsarticle; } function setPrintable() { $this->mPrintable = true; } @@ -223,6 +227,7 @@ class OutputPage { function addHTML( $text ) { $this->mBodytext .= $text; } function clearHTML() { $this->mBodytext = ''; } + function getHTML() { return $this->mBodytext; } function debug( $text ) { $this->mDebugtext .= $text; } function setParserOptions( $options ) { @@ -231,16 +236,26 @@ class OutputPage { /** * Convert wikitext to HTML and add it to the buffer + * Default assumes that the current page title will + * be used. */ function addWikiText( $text, $linestart = true ) { - global $wgParser, $wgTitle, $wgUseTidy; + global $wgTitle; + $this->addWikiTextTitle($text, $wgTitle, $linestart); + } - $parserOutput = $wgParser->parse( $text, $wgTitle, $this->mParserOptions, $linestart ); - if ($wgUseTidy) { - $text = Parser::tidy($text); - } + function addWikiTextWithTitle($text, &$title, $linestart = true) { + $this->addWikiTextTitle($text, $title, $linestart); + } + + function addWikiTextTitle($text, &$title, $linestart) { + global $wgParser, $wgUseTidy; + $parserOutput = $wgParser->parse( $text, $title, $this->mParserOptions, $linestart ); $this->mLanguageLinks += $parserOutput->getLanguageLinks(); $this->mCategoryLinks += $parserOutput->getCategoryLinks(); + if ( $parserOutput->getCacheTime() == -1 ) { + $this->enableClientCache( false ); + } $this->addHTML( $parserOutput->getText() ); } @@ -253,26 +268,45 @@ class OutputPage { $parserOutput = $wgParser->parse( $text, $wgTitle, $this->mParserOptions, true ); - # Replace link holders $text = $parserOutput->getText(); - $this->replaceLinkHolders( $text ); - if ($wgUseTidy) { - $text = Parser::tidy($text); - } - $parserOutput->setText( $text ); - - if ( $cacheArticle ) { + + if ( $cacheArticle && $parserOutput->getCacheTime() != -1 ) { $wgParserCache->save( $parserOutput, $cacheArticle, $wgUser ); } $this->mLanguageLinks += $parserOutput->getLanguageLinks(); $this->mCategoryLinks += $parserOutput->getCategoryLinks(); + if ( $parserOutput->getCacheTime() == -1 ) { + $this->enableClientCache( false ); + } $this->addHTML( $text ); } + /** + * Add the output of a QuickTemplate to the output buffer + * @param QuickTemplate $template + */ + function addTemplate( &$template ) { + ob_start(); + $template->execute(); + $this->addHtml( ob_get_contents() ); + ob_end_clean(); + } + + /** + * Parse wikitext and return the HTML. This is for special pages that add the text later + */ + function parse( $text, $linestart = true ) { + global $wgParser, $wgTitle; + $parserOutput = $wgParser->parse( $text, $wgTitle, $this->mParserOptions, $linestart ); + return $parserOutput->getText(); + } + /** * @param $article * @param $user + * + * @return bool */ function tryParserCache( $article, $user ) { global $wgParserCache; @@ -281,6 +315,10 @@ class OutputPage { $this->mLanguageLinks += $parserOutput->getLanguageLinks(); $this->mCategoryLinks += $parserOutput->getCategoryLinks(); $this->addHTML( $parserOutput->getText() ); + $t = $parserOutput->getTitleText(); + if( !empty( $t ) ) { + $this->setPageTitle( $t ); + } return true; } else { return false; @@ -305,7 +343,12 @@ class OutputPage { function sendCacheControl() { global $wgUseSquid, $wgUseESI; - # FIXME: This header may cause trouble with some versions of Internet Explorer + + if ($this->mETag) + header("ETag: $this->mETag"); + + # don't serve compressed data to clients who can't handle it + # maintain different caches for logged-in users and non-logged in ones header( 'Vary: Accept-Encoding, Cookie' ); if( $this->mEnableClientCache ) { if( $wgUseSquid && ! isset( $_COOKIE[ini_get( 'session.name') ] ) && @@ -375,7 +418,7 @@ class OutputPage { if( !$wgDebugRedirects ) { header("HTTP/1.1 {$this->mRedirectCode} Moved Permanently"); } - $this->mLastModified = gmdate( 'D, j M Y H:i:s' ) . ' GMT'; + $this->mLastModified = wfTimestamp( TS_RFC2822 ); } $this->sendCacheControl(); @@ -393,11 +436,11 @@ class OutputPage { } - $this->sendCacheControl(); - # Perform link colouring + # Buffer output; final headers may depend on later processing + ob_start(); + $this->transformBuffer(); - $this->replaceLinkHolders( $this->mSubtitle ); - + # Disable temporary placeholders, so that the skin produces HTML $sk->postParseLinkColour( false ); @@ -409,8 +452,16 @@ class OutputPage { setcookie( $name, $val, $exp, '/' ); } - $sk->outputPage( $this ); - # flush(); + if ($this->mArticleBodyOnly) { + $this->out($this->mBodytext); + } else { + wfProfileIn( 'Output-skin' ); + $sk->outputPage( $this ); + wfProfileOut( 'Output-skin' ); + } + + $this->sendCacheControl(); + ob_end_flush(); } function out( $ins ) { @@ -439,41 +490,13 @@ class OutputPage { $wgOutputEncoding = strtolower( $wgOutputEncoding ); return; } - - /* - # This code is unused anyway! - # Commenting out. --bv 2003-11-15 - - $a = explode( ",", $_SERVER['HTTP_ACCEPT_CHARSET'] ); - $best = 0.0; - $bestset = "*"; - - foreach ( $a as $s ) { - if ( preg_match( "/(.*);q=(.*)/", $s, $m ) ) { - $set = $m[1]; - $q = (float)($m[2]); - } else { - $set = $s; - $q = 1.0; - } - if ( $q > $best ) { - $bestset = $set; - $best = $q; - } - } - #if ( "*" == $bestset ) { $bestset = "iso-8859-1"; } - if ( "*" == $bestset ) { $bestset = $wgOutputEncoding; } - $wgOutputEncoding = strtolower( $bestset ); - -# Disable for now -# - */ $wgOutputEncoding = $wgInputEncoding; } /** * Returns a HTML comment with the elapsed time since request. * This method has no side effects. + * @return string */ function reportTime() { global $wgRequestTime; @@ -513,19 +536,60 @@ class OutputPage { $this->setHTMLTitle( wfMsg( 'errorpagetitle' ) ); $this->setRobotpolicy( 'noindex,nofollow' ); $this->setArticleRelated( false ); - $this->suppressQuickbar(); - $this->enableClientCache( false ); $this->mRedirect = ''; $this->mBodytext = ''; - $this->addHTML( '

' . wfMsg( $msg ) . "

\n" ); + $this->addWikiText( wfMsg( $msg ) ); $this->returnToMain( false ); $this->output(); wfErrorExit(); } + /** + * Display an error page indicating that a given version of MediaWiki is + * required to use it + * + * @param mixed $version The version of MediaWiki needed to use the page + */ + function versionRequired( $version ) { + global $wgUser; + + $this->setPageTitle( wfMsg( 'versionrequired', $version ) ); + $this->setHTMLTitle( wfMsg( 'versionrequired', $version ) ); + $this->setRobotpolicy( 'noindex,nofollow' ); + $this->setArticleRelated( false ); + $this->mBodytext = ''; + + $sk = $wgUser->getSkin(); + $this->addWikiText( wfMsg( 'versionrequiredtext', $version ) ); + $this->returnToMain(); + } + + /** + * Display an error page noting that a given permission bit is required. + * This should generally replace the sysopRequired, developerRequired etc. + * @param string $permission key required + */ + function permissionRequired( $permission ) { + global $wgUser; + + $this->setPageTitle( wfMsg( 'badaccess' ) ); + $this->setHTMLTitle( wfMsg( 'errorpagetitle' ) ); + $this->setRobotpolicy( 'noindex,nofollow' ); + $this->setArticleRelated( false ); + $this->mBodytext = ''; + + $sk = $wgUser->getSkin(); + $ap = $sk->makeKnownLink( wfMsgForContent( 'administrators' ) ); + $this->addHTML( wfMsgHtml( 'badaccesstext', $ap, $permission ) ); + $this->returnToMain(); + } + + /** + * @deprecated + */ function sysopRequired() { global $wgUser; @@ -537,10 +601,13 @@ class OutputPage { $sk = $wgUser->getSkin(); $ap = $sk->makeKnownLink( wfMsgForContent( 'administrators' ), '' ); - $this->addHTML( wfMsg( 'sysoptext', $ap ) ); + $this->addHTML( wfMsgHtml( 'sysoptext', $ap ) ); $this->returnToMain(); } + /** + * @deprecated + */ function developerRequired() { global $wgUser; @@ -552,7 +619,7 @@ class OutputPage { $sk = $wgUser->getSkin(); $ap = $sk->makeKnownLink( wfMsgForContent( 'administrators' ), '' ); - $this->addHTML( wfMsg( 'developertext', $ap ) ); + $this->addHTML( wfMsgHtml( 'developertext', $ap ) ); $this->returnToMain(); } @@ -576,7 +643,7 @@ class OutputPage { } function databaseError( $fname, $sql, $error, $errno ) { - global $wgUser, $wgCommandLineMode; + global $wgUser, $wgCommandLineMode, $wgShowSQLErrors; $this->setPageTitle( wfMsgNoDB( 'databaseerror' ) ); $this->setRobotpolicy( 'noindex,nofollow' ); @@ -584,6 +651,10 @@ class OutputPage { $this->enableClientCache( false ); $this->mRedirect = ''; + if( !$wgShowSQLErrors ) { + $sql = wfMsg( 'sqlhidden' ); + } + if ( $wgCommandLineMode ) { $msg = wfMsgNoDB( 'dberrortextcl', htmlspecialchars( $sql ), htmlspecialchars( $fname ), $errno, htmlspecialchars( $error ) ); @@ -602,7 +673,7 @@ class OutputPage { } function readOnlyPage( $source = null, $protected = false ) { - global $wgUser, $wgReadOnlyFile; + global $wgUser, $wgReadOnlyFile, $wgReadOnly; $this->setRobotpolicy( 'noindex,nofollow' ); $this->setArticleRelated( false ); @@ -612,7 +683,11 @@ class OutputPage { $this->addWikiText( wfMsg( 'protectedtext' ) ); } else { $this->setPageTitle( wfMsg( 'readonly' ) ); - $reason = file_get_contents( $wgReadOnlyFile ); + if ( $wgReadOnly ) { + $reason = $wgReadOnly; + } else { + $reason = file_get_contents( $wgReadOnlyFile ); + } $this->addWikiText( wfMsg( 'readonlytext', $reason ) ); } @@ -690,19 +765,20 @@ class OutputPage { } /** - * This function takes the existing and broken links for the page + * This function takes the title (first item of mGoodLinks), categories, existing and broken links for the page * and uses the first 10 of them for META keywords */ function addMetaTags () { global $wgLinkCache , $wgOut ; + $categories = array_keys ( $wgLinkCache->mCategoryLinks ) ; $good = array_keys ( $wgLinkCache->mGoodLinks ) ; $bad = array_keys ( $wgLinkCache->mBadLinks ) ; - $a = array_merge ( $good , $bad ) ; + $a = array_merge ( array_slice ( $good , 0 , 1 ), $categories, array_slice ( $good , 1 , 9 ) , $bad ) ; $a = array_slice ( $a , 0 , 10 ) ; # 10 keywords max $a = implode ( ',' , $a ) ; $strip = array( - "/<.*?" . ">/" => '', - "/[_]/" => ' ' + "/<.*?>/" => '', + "/_/" => ' ' ); $a = htmlspecialchars(preg_replace(array_keys($strip), array_values($strip),$a )); @@ -711,14 +787,14 @@ class OutputPage { /** * @private + * @return string */ function headElement() { global $wgDocType, $wgDTD, $wgContLanguageCode, $wgOutputEncoding, $wgMimeType; global $wgUser, $wgContLang, $wgRequest; - $xml = ($wgMimeType == 'text/xml'); - if( $xml ) { - $ret = "<" . "?xml version=\"1.0\" encoding=\"$wgOutputEncoding\" ?" . ">\n"; + if( $wgMimeType == 'text/xml' || $wgMimeType == 'application/xhtml+xml' || $wgMimeType == 'application/xml' ) { + $ret = "\n"; } else { $ret = ''; } @@ -728,13 +804,9 @@ class OutputPage { if ( "" == $this->mHTMLtitle ) { $this->mHTMLtitle = wfMsg( "pagetitle", $this->mPagetitle ); } - if( $xml ) { - $xmlbits = "xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\""; - } else { - $xmlbits = ''; - } + $rtl = $wgContLang->isRTL() ? " dir='RTL'" : ''; - $ret .= "\n"; + $ret .= "\n"; $ret .= "\n" . htmlspecialchars( $this->mHTMLtitle ) . "\n"; array_push( $this->mMetatags, array( "http:Content-type", "$wgMimeType; charset={$wgOutputEncoding}" ) ); @@ -775,8 +847,8 @@ class OutputPage { if ( count( $this->mKeywords ) > 0 ) { $strip = array( - "/<.*?" . ">/" => '', - "/[_]/" => ' ' + "/<.*?>/" => '', + "/_/" => ' ' ); $ret .= "mKeywords ))) . "\" />\n"; @@ -795,174 +867,33 @@ class OutputPage { $link = $wgRequest->escapeAppendQuery( 'feed=atom' ); $ret .= "\n"; } - # FIXME: get these working - # $fix = htmlspecialchars( $wgStylePath . "/ie-png-fix.js" ); - # $ret .= ""; + return $ret; } - + /** * Run any necessary pre-output transformations on the buffer text */ function transformBuffer( $options = 0 ) { - $this->replaceLinkHolders( $this->mBodytext, $options ); } + /** - * Replace link placeholders with actual links, in the buffer - * Placeholders created in Skin::makeLinkObj() - * Returns an array of links found, indexed by PDBK: - * 0 - broken - * 1 - normal link - * 2 - stub - * $options is a bit field, RLH_FOR_UPDATE to select for update + * Turn off regular page output and return an error reponse + * for when rate limiting has triggered. + * @todo i18n + * @access public */ - function replaceLinkHolders( &$text, $options = 0 ) { - global $wgUser, $wgLinkCache, $wgUseOldExistenceCheck, $wgLinkHolders; - - if ( $wgUseOldExistenceCheck ) { - return array(); - } - - $fname = 'OutputPage::replaceLinkHolders'; - wfProfileIn( $fname ); - - $pdbks = array(); - $colours = array(); - - #if ( !empty( $tmpLinks[0] ) ) { #TODO - if ( !empty( $wgLinkHolders['namespaces'] ) ) { - wfProfileIn( $fname.'-check' ); - $dbr =& wfGetDB( DB_SLAVE ); - $cur = $dbr->tableName( 'cur' ); - $sk = $wgUser->getSkin(); - $threshold = $wgUser->getOption('stubthreshold'); - - # Sort by namespace - asort( $wgLinkHolders['namespaces'] ); - - # Generate query - $query = false; - foreach ( $wgLinkHolders['namespaces'] as $key => $val ) { - # Make title object - $title = $wgLinkHolders['titles'][$key]; - - # Skip invalid entries. - # Result will be ugly, but prevents crash. - if ( is_null( $title ) ) { - continue; - } - $pdbk = $pdbks[$key] = $title->getPrefixedDBkey(); - - # Check if it's in the link cache already - if ( $wgLinkCache->getGoodLinkID( $pdbk ) ) { - $colours[$pdbk] = 1; - } elseif ( $wgLinkCache->isBadLink( $pdbk ) ) { - $colours[$pdbk] = 0; - } else { - # Not in the link cache, add it to the query - if ( !isset( $current ) ) { - $current = $val; - $query = "SELECT cur_id, cur_namespace, cur_title"; - if ( $threshold > 0 ) { - $query .= ", LENGTH(cur_text) AS cur_len, cur_is_redirect"; - } - $query .= " FROM $cur WHERE (cur_namespace=$val AND cur_title IN("; - } elseif ( $current != $val ) { - $current = $val; - $query .= ")) OR (cur_namespace=$val AND cur_title IN("; - } else { - $query .= ', '; - } - - $query .= $dbr->addQuotes( $wgLinkHolders['dbkeys'][$key] ); - } - } - if ( $query ) { - $query .= '))'; - if ( $options & RLH_FOR_UPDATE ) { - $query .= ' FOR UPDATE'; - } - - $res = $dbr->query( $query, $fname ); - - # Fetch data and form into an associative array - # non-existent = broken - # 1 = known - # 2 = stub - while ( $s = $dbr->fetchObject($res) ) { - $title = Title::makeTitle( $s->cur_namespace, $s->cur_title ); - $pdbk = $title->getPrefixedDBkey(); - $wgLinkCache->addGoodLink( $s->cur_id, $pdbk ); - - if ( $threshold > 0 ) { - $size = $s->cur_len; - if ( $s->cur_is_redirect || $s->cur_namespace != 0 || $length < $threshold ) { - $colours[$pdbk] = 1; - } else { - $colours[$pdbk] = 2; - } - } else { - $colours[$pdbk] = 1; - } - } - } - wfProfileOut( $fname.'-check' ); - - # Construct search and replace arrays - wfProfileIn( $fname.'-construct' ); - global $outputReplace; - $outputReplace = array(); - foreach ( $wgLinkHolders['namespaces'] as $key => $ns ) { - $pdbk = $pdbks[$key]; - $searchkey = ''; - $title = $wgLinkHolders['titles'][$key]; - if ( empty( $colours[$pdbk] ) ) { - $wgLinkCache->addBadLink( $pdbk ); - $colours[$pdbk] = 0; - $outputReplace[$searchkey] = $sk->makeBrokenLinkObj( $title, - $wgLinkHolders['texts'][$key], - $wgLinkHolders['queries'][$key] ); - } elseif ( $colours[$pdbk] == 1 ) { - $outputReplace[$searchkey] = $sk->makeKnownLinkObj( $title, - $wgLinkHolders['texts'][$key], - $wgLinkHolders['queries'][$key] ); - } elseif ( $colours[$pdbk] == 2 ) { - $outputReplace[$searchkey] = $sk->makeStubLinkObj( $title, - $wgLinkHolders['texts'][$key], - $wgLinkHolders['queries'][$key] ); - } - } - wfProfileOut( $fname.'-construct' ); - - # Do the thing - wfProfileIn( $fname.'-replace' ); - - $text = preg_replace_callback( - '/()/', - "outputReplaceMatches", - $text); - wfProfileOut( $fname.'-replace' ); - - wfProfileIn( $fname.'-interwiki' ); - global $wgInterwikiLinkHolders; - $outputReplace = $wgInterwikiLinkHolders; - $text = preg_replace_callback( - '//', - "outputReplaceMatches", - $text); - wfProfileOut( $fname.'-interwiki' ); - } - - wfProfileOut( $fname ); - return $colours; + function rateLimited() { + global $wgOut; + $wgOut->disable(); + wfHttpError( 500, 'Internal Server Error', + 'Sorry, the server has encountered an internal error. ' . + 'Please wait a moment and hit "refresh" to submit the request again.' ); } -} -function &outputReplaceMatches($matches) { - global $outputReplace; - return $outputReplace[$matches[1]]; } -} +} // MediaWiki + ?>