Example #1
0
 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);
     }
 }
Example #2
0
 /**
  * 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__);
 }
Example #3
0
 /**
  * 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;
     }
 }
Example #4
0
 /**
  * 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;
     }
 }
Example #5
0
 /**
  * @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;
 }
Example #6
0
 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);
 }
Example #7
0
 /**
  * @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;
 }
Example #8
0
 /**
  * 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;
 }
Example #9
0
 /**
  * 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);
     }
 }
Example #10
0
 /**
  * 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();
 }
Example #11
0
 /**
  * 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;
     }
 }
Example #12
0
 /**
  * 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();
 }
Example #13
0
/**
 * 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
}
Example #14
0
 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");
     }
 }
Example #15
0
 /**
  * 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]);
 }