static function purge($urlArr) { $caller = self::getPurgeCaller(); wfDebug("Purging backtrace: " . wfGetAllCallers(false) . "\n"); // Filter urls into buckets based on service backend $buckets = array_reduce($urlArr, function ($carry, $item) use($caller) { global $wgPurgeVignetteUsingSurrogateKeys; wfDebug("Purging URL {$item} from {$caller} via Celery\n"); if (isset($wgPurgeVignetteUsingSurrogateKeys) && VignetteRequest::isVignetteUrl($item)) { $carry['vignette'][] = $item; } elseif (strstr($item, 'MercuryApi') !== false) { $carry['mercury'][] = $item; $carry['mediawiki'][] = $item; // TODO: we can remove this when mercury is only using internal cache } else { $carry['mediawiki'][] = $item; } return $carry; }, array('mediawiki' => [], 'vignette' => [], 'mercury' => [])); if (empty(CeleryPurge::$buckets)) { CeleryPurge::$buckets = $buckets; } else { CeleryPurge::$buckets = array_merge_recursive(CeleryPurge::$buckets, $buckets); } }
/** * Add array of URLs to the purger queue * * @param Array $urlArr list of URLs to purge * @throws WikiaException */ static function purge($urlArr) { global $wgEnableScribeReport; wfProfileIn(__METHOD__); if (empty($wgEnableScribeReport)) { wfProfileOut(__METHOD__); return; } foreach ($urlArr as $url) { if (!is_string($url)) { throw new WikiaException('Bad purge URL'); } $url = SquidUpdate::expand($url); $method = self::getPurgeCaller(); wfDebug("Purging URL {$url} from {$method} via Scribe\n"); wfDebug("Purging backtrace: " . wfGetAllCallers(false) . "\n"); // add to the queue, will be sent by onRestInPeace method self::$urls[$url] = ['url' => $url, 'time' => time(), 'method' => $method]; self::$urlsCount++; } wfProfileOut(__METHOD__); }
/** * Create a new Title from text, such as what one would find in a link. De- * codes any HTML entities in the text. * * @param string $text The link text; spaces, prefixes, and an * initial ':' indicating the main namespace are accepted. * @param int $defaultNamespace The namespace to use if none is specified * by a prefix. If you want to force a specific namespace even if * $text might begin with a namespace prefix, use makeTitle() or * makeTitleSafe(). * @throws InvalidArgumentException * @return Title|null Title or null on an error. */ public static function newFromText($text, $defaultNamespace = NS_MAIN) { if (is_object($text)) { throw new InvalidArgumentException('$text must be a string.'); } elseif (!is_string($text)) { wfDebugLog('T76305', wfGetAllCallers(5)); wfWarn(__METHOD__ . ': $text must be a string. This will throw an InvalidArgumentException in future.', 2); } try { return Title::newFromTextThrow($text, $defaultNamespace); } catch (MalformedTitleException $ex) { return null; } }
/** * Create a new Title from text, such as what one would find in a link. De- * codes any HTML entities in the text. * * @param string|null $text The link text; spaces, prefixes, and an * initial ':' indicating the main namespace are accepted. * @param int $defaultNamespace The namespace to use if none is specified * by a prefix. If you want to force a specific namespace even if * $text might begin with a namespace prefix, use makeTitle() or * makeTitleSafe(). * @throws InvalidArgumentException * @return Title|null Title or null on an error. */ public static function newFromText($text, $defaultNamespace = NS_MAIN) { if (is_object($text)) { throw new InvalidArgumentException('$text must be a string.'); } if ($text !== null && !is_string($text)) { wfDebugLog('T76305', wfGetAllCallers(5)); return null; } if ($text === null) { return null; } try { return Title::newFromTextThrow($text, $defaultNamespace); } catch (MalformedTitleException $ex) { return null; } }
/** * @param string $text * @param Title $title * @param bool $linestart Whether or not this is at the start of a line * @param bool $interface Whether this is an interface message * @param string $language Language code * @return ParserOutput|string */ public function parse($text, $title = null, $linestart = true, $interface = false, $language = null) { if ($this->mInParser) { return htmlspecialchars($text); } $parser = $this->getParser(); $popts = $this->getParserOptions(); $popts->setInterfaceMessage($interface); $popts->setTargetLanguage($language); if (!$title || !$title instanceof Title) { global $wgTitle; wfDebugLog('GlobalTitleFail', __METHOD__ . ' called by ' . wfGetAllCallers(5) . ' with no title set.'); $title = $wgTitle; } // Sometimes $wgTitle isn't set either... if (!$title) { # It's not uncommon having a null $wgTitle in scripts. See r80898 # Create a ghost title in such case $title = Title::makeTitle(NS_SPECIAL, 'Badtitle/title not set in ' . __METHOD__); } $this->mInParser = true; $res = $parser->parse($text, $title, $popts, $linestart); $this->mInParser = false; return $res; }
function getRow() { $id = $this->id(); $dbw = wfGetDB(DB_MASTER); if (!$id) { $id = $dbw->nextSequenceValue('thread_thread_id'); } // If there's no root, bail out with an error message if (!$this->rootId && !($this->type & Threads::TYPE_DELETED)) { throw new MWException("Non-deleted thread saved with empty root ID"); } if ($this->replyCount < -1) { wfWarn("Saving thread {$id} with negative reply count {$this->replyCount} " . wfGetAllCallers()); $this->replyCount = -1; } // Reflect schema changes here. return array('thread_id' => $id, 'thread_root' => $this->rootId, 'thread_parent' => $this->parentId, 'thread_article_namespace' => $this->articleNamespace, 'thread_article_title' => $this->articleTitle, 'thread_article_id' => $this->articleId, 'thread_modified' => $dbw->timestamp($this->modified), 'thread_created' => $dbw->timestamp($this->created), 'thread_ancestor' => $this->ancestorId, 'thread_type' => $this->type, 'thread_subject' => $this->subject, 'thread_author_id' => $this->authorId, 'thread_author_name' => $this->authorName, 'thread_summary_page' => $this->summaryId, 'thread_editedness' => $this->editedness, 'thread_sortkey' => $this->sortkey, 'thread_replies' => $this->replyCount, 'thread_signature' => $this->signature); }
/** * @see self::generate() */ public function realGenerate($bytes, $forceStrong = false) { wfDebug(__METHOD__ . ": Generating cryptographic random bytes for " . wfGetAllCallers(5) . "\n"); $bytes = floor($bytes); static $buffer = ''; if (is_null($this->strong)) { // Set strength to false initially until we know what source data is coming from $this->strong = true; } if (strlen($buffer) < $bytes) { // If available make use of mcrypt_create_iv URANDOM source to generate randomness // On unix-like systems this reads from /dev/urandom but does it without any buffering // and bypasses openbasedir restrictions, so it's preferable to reading directly // On Windows starting in PHP 5.3.0 Windows' native CryptGenRandom is used to generate // entropy so this is also preferable to just trying to read urandom because it may work // on Windows systems as well. if (function_exists('mcrypt_create_iv')) { $rem = $bytes - strlen($buffer); $iv = mcrypt_create_iv($rem, MCRYPT_DEV_URANDOM); if ($iv === false) { wfDebug(__METHOD__ . ": mcrypt_create_iv returned false.\n"); } else { $buffer .= $iv; wfDebug(__METHOD__ . ": mcrypt_create_iv generated " . strlen($iv) . " bytes of randomness.\n"); } } } if (strlen($buffer) < $bytes) { // If available make use of openssl's random_pseudo_bytes method to // attempt to generate randomness. However don't do this on Windows // with PHP < 5.3.4 due to a bug: // http://stackoverflow.com/questions/1940168/openssl-random-pseudo-bytes-is-slow-php // http://git.php.net/?p=php-src.git;a=commitdiff;h=cd62a70863c261b07f6dadedad9464f7e213cad5 if (function_exists('openssl_random_pseudo_bytes') && (!wfIsWindows() || version_compare(PHP_VERSION, '5.3.4', '>='))) { $rem = $bytes - strlen($buffer); $openssl_bytes = openssl_random_pseudo_bytes($rem, $openssl_strong); if ($openssl_bytes === false) { wfDebug(__METHOD__ . ": openssl_random_pseudo_bytes returned false.\n"); } else { $buffer .= $openssl_bytes; wfDebug(__METHOD__ . ": openssl_random_pseudo_bytes generated " . strlen($openssl_bytes) . " bytes of " . ($openssl_strong ? "strong" : "weak") . " randomness.\n"); } if (strlen($buffer) >= $bytes) { // openssl tells us if the random source was strong, if some of our data was generated // using it use it's say on whether the randomness is strong $this->strong = !!$openssl_strong; } } } // Only read from urandom if we can control the buffer size or were passed forceStrong if (strlen($buffer) < $bytes && (function_exists('stream_set_read_buffer') || $forceStrong)) { $rem = $bytes - strlen($buffer); if (!function_exists('stream_set_read_buffer') && $forceStrong) { wfDebug(__METHOD__ . ": Was forced to read from /dev/urandom " . "without control over the buffer size.\n"); } // /dev/urandom is generally considered the best possible commonly // available random source, and is available on most *nix systems. MediaWiki\suppressWarnings(); $urandom = fopen("/dev/urandom", "rb"); MediaWiki\restoreWarnings(); // Attempt to read all our random data from urandom // php's fread always does buffered reads based on the stream's chunk_size // so in reality it will usually read more than the amount of data we're // asked for and not storing that risks depleting the system's random pool. // If stream_set_read_buffer is available set the chunk_size to the amount // of data we need. Otherwise read 8k, php's default chunk_size. if ($urandom) { // php's default chunk_size is 8k $chunk_size = 1024 * 8; if (function_exists('stream_set_read_buffer')) { // If possible set the chunk_size to the amount of data we need stream_set_read_buffer($urandom, $rem); $chunk_size = $rem; } $random_bytes = fread($urandom, max($chunk_size, $rem)); $buffer .= $random_bytes; fclose($urandom); wfDebug(__METHOD__ . ": /dev/urandom generated " . strlen($random_bytes) . " bytes of randomness.\n"); if (strlen($buffer) >= $bytes) { // urandom is always strong, set to true if all our data was generated using it $this->strong = true; } } else { wfDebug(__METHOD__ . ": /dev/urandom could not be opened.\n"); } } // If we cannot use or generate enough data from a secure source // use this loop to generate a good set of pseudo random data. // This works by initializing a random state using a pile of unstable data // and continually shoving it through a hash along with a variable salt. // We hash the random state with more salt to avoid the state from leaking // out and being used to predict the /randomness/ that follows. if (strlen($buffer) < $bytes) { wfDebug(__METHOD__ . ": Falling back to using a pseudo random state to generate randomness.\n"); } while (strlen($buffer) < $bytes) { $buffer .= MWCryptHash::hmac($this->randomState(), mt_rand()); // This code is never really cryptographically strong, if we use it // at all, then set strong to false. $this->strong = false; } // Once the buffer has been filled up with enough random data to fulfill // the request shift off enough data to handle the request and leave the // unused portion left inside the buffer for the next request for random data $generated = substr($buffer, 0, $bytes); $buffer = substr($buffer, $bytes); wfDebug(__METHOD__ . ": " . strlen($buffer) . " bytes of randomness leftover in the buffer.\n"); return $generated; }
/** * Get the Title object * * @return Title|null */ public function getTitle() { if ($this->title === null) { global $wgTitle; # fallback to $wg till we can improve this $this->title = $wgTitle; wfDebugLog('GlobalTitleFail', __METHOD__ . ' called by ' . wfGetAllCallers(5) . ' with no title set.'); } return $this->title; }
/** * Get/set the ParserOptions object to use for wikitext parsing * * @param ParserOptions|null $options Either the ParserOption to use or null to only get the * current ParserOption object * @return ParserOptions */ public function parserOptions($options = null) { if ($options !== null && !empty($options->isBogus)) { // Someone is trying to set a bogus pre-$wgUser PO. Check if it has // been changed somehow, and keep it if so. $anonPO = ParserOptions::newFromAnon(); $anonPO->setEditSection(false); if (!$options->matches($anonPO)) { wfLogWarning(__METHOD__ . ': Setting a changed bogus ParserOptions: ' . wfGetAllCallers(5)); $options->isBogus = false; } } if (!$this->mParserOptions) { if (!$this->getContext()->getUser()->isSafeToLoad()) { // $wgUser isn't unstubbable yet, so don't try to get a // ParserOptions for it. And don't cache this ParserOptions // either. $po = ParserOptions::newFromAnon(); $po->setEditSection(false); $po->isBogus = true; if ($options !== null) { $this->mParserOptions = empty($options->isBogus) ? $options : null; } return $po; } $this->mParserOptions = ParserOptions::newFromContext($this->getContext()); $this->mParserOptions->setEditSection(false); } if ($options !== null && !empty($options->isBogus)) { // They're trying to restore the bogus pre-$wgUser PO. Do the right // thing. return wfSetVar($this->mParserOptions, null, true); } else { return wfSetVar($this->mParserOptions, $options); } }
/** * Renew the session by resaving everything * * Resets the TTL in the backend store if the session is near expiring, and * re-persists the session to any active WebRequests if persistent. */ public function renew() { if (time() + $this->lifetime / 2 > $this->expires) { $this->metaDirty = true; $this->logger->debug('SessionBackend "{callers}" metadata dirty for renew(): {callers}', ['session' => $this->id, 'callers' => wfGetAllCallers(5)]); if ($this->persist) { $this->forcePersist = true; $this->logger->debug('SessionBackend "{session}" force-persist for renew(): {callers}', ['session' => $this->id, 'callers' => wfGetAllCallers(5)]); } } $this->autosave(); }
/** * Create a new Title from text, such as what one would find in a link. De- * codes any HTML entities in the text. * * @param string|int|null $text The link text; spaces, prefixes, and an * initial ':' indicating the main namespace are accepted. * @param int $defaultNamespace The namespace to use if none is specified * by a prefix. If you want to force a specific namespace even if * $text might begin with a namespace prefix, use makeTitle() or * makeTitleSafe(). * @throws InvalidArgumentException * @return Title|null Title or null on an error. */ public static function newFromText($text, $defaultNamespace = NS_MAIN) { if (is_object($text)) { throw new InvalidArgumentException('$text must be a string.'); } // DWIM: Integers can be passed in here when page titles are used as array keys. if ($text !== null && !is_string($text) && !is_int($text)) { wfDebugLog('T76305', wfGetAllCallers(5)); return null; } if ($text === null) { return null; } try { return Title::newFromTextThrow(strval($text), $defaultNamespace); } catch (MalformedTitleException $ex) { return null; } }
/** * Renew the session by resaving everything * * Resets the TTL in the backend store if the session is near expiring, and * re-persists the session to any active WebRequests if persistent. */ public function renew() { if (time() + $this->lifetime / 2 > $this->expires) { $this->metaDirty = true; $this->logger->debug("SessionBackend {$this->id} metadata dirty for renew(): " . wfGetAllCallers(5)); if ($this->persist) { $this->forcePersist = true; $this->logger->debug("SessionBackend {$this->id} force-persist for renew(): " . wfGetAllCallers(5)); } } $this->autosave(); }
/** * Initialise php session * * @param $sessionId Bool */ function wfSetupSession($sessionId = false) { global $wgSessionsInMemcached, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $wgCookieHttpOnly, $wgSessionHandler; if ($wgSessionsInMemcached) { if (!defined('MW_COMPILED')) { global $IP; require_once "{$IP}/includes/cache/MemcachedSessions.php"; } session_set_save_handler('memsess_open', 'memsess_close', 'memsess_read', 'memsess_write', 'memsess_destroy', 'memsess_gc'); // It's necessary to register a shutdown function to call session_write_close(), // because by the time the request shutdown function for the session module is // called, $wgMemc has already been destroyed. Shutdown functions registered // this way are called before object destruction. register_shutdown_function('memsess_write_close'); } elseif ($wgSessionHandler && $wgSessionHandler != ini_get('session.save_handler')) { # Only set this if $wgSessionHandler isn't null and session.save_handler # hasn't already been set to the desired value (that causes errors) ini_set('session.save_handler', $wgSessionHandler); } $httpOnlySafe = wfHttpOnlySafe() && $wgCookieHttpOnly; wfDebugLog('cookie', 'session_set_cookie_params: "' . implode('", "', array(0, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $httpOnlySafe)) . '"'); session_set_cookie_params(0, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $httpOnlySafe); session_cache_limiter('private, must-revalidate'); if ($sessionId) { session_id($sessionId); } else { wfFixSessionID(); } wfSuppressWarnings(); session_start(); wfRestoreWarnings(); // Wikia change - start // log all sessions started with 1% sampling (PLATFORM-1266) if ((new Wikia\Util\Statistics\BernoulliTrial(0.01))->shouldSample()) { Wikia\Logger\WikiaLogger::instance()->info(__METHOD__, ['caller' => wfGetAllCallers(), 'exception' => new Exception()]); } // Wikia change - end }
function __construct($details = null, Exception $previous = null) { parent::__construct($this->message, $this->code, $previous); wfDebug(get_class($this) . " raised from " . wfGetAllCallers(2) . "\n"); if (!empty($details)) { $this->details = $details; wfDebug(get_class($this) . ": {$this->details}\n"); } }
/** * Return the error message related to a certain array * @param array|string|MessageSpecifier $error Element of a getUserPermissionsErrors()-style array * @return [ 'code' => code, 'info' => info ] */ public function parseMsg($error) { // Check whether someone passed the whole array, instead of one element as // documented. This breaks if it's actually an array of fallback keys, but // that's long-standing misbehavior introduced in r87627 to incorrectly // fix T30797. if (is_array($error)) { $first = reset($error); if (is_array($first)) { wfDebug(__METHOD__ . ' was passed an array of arrays. ' . wfGetAllCallers(5)); $error = $first; } } $msg = Message::newFromSpecifier($error); if ($msg instanceof IApiMessage) { return ['code' => $msg->getApiCode(), 'info' => $msg->inLanguage('en')->useDatabase(false)->text(), 'data' => $msg->getApiData()]; } $key = $msg->getKey(); if (isset(self::$messageMap[$key])) { $params = $msg->getParams(); return ['code' => wfMsgReplaceArgs(self::$messageMap[$key]['code'], $params), 'info' => wfMsgReplaceArgs(self::$messageMap[$key]['info'], $params)]; } // If the key isn't present, throw an "unknown error" return $this->parseMsg(['unknownerror', $key]); }