Example #1
0
 /**
  * @covers MWDebug::deprecated
  */
 public function testAvoidNonConsecutivesDuplicateDeprecations()
 {
     MWDebug::deprecated('wfOldFunction', '1.0', 'component');
     MWDebug::warning('some warning');
     MWDebug::log('we could have logged something too');
     // Another deprecation
     MWDebug::deprecated('wfOldFunction', '1.0', 'component');
     // assertCount() not available on WMF integration server
     $this->assertEquals(3, count(MWDebug::getLog()), "Only one deprecated warning per function should be kept");
 }
Example #2
0
 /**
  * Acquire a Redis connection.
  *
  * @access	protected
  * @param	string	[Optiona] Server group key. 
  * 					Example: 'cache' would look up $wgRedisServers['cached']
  *					Default: Uses the first index of $wgRedisServers.
  * @param	array	[Optional] Additional options, will merge and overwrite default options.
  *					- connectTimeout : The timeout for new connections, in seconds.
  *                      Optional, default is 1 second.
  *					- persistent     : Set this to true to allow connections to persist across
  *                      multiple web requests. False by default.
  *					- password       : The authentication password, will be sent to Redis in clear text.
  *                      Optional, if it is unspecified, no AUTH command will be sent.
  *					- serializer     : Set to "php", "igbinary", or "none". Default is "php".
  * @param	boolean	[Optional] Force a new connection, useful when forking processes.
  * @return	mixed	Object RedisConnRef or false on failure.
  */
 public static function getClient($group = null, $options = [], $newConnection = false)
 {
     global $wgRedisServers;
     if (!extension_loaded('redis')) {
         throw new MWException(__METHOD__ . " - The PHP Redis extension is not available.  Please enable it on the server to use RedisCache.");
     }
     if (empty($wgRedisServers) || !is_array($wgRedisServers)) {
         MWDebug::log(__METHOD__ . " - \$wgRedisServers must be configured for RedisCache to function.");
         return false;
     }
     if (empty($group)) {
         $group = 0;
         $server = current($wgRedisServers);
     } else {
         $server = $wgRedisServers[$group];
     }
     if ($newConnection === false && array_key_exists($group, self::$servers)) {
         return self::$servers[$group];
     }
     if (empty($server) || !is_array($server)) {
         throw new MWException(__METHOD__ . " - An invalid server group key was passed.");
     }
     $pool = \RedisConnectionPool::singleton(array_merge($server['options'], $options));
     $redis = $pool->getConnection($server['host'] . ":" . $server['port']);
     //Concatenate these together for MediaWiki weirdness so it can split them later.
     if ($redis instanceof RedisConnRef) {
         //Set up any extra options.  RedisConnectionPool does not handle the prefix automatically.
         if (!empty($server['options']['prefix'])) {
             $redis->setOption(Redis::OPT_PREFIX, $server['options']['prefix']);
         }
         try {
             $pong = $redis->ping();
             if ($pong === '+PONG') {
                 self::$servers[$group] = $redis;
             } else {
                 $redis = false;
             }
         } catch (RedisException $e) {
             //People using HAProxy will find it will lie about a Redis cluster being healthy when the master is down, but the slaves are up.  Doing a PING will cause an immediate disconnect.
             self::$lastError = $e->getMessage();
             $redis = false;
         }
     }
     return $redis;
 }
Example #3
0
 /**
  * @covers MWDebug::appendDebugInfoToApiResult
  */
 public function testAppendDebugInfoToApiResultXmlFormat()
 {
     $request = $this->newApiRequest(['action' => 'help', 'format' => 'xml'], '/api.php?action=help&format=xml');
     $context = new RequestContext();
     $context->setRequest($request);
     $apiMain = new ApiMain($context);
     $result = new ApiResult($apiMain);
     MWDebug::appendDebugInfoToApiResult($context, $result);
     $this->assertInstanceOf('ApiResult', $result);
     $data = $result->getResultData();
     $expectedKeys = ['mwVersion', 'phpEngine', 'phpVersion', 'gitRevision', 'gitBranch', 'gitViewUrl', 'time', 'log', 'debugLog', 'queries', 'request', 'memory', 'memoryPeak', 'includes', '_element'];
     foreach ($expectedKeys as $expectedKey) {
         $this->assertArrayHasKey($expectedKey, $data['debuginfo'], "debuginfo has {$expectedKey}");
     }
     $xml = ApiFormatXml::recXmlPrint('help', $data);
     // exception not thrown
     $this->assertInternalType('string', $xml);
 }
 /**
  * Main Hook
  */
 public static function hOutputPageParserOutput(&$op, $parserOutput)
 {
     $action = $op->parserOptions()->getUser()->getRequest()->getVal("action");
     if ($action == 'edit' || $action == 'submit' || $action == 'history') {
         return true;
     }
     global $wgTitle, $wgOut;
     $ns = $wgTitle->getNsText();
     $name = $wgTitle->getPrefixedDBKey();
     $text = $parserOutput->getText();
     $categories = $wgTitle->getParentCategories();
     $categories = array_keys($categories);
     var_dump($categories);
     $categories = array_map(function ($cat) {
         return Title::newFromText($cat, NS_CATEGORY)->getText();
     }, $categories);
     var_dump($categories);
     //MWDebug::warning( "ns=" . $ns ) ;
     //MWDebug::warning( "name=" . $name ) ;
     $nsheader = "hf-nsheader-{$ns}";
     $nsfooter = "hf-nsfooter-{$ns}";
     $header = "hf-header-{$name}";
     $footer = "hf-footer-{$name}";
     /**
      * headers/footers are wrapped around page content.
      * header:	page + namespace + categories in reverse alphabetical order
      * footer:	categories in alphabetical order + namespace + page
      */
     $text = '<div class="hf-header">' . self::conditionalInclude($text, '__NOHEADER__', $header) . '</div>' . $text;
     $text = '<div class="hf-nsheader">' . self::conditionalInclude($text, '__NONSHEADER__', $nsheader) . '</div>' . $text;
     foreach ($categories as &$category) {
         MWDebug::warning("cat=" . $category);
         $catheader = "hf-catheader-{$category}";
         $text = '<div class="hf-catheader">' . self::conditionalInclude($text, '__NOCATHEADER__', $catheader) . '</div>' . $text;
         $catfooter = "hf-catfooter-{$category}";
         $text .= '<div class="hf-catfooter">' . self::conditionalInclude($text, '__NOCATFOOTER__', $catfooter) . '</div>';
     }
     ////
     $text .= '<div class="hf-footer">' . self::conditionalInclude($text, '__NOFOOTER__', $footer) . '</div>';
     $text .= '<div class="hf-nsfooter">' . self::conditionalInclude($text, '__NONSFOOTER__', $nsfooter) . '</div>';
     $parserOutput->setText($text);
     return true;
 }
 public function execute($parameters)
 {
     $out = $this->getOutput();
     $skin = $this->getSkin();
     $this->setHeaders();
     $out->setArticleBodyOnly(true);
     // Default modules copied from OutputPage::addDefaultModules
     $out->addModules(array('mediawiki.user', 'mediawiki.page.startup', 'mediawiki.page.ready'));
     $out->addModules(array('ext.cx.header', 'ext.cx.stats'));
     // Load legacy modules if any, for the skin.
     // Some wikis have Common.js scripts that depend on this module.
     $defaultSkinModules = $skin->getDefaultModules();
     $out->addModules($defaultSkinModules['legacy']);
     Hooks::run('BeforePageDisplay', array(&$out, &$skin));
     $out->addHTML($out->headElement($skin));
     $out->addHTML(Html::element('noscript', array(), $this->msg('cx-javascript')->text()));
     $out->addHtml(MWDebug::getDebugHTML($this->getContext()));
     $toolbarList = Html::rawElement('ul', null, $skin->getPersonalToolsList());
     $out->addHTML(Html::rawElement('div', array('id' => 'p-personal'), $toolbarList));
     $out->addHTML($skin->bottomScripts());
     $out->addHTML('</body></html>');
 }
Example #6
0
/**
 * Send a warning either to the debug log or in a PHP error depending on
 * $wgDevelopmentWarnings
 *
 * @param $msg String: message to send
 * @param $callerOffset Integer: number of items to go back in the backtrace to
 *        find the correct caller (1 = function calling wfWarn, ...)
 * @param $level Integer: PHP error level; only used when $wgDevelopmentWarnings
 *        is true
 */
function wfWarn($msg, $callerOffset = 1, $level = E_USER_NOTICE)
{
    global $wgDevelopmentWarnings;
    MWDebug::warning($msg, $callerOffset + 2);
    $callers = wfDebugBacktrace();
    if (isset($callers[$callerOffset + 1])) {
        $callerfunc = $callers[$callerOffset + 1];
        $callerfile = $callers[$callerOffset];
        if (isset($callerfile['file']) && isset($callerfile['line'])) {
            $file = $callerfile['file'] . ' at line ' . $callerfile['line'];
        } else {
            $file = '(internal function)';
        }
        $func = '';
        if (isset($callerfunc['class'])) {
            $func .= $callerfunc['class'] . '::';
        }
        if (isset($callerfunc['function'])) {
            $func .= $callerfunc['function'];
        }
        $msg .= " [Called from {$func} in {$file}]";
    }
    if ($wgDevelopmentWarnings) {
        trigger_error($msg, $level);
    } else {
        wfDebug("{$msg}\n");
    }
}
Example #7
0
 /**
  * Generate debug data HTML for displaying at the bottom of the main content
  * area.
  * @return String HTML containing debug data, if enabled (otherwise empty).
  */
 protected function generateDebugHTML()
 {
     global $wgShowDebug;
     $html = MWDebug::getDebugHTML($this->getContext());
     if ($wgShowDebug) {
         $listInternals = $this->formatDebugHTML($this->getOutput()->mDebugtext);
         $html .= "\n<hr />\n<strong>Debug data:</strong><ul id=\"mw-debug-html\">" . $listInternals . "</ul>\n";
     }
     return $html;
 }
Example #8
0
 /**
  * Output the basic end-page trail including bottomscripts, reporttime, and
  * debug stuff. This should be called right before outputting the closing
  * body and html tags.
  */
 function printTrail()
 {
     echo MWDebug::getDebugHTML($this->getSkin()->getContext());
     $this->html('bottomscripts');
     /* JS call to runBodyOnloadHook */
     $this->html('reporttime');
 }
Example #9
0
 /**
  * Finally, all the text has been munged and accumulated into
  * the object, let's actually output it:
  */
 public function output()
 {
     global $wgLanguageCode, $wgDebugRedirects, $wgMimeType, $wgVaryOnXFP, $wgUseAjax, $wgResponsiveImages;
     if ($this->mDoNothing) {
         return;
     }
     wfProfileIn(__METHOD__);
     $response = $this->getRequest()->response();
     if ($this->mRedirect != '') {
         # Standards require redirect URLs to be absolute
         $this->mRedirect = wfExpandUrl($this->mRedirect, PROTO_CURRENT);
         $redirect = $this->mRedirect;
         $code = $this->mRedirectCode;
         if (wfRunHooks("BeforePageRedirect", array($this, &$redirect, &$code))) {
             if ($code == '301' || $code == '303') {
                 if (!$wgDebugRedirects) {
                     $message = HttpStatus::getMessage($code);
                     $response->header("HTTP/1.1 {$code} {$message}");
                 }
                 $this->mLastModified = wfTimestamp(TS_RFC2822);
             }
             if ($wgVaryOnXFP) {
                 $this->addVaryHeader('X-Forwarded-Proto');
             }
             $this->sendCacheControl();
             $response->header("Content-Type: text/html; charset=utf-8");
             if ($wgDebugRedirects) {
                 $url = htmlspecialchars($redirect);
                 print "<html>\n<head>\n<title>Redirect</title>\n</head>\n<body>\n";
                 print "<p>Location: <a href=\"{$url}\">{$url}</a></p>\n";
                 print "</body>\n</html>\n";
             } else {
                 $response->header('Location: ' . $redirect);
             }
         }
         wfProfileOut(__METHOD__);
         return;
     } elseif ($this->mStatusCode) {
         $message = HttpStatus::getMessage($this->mStatusCode);
         if ($message) {
             $response->header('HTTP/1.1 ' . $this->mStatusCode . ' ' . $message);
         }
     }
     # Buffer output; final headers may depend on later processing
     ob_start();
     $response->header("Content-type: {$wgMimeType}; charset=UTF-8");
     $response->header('Content-language: ' . $wgLanguageCode);
     // Prevent framing, if requested
     $frameOptions = $this->getFrameOptions();
     if ($frameOptions) {
         $response->header("X-Frame-Options: {$frameOptions}");
     }
     if ($this->mArticleBodyOnly) {
         echo $this->mBodytext;
     } else {
         $sk = $this->getSkin();
         // add skin specific modules
         $modules = $sk->getDefaultModules();
         // enforce various default modules for all skins
         $coreModules = array('mediawiki.page.startup', 'mediawiki.user');
         // Support for high-density display images if enabled
         if ($wgResponsiveImages) {
             $coreModules[] = 'mediawiki.hidpi';
         }
         $this->addModules($coreModules);
         foreach ($modules as $group) {
             $this->addModules($group);
         }
         MWDebug::addModules($this);
         if ($wgUseAjax) {
             // FIXME: deprecate? - not clear why this is useful
             wfRunHooks('AjaxAddScript', array(&$this));
         }
         // Hook that allows last minute changes to the output page, e.g.
         // adding of CSS or Javascript by extensions.
         wfRunHooks('BeforePageDisplay', array(&$this, &$sk));
         wfProfileIn('Output-skin');
         $sk->outputPage();
         wfProfileOut('Output-skin');
     }
     // This hook allows last minute changes to final overall output by modifying output buffer
     wfRunHooks('AfterFinalPageOutput', array($this));
     $this->sendCacheControl();
     ob_end_flush();
     wfProfileOut(__METHOD__);
 }
Example #10
0
 /**
  * Execute and profile the query. This is a wrapper for capturing timing information
  * while executing a query.
  *
  * @param string $sql the query
  * @param string $fname the function name
  * @param bool $isMaster is this against the master
  *
  * @return ResultWrapper|resource|bool see doQuery
  */
 protected function executeAndProfileQuery($sql, $fname, $isMaster)
 {
     $queryId = MWDebug::query($sql, $fname, $isMaster);
     $start = microtime(true);
     // Wikia change: DatabaseMysql returns a resource instead of ResultWrapper instance
     /* @var $ret resource|bool */
     $ret = $this->doQuery($sql);
     $this->logSql($sql, $ret, $fname, microtime(true) - $start, $isMaster);
     MWDebug::queryTime($queryId);
     return $ret;
 }
Example #11
0
}
$wgSessionsInObjectCache = true;
if ($wgPHPSessionHandling !== 'enable' && $wgPHPSessionHandling !== 'warn' && $wgPHPSessionHandling !== 'disable') {
    $wgPHPSessionHandling = 'warn';
}
if (defined('MW_NO_SESSION')) {
    // If the entry point wants no session, force 'disable' here unless they
    // specifically set it to the (undocumented) 'warn'.
    $wgPHPSessionHandling = MW_NO_SESSION === 'warn' ? 'warn' : 'disable';
}
Profiler::instance()->scopedProfileOut($ps_default);
// Disable MWDebug for command line mode, this prevents MWDebug from eating up
// all the memory from logging SQL queries on maintenance scripts
global $wgCommandLineMode;
if ($wgDebugToolbar && !$wgCommandLineMode) {
    MWDebug::init();
}
if (!class_exists('AutoLoader')) {
    require_once "{$IP}/includes/AutoLoader.php";
}
// Reset the global service locator, so any services that have already been created will be
// re-created while taking into account any custom settings and extensions.
MediaWikiServices::resetGlobalInstance(new GlobalVarConfig(), 'quick');
if ($wgSharedDB && $wgSharedTables) {
    // Apply $wgSharedDB table aliases for the local LB (all non-foreign DB connections)
    MediaWikiServices::getInstance()->getDBLoadBalancer()->setTableAliases(array_fill_keys($wgSharedTables, ['dbname' => $wgSharedDB, 'schema' => $wgSharedSchema, 'prefix' => $wgSharedPrefix]));
}
// Define a constant that indicates that the bootstrapping of the service locator
// is complete.
define('MW_SERVICE_BOOTSTRAP_COMPLETE', 1);
// Install a header callback to prevent caching of responses with cookies (T127993)
Example #12
0
 /**
  * Run an SQL query and return the result. Normally throws a DBQueryError
  * on failure. If errors are ignored, returns false instead.
  *
  * In new code, the query wrappers select(), insert(), update(), delete(),
  * etc. should be used where possible, since they give much better DBMS
  * independence and automatically quote or validate user input in a variety
  * of contexts. This function is generally only useful for queries which are
  * explicitly DBMS-dependent and are unsupported by the query wrappers, such
  * as CREATE TABLE.
  *
  * However, the query wrappers themselves should call this function.
  *
  * @param string $sql SQL query
  * @param string $fname Name of the calling function, for profiling/SHOW PROCESSLIST
  *     comment (you can use __METHOD__ or add some extra info)
  * @param bool $tempIgnore Whether to avoid throwing an exception on errors...
  *     maybe best to catch the exception instead?
  * @throws MWException
  * @return bool|ResultWrapper True for a successful write query, ResultWrapper object
  *     for a successful read query, or false on failure if $tempIgnore set
  */
 public function query($sql, $fname = __METHOD__, $tempIgnore = false)
 {
     global $wgUser;
     $this->mLastQuery = $sql;
     $isWriteQuery = $this->isWriteQuery($sql);
     if ($isWriteQuery) {
         $reason = $this->getReadOnlyReason();
         if ($reason !== false) {
             throw new DBReadOnlyError($this, "Database is read-only: {$reason}");
         }
         # Set a flag indicating that writes have been done
         $this->mDoneWrites = microtime(true);
     }
     # Add a comment for easy SHOW PROCESSLIST interpretation
     if (is_object($wgUser) && $wgUser->isItemLoaded('name')) {
         $userName = $wgUser->getName();
         if (mb_strlen($userName) > 15) {
             $userName = mb_substr($userName, 0, 15) . '...';
         }
         $userName = str_replace('/', '', $userName);
     } else {
         $userName = '';
     }
     // Add trace comment to the begin of the sql string, right after the operator.
     // Or, for one-word queries (like "BEGIN" or COMMIT") add it to the end (bug 42598)
     $commentedSql = preg_replace('/\\s|$/', " /* {$fname} {$userName} */ ", $sql, 1);
     if (!$this->mTrxLevel && $this->getFlag(DBO_TRX) && $this->isTransactableQuery($sql)) {
         $this->begin(__METHOD__ . " ({$fname})");
         $this->mTrxAutomatic = true;
     }
     # Keep track of whether the transaction has write queries pending
     if ($this->mTrxLevel && !$this->mTrxDoneWrites && $isWriteQuery) {
         $this->mTrxDoneWrites = true;
         $this->getTransactionProfiler()->transactionWritingIn($this->mServer, $this->mDBname, $this->mTrxShortId);
     }
     $isMaster = !is_null($this->getLBInfo('master'));
     # generalizeSQL will probably cut down the query to reasonable
     # logging size most of the time. The substr is really just a sanity check.
     if ($isMaster) {
         $queryProf = 'query-m: ' . substr(DatabaseBase::generalizeSQL($sql), 0, 255);
         $totalProf = 'DatabaseBase::query-master';
     } else {
         $queryProf = 'query: ' . substr(DatabaseBase::generalizeSQL($sql), 0, 255);
         $totalProf = 'DatabaseBase::query';
     }
     # Include query transaction state
     $queryProf .= $this->mTrxShortId ? " [TRX#{$this->mTrxShortId}]" : "";
     $profiler = Profiler::instance();
     if (!$profiler instanceof ProfilerStub) {
         $totalProfSection = $profiler->scopedProfileIn($totalProf);
         $queryProfSection = $profiler->scopedProfileIn($queryProf);
     }
     if ($this->debug()) {
         wfDebugLog('queries', sprintf("%s: %s", $this->mDBname, $sql));
     }
     $queryId = MWDebug::query($sql, $fname, $isMaster);
     # Avoid fatals if close() was called
     $this->assertOpen();
     # Do the query and handle errors
     $startTime = microtime(true);
     $ret = $this->doQuery($commentedSql);
     $queryRuntime = microtime(true) - $startTime;
     # Log the query time and feed it into the DB trx profiler
     $this->getTransactionProfiler()->recordQueryCompletion($queryProf, $startTime, $isWriteQuery, $this->affectedRows());
     MWDebug::queryTime($queryId);
     # Try reconnecting if the connection was lost
     if (false === $ret && $this->wasErrorReissuable()) {
         # Transaction is gone, like it or not
         $hadTrx = $this->mTrxLevel;
         // possible lost transaction
         $this->mTrxLevel = 0;
         $this->mTrxIdleCallbacks = array();
         // bug 65263
         $this->mTrxPreCommitCallbacks = array();
         // bug 65263
         wfDebug("Connection lost, reconnecting...\n");
         # Stash the last error values since ping() might clear them
         $lastError = $this->lastError();
         $lastErrno = $this->lastErrno();
         if ($this->ping()) {
             wfDebug("Reconnected\n");
             $server = $this->getServer();
             $msg = __METHOD__ . ": lost connection to {$server}; reconnected";
             wfDebugLog('DBPerformance', "{$msg}:\n" . wfBacktrace(true));
             if ($hadTrx) {
                 # Leave $ret as false and let an error be reported.
                 # Callers may catch the exception and continue to use the DB.
                 $this->reportQueryError($lastError, $lastErrno, $sql, $fname, $tempIgnore);
             } else {
                 # Should be safe to silently retry (no trx and thus no callbacks)
                 $startTime = microtime(true);
                 $ret = $this->doQuery($commentedSql);
                 $queryRuntime = microtime(true) - $startTime;
                 # Log the query time and feed it into the DB trx profiler
                 $this->getTransactionProfiler()->recordQueryCompletion($queryProf, $startTime, $isWriteQuery, $this->affectedRows());
             }
         } else {
             wfDebug("Failed\n");
         }
     }
     if (false === $ret) {
         $this->reportQueryError($this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore);
     }
     $res = $this->resultObject($ret);
     // Destroy profile sections in the opposite order to their creation
     ScopedCallback::consume($queryProfSection);
     ScopedCallback::consume($totalProfSection);
     if ($isWriteQuery && $this->mTrxLevel) {
         $this->mTrxWriteDuration += $queryRuntime;
     }
     return $res;
 }
Example #13
0
	/**
	 * Run an SQL query and return the result. Normally throws a DBQueryError
	 * on failure. If errors are ignored, returns false instead.
	 *
	 * In new code, the query wrappers select(), insert(), update(), delete(),
	 * etc. should be used where possible, since they give much better DBMS
	 * independence and automatically quote or validate user input in a variety
	 * of contexts. This function is generally only useful for queries which are
	 * explicitly DBMS-dependent and are unsupported by the query wrappers, such
	 * as CREATE TABLE.
	 *
	 * However, the query wrappers themselves should call this function.
	 *
	 * @param  $sql        String: SQL query
	 * @param  $fname      String: Name of the calling function, for profiling/SHOW PROCESSLIST
	 *     comment (you can use __METHOD__ or add some extra info)
	 * @param  $tempIgnore Boolean:   Whether to avoid throwing an exception on errors...
	 *     maybe best to catch the exception instead?
	 * @throws MWException
	 * @return boolean|ResultWrapper. true for a successful write query, ResultWrapper object
	 *     for a successful read query, or false on failure if $tempIgnore set
	 */
	public function query( $sql, $fname = __METHOD__, $tempIgnore = false ) {
		global $wgUser, $wgDebugDBTransactions;

		$this->mLastQuery = $sql;
		if ( !$this->mDoneWrites && $this->isWriteQuery( $sql ) ) {
			# Set a flag indicating that writes have been done
			wfDebug( __METHOD__ . ": Writes done: $sql\n" );
			$this->mDoneWrites = true;
		}

		# Add a comment for easy SHOW PROCESSLIST interpretation
		if ( is_object( $wgUser ) && $wgUser->isItemLoaded( 'name' ) ) {
			$userName = $wgUser->getName();
			if ( mb_strlen( $userName ) > 15 ) {
				$userName = mb_substr( $userName, 0, 15 ) . '...';
			}
			$userName = str_replace( '/', '', $userName );
		} else {
			$userName = '';
		}

		// Add trace comment to the begin of the sql string, right after the operator.
		// Or, for one-word queries (like "BEGIN" or COMMIT") add it to the end (bug 42598)
		$commentedSql = preg_replace( '/\s|$/', " /* $fname $userName */ ", $sql, 1 );

		# If DBO_TRX is set, start a transaction
		if ( ( $this->mFlags & DBO_TRX ) && !$this->mTrxLevel &&
			$sql != 'BEGIN' && $sql != 'COMMIT' && $sql != 'ROLLBACK' )
		{
			# Avoid establishing transactions for SHOW and SET statements too -
			# that would delay transaction initializations to once connection
			# is really used by application
			$sqlstart = substr( $sql, 0, 10 ); // very much worth it, benchmark certified(tm)
			if ( strpos( $sqlstart, "SHOW " ) !== 0 && strpos( $sqlstart, "SET " ) !== 0 ) {
				if ( $wgDebugDBTransactions ) {
					wfDebug( "Implicit transaction start.\n" );
				}
				$this->begin( __METHOD__ . " ($fname)" );
				$this->mTrxAutomatic = true;
			}
		}

		# Keep track of whether the transaction has write queries pending
		if ( $this->mTrxLevel && !$this->mTrxDoneWrites && $this->isWriteQuery( $sql ) ) {
			$this->mTrxDoneWrites = true;
			Profiler::instance()->transactionWritingIn( $this->mServer, $this->mDBname );
		}

		$isMaster = !is_null( $this->getLBInfo( 'master' ) );
		if ( !Profiler::instance()->isStub() ) {
			# generalizeSQL will probably cut down the query to reasonable
			# logging size most of the time. The substr is really just a sanity check.
			if ( $isMaster ) {
				$queryProf = 'query-m: ' . substr( DatabaseBase::generalizeSQL( $sql ), 0, 255 );
				$totalProf = 'DatabaseBase::query-master';
			} else {
				$queryProf = 'query: ' . substr( DatabaseBase::generalizeSQL( $sql ), 0, 255 );
				$totalProf = 'DatabaseBase::query';
			}
			wfProfileIn( $totalProf );
			wfProfileIn( $queryProf );
		}

		if ( $this->debug() ) {
			static $cnt = 0;

			$cnt++;
			$sqlx = substr( $commentedSql, 0, 500 );
			$sqlx = strtr( $sqlx, "\t\n", '  ' );

			$master = $isMaster ? 'master' : 'slave';
			wfDebug( "Query {$this->mDBname} ($cnt) ($master): $sqlx\n" );
		}

		$queryId = MWDebug::query( $sql, $fname, $isMaster );

		# Do the query and handle errors
		$ret = $this->doQuery( $commentedSql );

		MWDebug::queryTime( $queryId );

		# Try reconnecting if the connection was lost
		if ( false === $ret && $this->wasErrorReissuable() ) {
			# Transaction is gone, like it or not
			$this->mTrxLevel = 0;
			$this->mTrxIdleCallbacks = array(); // cancel
			$this->mTrxPreCommitCallbacks = array(); // cancel
			wfDebug( "Connection lost, reconnecting...\n" );

			if ( $this->ping() ) {
				wfDebug( "Reconnected\n" );
				$sqlx = substr( $commentedSql, 0, 500 );
				$sqlx = strtr( $sqlx, "\t\n", '  ' );
				global $wgRequestTime;
				$elapsed = round( microtime( true ) - $wgRequestTime, 3 );
				if ( $elapsed < 300 ) {
					# Not a database error to lose a transaction after a minute or two
					wfLogDBError( "Connection lost and reconnected after {$elapsed}s, query: $sqlx\n" );
				}
				$ret = $this->doQuery( $commentedSql );
			} else {
				wfDebug( "Failed\n" );
			}
		}

		if ( false === $ret ) {
			$this->reportQueryError( $this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore );
		}

		if ( !Profiler::instance()->isStub() ) {
			wfProfileOut( $queryProf );
			wfProfileOut( $totalProf );
		}

		return $this->resultObject( $ret );
	}
Example #14
0
 /**
  * Add the default ResourceLoader modules to this object
  */
 private function addDefaultModules()
 {
     global $wgIncludeLegacyJavaScript, $wgPreloadJavaScriptMwUtil, $wgUseAjax, $wgAjaxWatch, $wgEnableMWSuggest;
     // Add base resources
     $this->addModules(array('mediawiki.user', 'mediawiki.page.startup', 'mediawiki.page.ready'));
     if ($wgIncludeLegacyJavaScript) {
         $this->addModules('mediawiki.legacy.wikibits');
     }
     if ($wgPreloadJavaScriptMwUtil) {
         $this->addModules('mediawiki.util');
     }
     MWDebug::addModules($this);
     $skin = $this->getSkin();
     // Add various resources if required
     if ($wgUseAjax) {
         # macbre: following files are part of merged JS for following skins - don't load them from here
         $skinName = get_class($skin);
         $skipWikiaSkins = array();
         if (!in_array($skinName, $skipWikiaSkins)) {
             $this->addModules('mediawiki.legacy.ajax');
         }
         wfRunHooks('AjaxAddScript', array(&$this));
         if (!in_array($skinName, $skipWikiaSkins)) {
             if ($wgAjaxWatch && $this->getUser()->isLoggedIn()) {
                 $this->addModules('mediawiki.action.watch.ajax');
             }
         }
         if (!in_array($skinName, $skipWikiaSkins)) {
             if ($wgEnableMWSuggest && !$this->getUser()->getOption('disablesuggest', false)) {
                 $this->addModules('mediawiki.legacy.mwsuggest');
             }
         }
     }
     if ($this->getUser()->getBoolOption('editsectiononrightclick')) {
         $this->addModules('mediawiki.action.view.rightClickEdit');
     }
     # Crazy edit-on-double-click stuff
     if ($this->isArticle() && $this->getUser()->getOption('editondblclick')) {
         $this->addModules('mediawiki.action.view.dblClickEdit');
     }
 }
Example #15
0
 /**
  * Execute the actual module, without any error handling
  */
 protected function executeAction()
 {
     $params = $this->setupExecuteAction();
     $module = $this->setupModule();
     $this->checkExecutePermissions($module);
     if (!$this->checkMaxLag($module, $params)) {
         return;
     }
     if (!$this->mInternalMode) {
         $this->setupExternalResponse($module, $params);
     }
     // Execute
     $module->profileIn();
     $module->execute();
     wfRunHooks('APIAfterExecute', array(&$module));
     $module->profileOut();
     if (!$this->mInternalMode) {
         //append Debug information
         MWDebug::appendDebugInfoToApiResult($this->getContext(), $this->getResult());
         // Print result data
         $this->printResult(false);
     }
 }
Example #16
0
 /**
  * Add the default ResourceLoader modules to this object
  */
 private function addDefaultModules()
 {
     global $wgIncludeLegacyJavaScript, $wgPreloadJavaScriptMwUtil, $wgUseAjax, $wgAjaxWatch, $wgEnableMWSuggest;
     // Add base resources
     $this->addModules(array('mediawiki.user', 'mediawiki.page.startup', 'mediawiki.page.ready'));
     if ($wgIncludeLegacyJavaScript) {
         $this->addModules('mediawiki.legacy.wikibits');
     }
     if ($wgPreloadJavaScriptMwUtil) {
         $this->addModules('mediawiki.util');
     }
     MWDebug::addModules($this);
     // Add various resources if required
     if ($wgUseAjax) {
         $this->addModules('mediawiki.legacy.ajax');
         wfRunHooks('AjaxAddScript', array(&$this));
         if ($wgAjaxWatch && $this->getUser()->isLoggedIn()) {
             $this->addModules('mediawiki.action.watch.ajax');
         }
         if ($wgEnableMWSuggest && !$this->getUser()->getOption('disablesuggest', false)) {
             $this->addModules('mediawiki.legacy.mwsuggest');
         }
     }
     if ($this->getUser()->getBoolOption('editsectiononrightclick')) {
         $this->addModules('mediawiki.action.view.rightClickEdit');
     }
     # Crazy edit-on-double-click stuff
     if ($this->isArticle() && $this->getUser()->getOption('editondblclick')) {
         $this->addModules('mediawiki.action.view.dblClickEdit');
     }
 }
Example #17
0
 /**
  * Run an SQL query and return the result. Normally throws a DBQueryError
  * on failure. If errors are ignored, returns false instead.
  *
  * In new code, the query wrappers select(), insert(), update(), delete(),
  * etc. should be used where possible, since they give much better DBMS
  * independence and automatically quote or validate user input in a variety
  * of contexts. This function is generally only useful for queries which are
  * explicitly DBMS-dependent and are unsupported by the query wrappers, such
  * as CREATE TABLE.
  *
  * However, the query wrappers themselves should call this function.
  *
  * @param  $sql        String: SQL query
  * @param  $fname      String: Name of the calling function, for profiling/SHOW PROCESSLIST
  *     comment (you can use __METHOD__ or add some extra info)
  * @param  $tempIgnore Boolean:   Whether to avoid throwing an exception on errors...
  *     maybe best to catch the exception instead?
  * @return boolean|ResultWrapper. true for a successful write query, ResultWrapper object
  *     for a successful read query, or false on failure if $tempIgnore set
  * @throws DBQueryError Thrown when the database returns an error of any kind
  */
 public function query($sql, $fname = '', $tempIgnore = false)
 {
     $isMaster = !is_null($this->getLBInfo('master'));
     if (!Profiler::instance()->isStub()) {
         # generalizeSQL will probably cut down the query to reasonable
         # logging size most of the time. The substr is really just a sanity check.
         if ($isMaster) {
             $queryProf = 'query-m: ' . substr(DatabaseBase::generalizeSQL($sql), 0, 255);
             $totalProf = 'DatabaseBase::query-master';
         } else {
             $queryProf = 'query: ' . substr(DatabaseBase::generalizeSQL($sql), 0, 255);
             $totalProf = 'DatabaseBase::query';
         }
         wfProfileIn($totalProf);
         wfProfileIn($queryProf);
     }
     $this->mLastQuery = $sql;
     if (!$this->mDoneWrites && $this->isWriteQuery($sql)) {
         # Set a flag indicating that writes have been done
         wfDebug(__METHOD__ . ": Writes done: {$sql}\n");
         $this->mDoneWrites = true;
     }
     # Add a comment for easy SHOW PROCESSLIST interpretation
     global $wgUser;
     if (is_object($wgUser) && $wgUser->isItemLoaded('name')) {
         $userName = $wgUser->getName();
         if (mb_strlen($userName) > 15) {
             $userName = mb_substr($userName, 0, 15) . '...';
         }
         $userName = str_replace('/', '', $userName);
     } else {
         $userName = '';
     }
     $commentedSql = preg_replace('/\\s/', " /* {$fname} {$userName} */ ", $sql, 1);
     # If DBO_TRX is set, start a transaction
     if ($this->mFlags & DBO_TRX && !$this->trxLevel() && $sql != 'BEGIN' && $sql != 'COMMIT' && $sql != 'ROLLBACK') {
         # avoid establishing transactions for SHOW and SET statements too -
         # that would delay transaction initializations to once connection
         # is really used by application
         $sqlstart = substr($sql, 0, 10);
         // very much worth it, benchmark certified(tm)
         if (strpos($sqlstart, "SHOW ") !== 0 && strpos($sqlstart, "SET ") !== 0) {
             $this->begin(__METHOD__ . " ({$fname})");
         }
     }
     if ($this->debug()) {
         static $cnt = 0;
         $cnt++;
         $sqlx = substr($commentedSql, 0, 500);
         $sqlx = strtr($sqlx, "\t\n", '  ');
         $master = $isMaster ? 'master' : 'slave';
         wfDebug("Query {$this->mDBname} ({$cnt}) ({$master}): {$sqlx}\n");
     }
     if (istainted($sql) & TC_MYSQL) {
         throw new MWException('Tainted query found');
     }
     $queryId = MWDebug::query($sql, $fname, $isMaster);
     # Do the query and handle errors
     $ret = $this->doQuery($commentedSql);
     MWDebug::queryTime($queryId);
     # Try reconnecting if the connection was lost
     if (false === $ret && $this->wasErrorReissuable()) {
         # Transaction is gone, like it or not
         $this->mTrxLevel = 0;
         wfDebug("Connection lost, reconnecting...\n");
         if ($this->ping()) {
             wfDebug("Reconnected\n");
             $sqlx = substr($commentedSql, 0, 500);
             $sqlx = strtr($sqlx, "\t\n", '  ');
             global $wgRequestTime;
             $elapsed = round(microtime(true) - $wgRequestTime, 3);
             if ($elapsed < 300) {
                 # Not a database error to lose a transaction after a minute or two
                 wfLogDBError("Connection lost and reconnected after {$elapsed}s, query: {$sqlx}\n");
             }
             $ret = $this->doQuery($commentedSql);
         } else {
             wfDebug("Failed\n");
         }
     }
     if (false === $ret) {
         $this->reportQueryError($this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore);
     }
     if (!Profiler::instance()->isStub()) {
         wfProfileOut($queryProf);
         wfProfileOut($totalProf);
     }
     return $this->resultObject($ret);
 }
Example #18
0
 /**
  * Returns the HTML to add to the page for the toolbar
  *
  * @param $context IContextSource
  * @return string
  */
 public static function getDebugHTML(IContextSource $context)
 {
     if (!self::$enabled) {
         return '';
     }
     global $wgVersion, $wgRequestTime;
     MWDebug::log('MWDebug output complete');
     $request = $context->getRequest();
     $debugInfo = array('mwVersion' => $wgVersion, 'phpVersion' => PHP_VERSION, 'time' => microtime(true) - $wgRequestTime, 'log' => self::$log, 'debugLog' => self::$debug, 'queries' => self::$query, 'request' => array('method' => $_SERVER['REQUEST_METHOD'], 'url' => $request->getRequestURL(), 'headers' => $request->getAllHeaders(), 'params' => $request->getValues()), 'memory' => $context->getLanguage()->formatSize(memory_get_usage()), 'memoryPeak' => $context->getLanguage()->formatSize(memory_get_peak_usage()), 'includes' => self::getFilesIncluded($context));
     // Cannot use OutputPage::addJsConfigVars because those are already outputted
     // by the time this method is called.
     $html = Html::inlineScript(ResourceLoader::makeLoaderConditionalScript(ResourceLoader::makeConfigSetScript(array('debugInfo' => $debugInfo))));
     return $html;
 }
Example #19
0
 /**
  * Append the debug info to given ApiResult
  *
  * @param $context IContextSource
  * @param $result ApiResult
  */
 public static function appendDebugInfoToApiResult(IContextSource $context, ApiResult $result)
 {
     if (!self::$enabled) {
         return;
     }
     // output errors as debug info, when display_errors is on
     // this is necessary for all non html output of the api, because that clears all errors first
     $obContents = ob_get_contents();
     if ($obContents) {
         $obContentArray = explode('<br />', $obContents);
         foreach ($obContentArray as $obContent) {
             if (trim($obContent)) {
                 self::debugMsg(Sanitizer::stripAllTags($obContent));
             }
         }
     }
     MWDebug::log('MWDebug output complete');
     $debugInfo = self::getDebugInfo($context);
     $result->setIndexedTagName($debugInfo, 'debuginfo');
     $result->setIndexedTagName($debugInfo['log'], 'line');
     $result->setIndexedTagName($debugInfo['debugLog'], 'msg');
     $result->setIndexedTagName($debugInfo['queries'], 'query');
     $result->setIndexedTagName($debugInfo['includes'], 'queries');
     $result->addValue(null, 'debuginfo', $debugInfo);
 }
Example #20
0
 function printTrail()
 {
     echo MWDebug::getDebugHTML($this->getSkin()->getContext());
 }
Example #21
0
 static function onImageBeforeProduceHTML(&$dummy, &$title, &$file, &$frameParams, &$handlerParams, &$time, &$res)
 {
     if (!$file) {
         MWDebug::warning("could not load file from title: {$title}");
         return false;
     }
     return true;
 }
Example #22
0
 private function getNextTip($content)
 {
     $showCoachTip = $this->showCoachTip(&$content);
     $coachTip = null;
     if ($showCoachTip) {
         $coachTip = $this->getCoachTip(&$content);
         MWDebug::log("this will be a coach tip");
     }
     if (!$coachTip) {
         $this->getDBTip(&$content);
     }
 }
Example #23
0
 /**
  * Generate debug data HTML for displaying at the bottom of the main content
  * area.
  * @return String HTML containing debug data, if enabled (otherwise empty).
  */
 protected function generateDebugHTML()
 {
     return MWDebug::getHTMLDebugLog();
 }
 public function execute($parameters)
 {
     global $wgContentTranslationUseMagnusTool, $wgContentTranslationTranslateInTarget;
     $out = $this->getOutput();
     $skin = $this->getSkin();
     $request = $this->getRequest();
     $user = $this->getUser();
     $hasToken = $this->hasToken();
     $campaign = $request->getVal('campaign');
     $isCampaign = $this->isValidCampaign($campaign);
     // Direct access, isListed only affects Special:SpecialPages
     if (!ContentTranslationHooks::isEnabledForUser($user)) {
         if ($hasToken || $isCampaign) {
             // User has a token. Enabled cx for the user in this wiki.
             $this->enableCXBetaFeature();
         } else {
             if ($campaign) {
                 // Show login page if the URL has campaign parameter
                 $out->showPermissionsErrorPage(array(array('badaccess-groups')), 'edit');
                 return;
             }
             $out->showErrorPage('nosuchspecialpage', 'nospecialpagetext');
             return;
         }
     }
     // Preloading to avoid FOUC
     $out->addModuleStyles('ext.cx.header.skin');
     if ($hasToken) {
         $out->addModules('ext.cx.translationview');
         // If Wikibase is installed, load the module for linking
         // the published article with the source article
         if ($wgContentTranslationTranslateInTarget && defined('WBC_VERSION')) {
             $out->addModules('ext.cx.wikibase.link');
         }
     } else {
         $out->addModules('ext.cx.dashboard');
         if ($wgContentTranslationUseMagnusTool) {
             $out->addModules('ext.cx.magnuslink');
         }
     }
     $this->setHeaders();
     $out->setArticleBodyOnly(true);
     // Default modules copied from OutputPage::addDefaultModules
     $out->addModules(array('mediawiki.user', 'mediawiki.page.startup', 'mediawiki.page.ready'));
     // Load legacy modules if any, for the skin.
     // Some wikis have Common.js scripts that depend on this module.
     $defaultSkinModules = $skin->getDefaultModules();
     $out->addModules($defaultSkinModules['legacy']);
     Hooks::run('BeforePageDisplay', array(&$out, &$skin));
     // T111668: Make sure we generate the personal tools
     // before we output the head, as extensions may add
     // things using the PersonalUrls hook.
     $toolbarList = Html::rawElement('ul', null, $skin->getPersonalToolsList());
     $out->addHTML($out->headElement($skin));
     $out->addHTML(Html::element('noscript', array(), $this->msg('cx-javascript')->text()));
     $out->addHtml(MWDebug::getDebugHTML($this->getContext()));
     $out->addHTML(Html::rawElement('div', array('id' => 'p-personal'), $toolbarList));
     $out->addHTML($skin->bottomScripts());
     $out->addHTML('</body></html>');
 }
Example #25
0
/**
 * Send a warning as a PHP error and the debug log. This is intended for logging
 * warnings in production. For logging development warnings, use WfWarn instead.
 *
 * @param string $msg Message to send
 * @param int $callerOffset Number of items to go back in the backtrace to
 *        find the correct caller (1 = function calling wfLogWarning, ...)
 * @param int $level PHP error level; defaults to E_USER_WARNING
 */
function wfLogWarning($msg, $callerOffset = 1, $level = E_USER_WARNING)
{
    MWDebug::warning($msg, $callerOffset + 1, $level, 'production');
}
Example #26
0
 static function getNextArticleToPatrolInner($rcid = null)
 {
     global $wgRequest, $wgUser, $wgCookiePrefix;
     $show_namespace = $wgRequest->getVal('namespace');
     $invert = $wgRequest->getVal('invert');
     $reverse = $wgRequest->getVal('reverse');
     $featured = $wgRequest->getVal('featured');
     $title = $wgRequest->getVal('target');
     $skiptitle = $wgRequest->getVal('skiptitle');
     $rc_user_filter = trim(urldecode($wgRequest->getVal('rc_user_filter')));
     // assert that current user is not anon
     if ($wgUser->isAnon()) {
         return null;
     }
     // In English, when a user rolls back an edit, it gives the edit a comment
     // like: "Reverted edits by ...", so MediaWiki:rollback_comment_prefix
     // is set to "Reverted" in English wikiHow.
     $rollbackCommentPrefix = wfMessage('rollback_comment_prefix')->plain();
     if (empty($rollbackCommentPrefix) || strpos($rollbackCommentPrefix, '&') === 0) {
         die("Cannot use RCPatrol feature until MediaWiki:rollback_comment_prefix is set up properly");
     }
     $t = null;
     if ($title) {
         $t = Title::newFromText($title);
     }
     $skip = null;
     if ($skiptitle) {
         $skip = Title::newFromText($skiptitle);
     }
     $dbr = wfGetDB(DB_MASTER);
     /*	DEPRECATED rc_moved_to_ns & rc_moved_to_title columns
     			$sql = "SELECT rc_id, rc_cur_id, rc_moved_to_ns, rc_moved_to_title, rc_new, 
     			  rc_namespace, rc_title, rc_last_oldid, rc_this_oldid 
     			FROM recentchanges 
     			LEFT OUTER JOIN page ON rc_cur_id = page_id AND rc_namespace = page_namespace 
     			WHERE ";*/
     $sql = "SELECT rc_id, rc_cur_id, rc_new, rc_namespace, rc_title, rc_last_oldid, rc_this_oldid \n\t\t\tFROM recentchanges \n\t\t\tLEFT OUTER JOIN page ON rc_cur_id = page_id AND rc_namespace = page_namespace \n\t\t\tWHERE ";
     if (!$wgRequest->getVal('ignore_rcid') && $rcid) {
         $sql .= " rc_id " . ($reverse == 1 ? " > " : " < ") . " {$rcid} and ";
     }
     // if we filter by user we show both patrolled and non-patrolled edits
     if ($rc_user_filter) {
         $sql .= " rc_user_text = " . $dbr->addQuotes($rc_user_filter);
         if ($rcid) {
             $sql .= " AND rc_id < " . $rcid;
         }
     } else {
         $sql .= " rc_patrolled = 0 ";
     }
     // can't patrol your own edits
     $sql .= " AND rc_user <> " . $wgUser->getID();
     // only featured?
     if ($featured) {
         $sql .= " AND page_is_featured = 1 ";
     }
     if ($show_namespace) {
         $sql .= " AND rc_namespace " . ($invert ? '<>' : '=') . $show_namespace;
     } else {
         // always ignore video
         $sql .= " AND rc_namespace <> " . NS_VIDEO;
     }
     // log entries have namespace = -1, we don't want to show those, hide bots too
     $sql .= " AND rc_namespace >= 0 AND rc_bot = 0 ";
     if ($t) {
         $sql .= " AND rc_title <> " . $dbr->addQuotes($t->getDBKey());
     }
     if ($skip) {
         $sql .= " AND rc_title <> " . $dbr->addQuotes($skip->getDBKey());
     }
     $sa = $wgRequest->getVal('sa');
     if ($sa) {
         $sa = Title::newFromText($sa);
         $sql .= " AND rc_title = " . $dbr->addQuotes($sa->getDBKey());
     }
     // has the user skipped any articles?
     $cookiename = $wgCookiePrefix . "Rcskip";
     $skipids = "";
     if (isset($_COOKIE[$cookiename])) {
         $cookie_ids = array_unique(split(",", $_COOKIE[$cookiename]));
         $ids = array();
         //safety first
         foreach ($cookie_ids as $id) {
             $id = intval($id);
             if ($id > 0) {
                 $ids[] = $id;
             }
         }
         if ($ids) {
             $skipids = " AND rc_cur_id NOT IN (" . implode(",", $ids) . ") ";
         }
     }
     $sql .= "{$skipids} ORDER BY rc_timestamp " . ($reverse == 1 ? "" : "DESC ") . "LIMIT 1";
     $res = $dbr->query($sql, __METHOD__);
     $row = $res->fetchObject();
     /*$show=true;
     if ($show){
     var_dump($_GET);
     var_dump($_POST);
     echo $sql;
     var_dump($row);
     exit;
     }*/
     if ($row) {
         $result = array();
         $t = Title::makeTitle($row->rc_namespace, $row->rc_title);
         if ($t->isRedirect()) {
             $wp = new WikiPage($t);
             $t = $wp->getRedirectTarget();
         }
         // if title has been deleted set $t to null so we will skip it
         if (!$t->exists()) {
             MWDebug::log("{$t} does not exist");
             $t = null;
         }
         $result['rc_cur_id'] = $row->rc_cur_id;
         if ($rc_user_filter) {
             $result['rchi'] = $result['rclo'] = $row->rc_id;
             $result['new'] = $dbr->selectField('recentchanges', array('rc_this_oldid'), array('rc_id' => $row->rc_id));
         } else {
             // always compare to current version
             $result['new'] = $dbr->selectField('revision', array('max(rev_id)'), array('rev_page' => $row->rc_cur_id));
             $result['rchi'] = $dbr->selectField('recentchanges', array('rc_id'), array('rc_this_oldid' => $result['new']));
             $result['rclo'] = $dbr->selectField('recentchanges', array('min(rc_id)'), array('rc_patrolled' => 0, "rc_cur_id" => $row->rc_cur_id));
             // do we have a reverted edit caught between these 2?
             // if so, only show the reversion, because otherwise you get the reversion trapped in the middle
             // and it shows a weird diff page.
             $hi = isset($result['rchi']) ? $result['rchi'] : $row->rc_id;
             if ($hi) {
                 $reverted_id = $dbr->selectField('recentchanges', array('min(rc_id)'), array('rc_comment like ' . $dbr->addQuotes($rollbackCommentPrefix . '%'), "rc_id < {$hi}", "rc_id >= {$result['rclo']}", "rc_cur_id" => $row->rc_cur_id));
                 if ($reverted_id) {
                     $result['rchi'] = $reverted_id;
                     $result['new'] = $dbr->selectField('recentchanges', array('rc_this_oldid'), array('rc_id' => $reverted_id));
                     $row->rc_id = $result['rchi'];
                 }
                 //} else {
                 //	$email = new MailAddress("*****@*****.**");
                 //	$subject = "Could not find hi variable " . date("r");
                 //	$body = print_r($_SERVER, true) . "\n\n" . $sql . "\n\n" . print_r($result, true) . "\n\n\$hi: " . $hi;
                 //	UserMailer::send($email, $email, $subject, $body);
             }
             if (!$result['rclo']) {
                 $result['rclo'] = $row->rc_id;
             }
             if (!$result['rchi']) {
                 $result['rchi'] = $row->rc_id;
             }
             // is the last patrolled edit a rollback? if so, show the diff starting at that edit
             // makes it more clear when someone has reverted vandalism
             $result['vandal'] = 0;
             $comm = $dbr->selectField('recentchanges', array('rc_comment'), array('rc_id' => $result['rclo']));
             if (strpos($comm, $rollbackCommentPrefix) === 0) {
                 $row2 = $dbr->selectRow('recentchanges', array('rc_id', 'rc_comment'), array("rc_id < {$result['rclo']}", 'rc_cur_id' => $row->rc_cur_id), __METHOD__, array("ORDER BY" => "rc_id desc", "LIMIT" => 1));
                 if ($row2) {
                     $result['rclo'] = $row2->rc_id;
                 }
                 $result['vandal'] = 1;
             }
         }
         $result['user'] = $dbr->selectField('recentchanges', array('rc_user_text'), array('rc_this_oldid' => $result['new']));
         $result['old'] = $dbr->selectField('recentchanges', array('rc_last_oldid'), array('rc_id' => $result['rclo']));
         $result['title'] = $t;
         $result['rcid'] = $row->rc_id;
         if ($result['rchi'] == $result['rclo']) {
             $conds = array('rc_id' => $result['rchi']);
         } else {
             $conds = array('rc_id <= ' . $result['rchi'], 'rc_id >= ' . $result['rclo']);
         }
         $result['count'] = $dbr->selectField('recentchanges', array('count(*)'), array("rc_id <= " . $result['rchi'], "rc_id >= " . $result['rclo'], "rc_patrolled" => 0, "rc_cur_id" => $row->rc_cur_id));
         $result = self::getListofEditors($result);
         return $result;
     } else {
         return null;
     }
 }
Example #27
0
 /**
  * Execute the actual module, without any error handling
  */
 protected function executeAction()
 {
     $params = $this->setupExecuteAction();
     $module = $this->setupModule();
     $this->mModule = $module;
     $this->checkExecutePermissions($module);
     if (!$this->checkMaxLag($module, $params)) {
         return;
     }
     if (!$this->checkConditionalRequestHeaders($module)) {
         return;
     }
     if (!$this->mInternalMode) {
         $this->setupExternalResponse($module, $params);
     }
     $this->checkAsserts($params);
     // Execute
     $module->execute();
     Hooks::run('APIAfterExecute', array(&$module));
     $this->reportUnusedParams();
     if (!$this->mInternalMode) {
         // append Debug information
         MWDebug::appendDebugInfoToApiResult($this->getContext(), $this->getResult());
         // Print result data
         $this->printResult(false);
     }
 }
Example #28
0
 /**
  * Run an SQL query and return the result. Normally throws a DBQueryError
  * on failure. If errors are ignored, returns false instead.
  *
  * In new code, the query wrappers select(), insert(), update(), delete(),
  * etc. should be used where possible, since they give much better DBMS
  * independence and automatically quote or validate user input in a variety
  * of contexts. This function is generally only useful for queries which are
  * explicitly DBMS-dependent and are unsupported by the query wrappers, such
  * as CREATE TABLE.
  *
  * However, the query wrappers themselves should call this function.
  *
  * @param string $sql SQL query
  * @param string $fname Name of the calling function, for profiling/SHOW PROCESSLIST
  *     comment (you can use __METHOD__ or add some extra info)
  * @param bool $tempIgnore Whether to avoid throwing an exception on errors...
  *     maybe best to catch the exception instead?
  * @throws MWException
  * @return bool|ResultWrapper True for a successful write query, ResultWrapper object
  *     for a successful read query, or false on failure if $tempIgnore set
  */
 public function query($sql, $fname = __METHOD__, $tempIgnore = false)
 {
     global $wgUser, $wgDebugDBTransactions, $wgDebugDumpSqlLength;
     $this->mLastQuery = $sql;
     if ($this->isWriteQuery($sql)) {
         # Set a flag indicating that writes have been done
         wfDebug(__METHOD__ . ': Writes done: ' . DatabaseBase::generalizeSQL($sql) . "\n");
         $this->mDoneWrites = microtime(true);
     }
     # Add a comment for easy SHOW PROCESSLIST interpretation
     if (is_object($wgUser) && $wgUser->isItemLoaded('name')) {
         $userName = $wgUser->getName();
         if (mb_strlen($userName) > 15) {
             $userName = mb_substr($userName, 0, 15) . '...';
         }
         $userName = str_replace('/', '', $userName);
     } else {
         $userName = '';
     }
     // Add trace comment to the begin of the sql string, right after the operator.
     // Or, for one-word queries (like "BEGIN" or COMMIT") add it to the end (bug 42598)
     $commentedSql = preg_replace('/\\s|$/', " /* {$fname} {$userName} */ ", $sql, 1);
     # If DBO_TRX is set, start a transaction
     if ($this->mFlags & DBO_TRX && !$this->mTrxLevel && $sql != 'BEGIN' && $sql != 'COMMIT' && $sql != 'ROLLBACK') {
         # Avoid establishing transactions for SHOW and SET statements too -
         # that would delay transaction initializations to once connection
         # is really used by application
         $sqlstart = substr($sql, 0, 10);
         // very much worth it, benchmark certified(tm)
         if (strpos($sqlstart, "SHOW ") !== 0 && strpos($sqlstart, "SET ") !== 0) {
             if ($wgDebugDBTransactions) {
                 wfDebug("Implicit transaction start.\n");
             }
             $this->begin(__METHOD__ . " ({$fname})");
             $this->mTrxAutomatic = true;
         }
     }
     # Keep track of whether the transaction has write queries pending
     if ($this->mTrxLevel && !$this->mTrxDoneWrites && $this->isWriteQuery($sql)) {
         $this->mTrxDoneWrites = true;
         Profiler::instance()->transactionWritingIn($this->mServer, $this->mDBname, $this->mTrxShortId);
     }
     $queryProf = '';
     $totalProf = '';
     $isMaster = !is_null($this->getLBInfo('master'));
     if (!Profiler::instance()->isStub()) {
         # generalizeSQL will probably cut down the query to reasonable
         # logging size most of the time. The substr is really just a sanity check.
         if ($isMaster) {
             $queryProf = 'query-m: ' . substr(DatabaseBase::generalizeSQL($sql), 0, 255);
             $totalProf = 'DatabaseBase::query-master';
         } else {
             $queryProf = 'query: ' . substr(DatabaseBase::generalizeSQL($sql), 0, 255);
             $totalProf = 'DatabaseBase::query';
         }
         # Include query transaction state
         $queryProf .= $this->mTrxShortId ? " [TRX#{$this->mTrxShortId}]" : "";
         $trx = $this->mTrxLevel ? 'TRX=yes' : 'TRX=no';
         wfProfileIn($totalProf);
         wfProfileIn($queryProf);
     }
     if ($this->debug()) {
         static $cnt = 0;
         $cnt++;
         $sqlx = $wgDebugDumpSqlLength ? substr($commentedSql, 0, $wgDebugDumpSqlLength) : $commentedSql;
         $sqlx = strtr($sqlx, "\t\n", '  ');
         $master = $isMaster ? 'master' : 'slave';
         wfDebug("Query {$this->mDBname} ({$cnt}) ({$master}): {$sqlx}\n");
     }
     $queryId = MWDebug::query($sql, $fname, $isMaster);
     # Avoid fatals if close() was called
     if (!$this->isOpen()) {
         throw new DBUnexpectedError($this, "DB connection was already closed.");
     }
     # Do the query and handle errors
     $ret = $this->doQuery($commentedSql);
     MWDebug::queryTime($queryId);
     # Try reconnecting if the connection was lost
     if (false === $ret && $this->wasErrorReissuable()) {
         # Transaction is gone, like it or not
         $hadTrx = $this->mTrxLevel;
         // possible lost transaction
         $this->mTrxLevel = 0;
         $this->mTrxIdleCallbacks = array();
         // bug 65263
         $this->mTrxPreCommitCallbacks = array();
         // bug 65263
         wfDebug("Connection lost, reconnecting...\n");
         # Stash the last error values since ping() might clear them
         $lastError = $this->lastError();
         $lastErrno = $this->lastErrno();
         if ($this->ping()) {
             global $wgRequestTime;
             wfDebug("Reconnected\n");
             $sqlx = $wgDebugDumpSqlLength ? substr($commentedSql, 0, $wgDebugDumpSqlLength) : $commentedSql;
             $sqlx = strtr($sqlx, "\t\n", '  ');
             $elapsed = round(microtime(true) - $wgRequestTime, 3);
             if ($elapsed < 300) {
                 # Not a database error to lose a transaction after a minute or two
                 wfLogDBError("Connection lost and reconnected after {$elapsed}s, query: {$sqlx}");
             }
             if ($hadTrx) {
                 # Leave $ret as false and let an error be reported.
                 # Callers may catch the exception and continue to use the DB.
                 $this->reportQueryError($lastError, $lastErrno, $sql, $fname, $tempIgnore);
             } else {
                 # Should be safe to silently retry (no trx and thus no callbacks)
                 $ret = $this->doQuery($commentedSql);
             }
         } else {
             wfDebug("Failed\n");
         }
     }
     if (false === $ret) {
         $this->reportQueryError($this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore);
     }
     if (!Profiler::instance()->isStub()) {
         wfProfileOut($queryProf);
         wfProfileOut($totalProf);
     }
     return $this->resultObject($ret);
 }
Example #29
0
 /**
  * Finally, all the text has been munged and accumulated into
  * the object, let's actually output it:
  */
 public function output()
 {
     if ($this->mDoNothing) {
         return;
     }
     $response = $this->getRequest()->response();
     $config = $this->getConfig();
     if ($this->mRedirect != '') {
         # Standards require redirect URLs to be absolute
         $this->mRedirect = wfExpandUrl($this->mRedirect, PROTO_CURRENT);
         $redirect = $this->mRedirect;
         $code = $this->mRedirectCode;
         if (Hooks::run("BeforePageRedirect", array($this, &$redirect, &$code))) {
             if ($code == '301' || $code == '303') {
                 if (!$config->get('DebugRedirects')) {
                     $response->statusHeader($code);
                 }
                 $this->mLastModified = wfTimestamp(TS_RFC2822);
             }
             if ($config->get('VaryOnXFP')) {
                 $this->addVaryHeader('X-Forwarded-Proto');
             }
             $this->sendCacheControl();
             $response->header("Content-Type: text/html; charset=utf-8");
             if ($config->get('DebugRedirects')) {
                 $url = htmlspecialchars($redirect);
                 print "<html>\n<head>\n<title>Redirect</title>\n</head>\n<body>\n";
                 print "<p>Location: <a href=\"{$url}\">{$url}</a></p>\n";
                 print "</body>\n</html>\n";
             } else {
                 $response->header('Location: ' . $redirect);
             }
         }
         return;
     } elseif ($this->mStatusCode) {
         $response->statusHeader($this->mStatusCode);
     }
     # Buffer output; final headers may depend on later processing
     ob_start();
     $response->header('Content-type: ' . $config->get('MimeType') . '; charset=UTF-8');
     $response->header('Content-language: ' . $config->get('LanguageCode'));
     // Avoid Internet Explorer "compatibility view" in IE 8-10, so that
     // jQuery etc. can work correctly.
     $response->header('X-UA-Compatible: IE=Edge');
     // Prevent framing, if requested
     $frameOptions = $this->getFrameOptions();
     if ($frameOptions) {
         $response->header("X-Frame-Options: {$frameOptions}");
     }
     if ($this->mArticleBodyOnly) {
         echo $this->mBodytext;
     } else {
         $sk = $this->getSkin();
         // add skin specific modules
         $modules = $sk->getDefaultModules();
         // enforce various default modules for all skins
         $coreModules = array('mediawiki.page.startup', 'mediawiki.user');
         // Support for high-density display images if enabled
         if ($config->get('ResponsiveImages')) {
             $coreModules[] = 'mediawiki.hidpi';
         }
         $this->addModules($coreModules);
         foreach ($modules as $group) {
             $this->addModules($group);
         }
         MWDebug::addModules($this);
         // Hook that allows last minute changes to the output page, e.g.
         // adding of CSS or Javascript by extensions.
         Hooks::run('BeforePageDisplay', array(&$this, &$sk));
         $sk->outputPage();
     }
     // This hook allows last minute changes to final overall output by modifying output buffer
     Hooks::run('AfterFinalPageOutput', array($this));
     $this->sendCacheControl();
     ob_end_flush();
 }
/**
 * Send a warning either to the debug log or in a PHP error depending on
 * $wgDevelopmentWarnings
 *
 * @param $msg String: message to send
 * @param $callerOffset Integer: number of items to go back in the backtrace to
 *        find the correct caller (1 = function calling wfWarn, ...)
 * @param $level Integer: PHP error level; only used when $wgDevelopmentWarnings
 *        is true
 */
function wfWarn($msg, $callerOffset = 1, $level = E_USER_NOTICE)
{
    MWDebug::warning($msg, $callerOffset + 1, $level);
}