public function execute()
 {
     $users = 10;
     // For number of translations, limited to [0,20]
     $mean = 15;
     $stddev = 20;
     $stash = new TranslationStashStorage(wfGetDB(DB_MASTER));
     $languages = array_keys(Language::fetchLanguageNames());
     for ($i = 0; $i < $users; $i++) {
         $username = '******' . wfRandomString(6);
         $password = wfRandomString(12);
         $email = "{$username}.{$password}@blackhole.io";
         $user = TranslateSandbox::addUser($username, $password, $email);
         $language = $languages[rand(0, count($languages) - 1)];
         $count = wfGaussMs($mean, $stddev);
         $count = min(20, $count);
         $count = max(0, $count);
         for ($j = 0; $j < $count; $j++) {
             $title = Title::makeTitle(NS_MEDIAWIKI, wfRandomString(24) . '/' . $language);
             $value = array('Pupu söi');
             for ($k = rand(0, 20); $k > 0; $k--) {
                 $value[] = wfRandomString(rand(1, 28));
             }
             $value = implode("\n", $value);
             $translation = new StashedTranslation($user, $title, $value);
             $stash->addTranslation($translation);
         }
     }
 }
 /**
  * Make a new temporary file on the file system.
  * Temporary files may be purged when the file object falls out of scope.
  *
  * @param $prefix string
  * @param $extension string
  * @return TempFSFile|null
  */
 public static function factory($prefix, $extension = '')
 {
     wfProfileIn(__METHOD__);
     $base = wfTempDir() . '/' . $prefix . wfRandomString(12);
     $ext = $extension != '' ? ".{$extension}" : "";
     for ($attempt = 1; true; $attempt++) {
         $path = "{$base}-{$attempt}{$ext}";
         wfSuppressWarnings();
         $newFileHandle = fopen($path, 'x');
         wfRestoreWarnings();
         if ($newFileHandle) {
             fclose($newFileHandle);
             break;
             // got it
         }
         if ($attempt >= 5) {
             wfProfileOut(__METHOD__);
             return null;
             // give up
         }
     }
     $tmpFile = new self($path);
     $tmpFile->canDelete = true;
     // safely instantiated
     wfProfileOut(__METHOD__);
     return $tmpFile;
 }
 /**
  * @param array[] $markers Markers generated by another instance of TextInjector,
  *        for use by inject(); a map of string markers associated with
  *        parameter arrays.
  */
 public function __construct(array $markers = array())
 {
     $this->markers = $markers;
     // idea stolen from Parser class in core
     $this->uniqPrefix = "UNIQ" . wfRandomString(16);
     $this->markerIndex = 0;
 }
 public function testForAuthentication(array $reqs)
 {
     $req = AuthenticationRequest::getRequestByClass($reqs, PasswordAuthenticationRequest::class);
     if ($req) {
         $user = User::newFromName($req->username);
         $password = $req->password;
     } else {
         $user = null;
         foreach ($reqs as $req) {
             if ($req->username !== null) {
                 $user = User::newFromName($req->username);
                 break;
             }
         }
         if (!$user) {
             $this->logger->debug(__METHOD__ . ': No username in $reqs, skipping hooks');
             return StatusValue::newGood();
         }
         // Something random for the 'AbortLogin' hook.
         $password = wfRandomString(32);
     }
     $msg = null;
     if (!\Hooks::run('LoginUserMigrated', [$user, &$msg])) {
         return $this->makeFailResponse($user, null, LoginForm::USER_MIGRATED, $msg, 'LoginUserMigrated');
     }
     $abort = LoginForm::ABORTED;
     $msg = null;
     if (!\Hooks::run('AbortLogin', [$user, $password, &$abort, &$msg])) {
         return $this->makeFailResponse($user, null, $abort, $msg, 'AbortLogin');
     }
     return StatusValue::newGood();
 }
 /**
  * @covers ReplicatedBagOStuff::get
  */
 public function testGetAbsent()
 {
     $key = wfRandomString();
     $value = wfRandomString();
     $this->writeCache->set($key, $value);
     // Don't read from master. No failover if value is absent.
     $this->assertEquals($this->cache->get($key), false);
 }
 public function execute()
 {
     global $wgCaptchaSecret, $wgCaptchaDirectoryLevels;
     $instance = ConfirmEditHooks::getInstance();
     if (!$instance instanceof FancyCaptcha) {
         $this->error("\$wgCaptchaClass is not FancyCaptcha.\n", 1);
     }
     $backend = $instance->getBackend();
     $countAct = $instance->estimateCaptchaCount();
     $this->output("Estimated number of captchas is {$countAct}.\n");
     $countGen = (int) $this->getOption('fill') - $countAct;
     if ($countGen <= 0) {
         $this->output("No need to generate anymore captchas.\n");
         return;
     }
     $tmpDir = wfTempDir() . '/mw-fancycaptcha-' . time() . '-' . wfRandomString(6);
     if (!wfMkdirParents($tmpDir)) {
         $this->error("Could not create temp directory.\n", 1);
     }
     $e = null;
     // exception
     try {
         $cmd = sprintf("python %s --key %s --output %s --count %s --dirs %s", wfEscapeShellArg(__DIR__ . '/../captcha.py'), wfEscapeShellArg($wgCaptchaSecret), wfEscapeShellArg($tmpDir), wfEscapeShellArg($countGen), wfEscapeShellArg($wgCaptchaDirectoryLevels));
         foreach (array('wordlist', 'font', 'font-size', 'blacklist', 'verbose') as $par) {
             if ($this->hasOption($par)) {
                 $cmd .= " --{$par} " . wfEscapeShellArg($this->getOption($par));
             }
         }
         $this->output("Generating {$countGen} new captchas...\n");
         $retVal = 1;
         wfShellExec($cmd, $retVal, array(), array('time' => 0));
         if ($retVal != 0) {
             wfRecursiveRemoveDir($tmpDir);
             $this->error("Could not run generation script.\n", 1);
         }
         $flags = FilesystemIterator::SKIP_DOTS;
         $iter = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($tmpDir, $flags), RecursiveIteratorIterator::CHILD_FIRST);
         $this->output("Copying the new captchas to storage...\n");
         foreach ($iter as $fileInfo) {
             if (!$fileInfo->isFile()) {
                 continue;
             }
             list($salt, $hash) = $instance->hashFromImageName($fileInfo->getBasename());
             $dest = $instance->imagePath($salt, $hash);
             $backend->prepare(array('dir' => dirname($dest)));
             $status = $backend->quickStore(array('src' => $fileInfo->getPathname(), 'dst' => $dest));
             if (!$status->isOK()) {
                 $this->error("Could not save file '{$fileInfo->getPathname()}'.\n");
             }
         }
     } catch (Exception $e) {
         wfRecursiveRemoveDir($tmpDir);
         throw $e;
     }
     $this->output("Removing temporary files...\n");
     wfRecursiveRemoveDir($tmpDir);
     $this->output("Done.\n");
 }
 protected function doGetLocalCopyMulti(array $params)
 {
     $tmpFiles = array();
     // (path => MockFSFile)
     foreach ($params['srcs'] as $src) {
         $tmpFiles[$src] = new MockFSFile(wfTempDir() . '/' . wfRandomString(32));
     }
     return $tmpFiles;
 }
 /**
  * @covers GlobalVarConfig::has
  */
 public function testHas()
 {
     $this->maybeStashGlobal('wgGlobalVarConfigTestHas');
     $GLOBALS['wgGlobalVarConfigTestHas'] = wfRandomString();
     $this->maybeStashGlobal('wgGlobalVarConfigTestNotHas');
     $config = new GlobalVarConfig();
     $this->assertTrue($config->has('GlobalVarConfigTestHas'));
     $this->assertFalse($config->has('GlobalVarConfigTestNotHas'));
 }
 /**
  * @dataProvider provideSet
  * @covers GlobalVarConfig::set
  * @covers GlobalVarConfig::setWithPrefix
  */
 public function testSet($name, $prefix, $var)
 {
     $this->maybeStashGlobal($var);
     $config = new GlobalVarConfig($prefix);
     $random = wfRandomString();
     $config->set($name, $random);
     $this->assertArrayHasKey($var, $GLOBALS);
     $this->assertEquals($random, $GLOBALS[$var]);
 }
示例#10
0
 /**
  * Construct a new instance from configuration.
  *
  * @param array $config Parameters include:
  *   - lockServers  : Associative array of server names to "<IP>:<port>" strings.
  *   - srvsByBucket : Array of 1-16 consecutive integer keys, starting from 0,
  *                    each having an odd-numbered list of server names (peers) as values.
  *   - redisConfig  : Configuration for RedisConnectionPool::__construct().
  * @throws Exception
  */
 public function __construct(array $config)
 {
     parent::__construct($config);
     $this->lockServers = $config['lockServers'];
     // Sanitize srvsByBucket config to prevent PHP errors
     $this->srvsByBucket = array_filter($config['srvsByBucket'], 'is_array');
     $this->srvsByBucket = array_values($this->srvsByBucket);
     // consecutive
     $config['redisConfig']['serializer'] = 'none';
     $this->redisPool = RedisConnectionPool::singleton($config['redisConfig']);
     $this->session = wfRandomString(32);
 }
 public function testSetDelayed()
 {
     $key = wfRandomString();
     $value = wfRandomString();
     // XXX: DeferredUpdates bound to transactions in CLI mode
     $dbw = wfGetDB(DB_MASTER);
     $dbw->begin();
     $this->cache->set($key, $value);
     // Set in tier 1
     $this->assertEquals($value, $this->cache1->get($key), 'Written to tier 1');
     // Not yet set in tier 2
     $this->assertEquals(false, $this->cache2->get($key), 'Not written to tier 2');
     $dbw->commit();
     // Set in tier 2
     $this->assertEquals($value, $this->cache2->get($key), 'Written to tier 2');
 }
示例#12
0
 /**
  * Construct a new instance from configuration.
  *
  * $config paramaters include:
  *   - lockServers  : Associative array of server names to configuration.
  *                    Configuration is an associative array that includes:
  *                      - host    : IP address/hostname
  *                      - port    : TCP port
  *                      - authKey : Secret string the lock server uses
  *   - srvsByBucket : Array of 1-16 consecutive integer keys, starting from 0,
  *                    each having an odd-numbered list of server names (peers) as values.
  *   - connTimeout  : Lock server connection attempt timeout. [optional]
  *
  * @param Array $config
  */
 public function __construct(array $config)
 {
     parent::__construct($config);
     $this->lockServers = $config['lockServers'];
     // Sanitize srvsByBucket config to prevent PHP errors
     $this->srvsByBucket = array_filter($config['srvsByBucket'], 'is_array');
     $this->srvsByBucket = array_values($this->srvsByBucket);
     // consecutive
     if (isset($config['connTimeout'])) {
         $this->connTimeout = $config['connTimeout'];
     } else {
         $this->connTimeout = 3;
         // use some sane amount
     }
     $this->session = wfRandomString(32);
     // 128 bits
 }
示例#13
0
 /**
  * Construct a new instance from configuration.
  *
  * @param array $config Parameters include:
  *   - lockServers  : Associative array of server names to "<IP>:<port>" strings.
  *   - srvsByBucket : Array of 1-16 consecutive integer keys, starting from 0,
  *                    each having an odd-numbered list of server names (peers) as values.
  *   - memcConfig   : Configuration array for ObjectCache::newFromParams. [optional]
  *                    If set, this must use one of the memcached classes.
  * @throws Exception
  */
 public function __construct(array $config)
 {
     parent::__construct($config);
     // Sanitize srvsByBucket config to prevent PHP errors
     $this->srvsByBucket = array_filter($config['srvsByBucket'], 'is_array');
     $this->srvsByBucket = array_values($this->srvsByBucket);
     // consecutive
     $memcConfig = isset($config['memcConfig']) ? $config['memcConfig'] : ['class' => 'MemcachedPhpBagOStuff'];
     foreach ($config['lockServers'] as $name => $address) {
         $params = ['servers' => [$address]] + $memcConfig;
         $cache = ObjectCache::newFromParams($params);
         if ($cache instanceof MemcachedBagOStuff) {
             $this->bagOStuffs[$name] = $cache;
         } else {
             throw new Exception('Only MemcachedBagOStuff classes are supported by MemcLockManager.');
         }
     }
     $this->session = wfRandomString(32);
 }
示例#14
0
 /**
  * Make a new temporary file on the file system.
  * Temporary files may be purged when the file object falls out of scope.
  *
  * @param string $prefix
  * @param string $extension
  * @return TempFSFile|null
  */
 public static function factory($prefix, $extension = '')
 {
     $ext = $extension != '' ? ".{$extension}" : '';
     $attempts = 5;
     while ($attempts--) {
         $path = wfTempDir() . '/' . $prefix . wfRandomString(12) . $ext;
         MediaWiki\suppressWarnings();
         $newFileHandle = fopen($path, 'x');
         MediaWiki\restoreWarnings();
         if ($newFileHandle) {
             fclose($newFileHandle);
             $tmpFile = new self($path);
             $tmpFile->autocollect();
             // Safely instantiated, end loop.
             return $tmpFile;
         }
     }
     // Give up
     return null;
 }
示例#15
0
 public function execute()
 {
     $user = User::newFromName($this->getOption('user'));
     if (!$user->getId()) {
         $this->error("No such user exists.", 1);
     }
     $count = $this->getOption('count');
     $namespace = (int) $this->getOption('namespace', 0);
     for ($i = 0; $i < $count; ++$i) {
         $title = Title::makeTitleSafe($namespace, "Page " . wfRandomString(2));
         $page = WikiPage::factory($title);
         $content = ContentHandler::makeContent(wfRandomString(), $title);
         $summary = "Change " . wfRandomString(6);
         $page->doEditContent($content, $summary, 0, false, $user);
         $this->output("Edited {$title}\n");
         if ($i && $i % $this->mBatchSize == 0) {
             wfWaitForSlaves();
         }
     }
     $this->output("Done\n");
 }
示例#16
0
 /**
  * Get a TestUser object that the caller may not modify.
  *
  * Whenever possible, unit tests should use immutable users, because
  * immutable users can be reused in multiple tests, which helps keep
  * the unit tests fast.
  *
  * @since 1.28
  *
  * @param string[] $groups Groups the test user should be added to.
  * @return TestUser
  */
 public static function getImmutableTestUser($groups = [])
 {
     $groups = array_unique($groups);
     sort($groups);
     $key = implode(',', $groups);
     $testUser = isset(self::$testUsers[$key]) ? self::$testUsers[$key] : false;
     if (!$testUser || !$testUser->getUser()->isLoggedIn()) {
         $id = self::getNextId();
         // Hack! If this is the primary sysop account, make the username
         // be 'UTSysop', for back-compat, and for the sake of PHPUnit data
         // provider methods, which are executed before the test database
         // is set up. See T136348.
         if ($groups === ['bureaucrat', 'sysop']) {
             $username = '******';
             $password = '******';
         } else {
             $username = "******";
             $password = wfRandomString(20);
         }
         self::$testUsers[$key] = $testUser = new TestUser($username, "Name {$id}", "{$id}@mediawiki.test", $groups, $password);
     }
     $testUser->getUser()->clearInstanceCache();
     return self::$testUsers[$key];
 }
示例#17
0
 /**
  * Make a new temporary file on the file system.
  * Temporary files may be purged when the file object falls out of scope.
  *
  * @param string $prefix
  * @param string $extension
  * @return TempFSFile|null
  */
 public static function factory($prefix, $extension = '')
 {
     $base = wfTempDir() . '/' . $prefix . wfRandomString(12);
     $ext = $extension != '' ? ".{$extension}" : "";
     for ($attempt = 1; true; $attempt++) {
         $path = "{$base}-{$attempt}{$ext}";
         MediaWiki\suppressWarnings();
         $newFileHandle = fopen($path, 'x');
         MediaWiki\restoreWarnings();
         if ($newFileHandle) {
             fclose($newFileHandle);
             break;
             // got it
         }
         if ($attempt >= 5) {
             return null;
             // give up
         }
     }
     $tmpFile = new self($path);
     $tmpFile->autocollect();
     // safely instantiated
     return $tmpFile;
 }
示例#18
0
 /**
  * Get the unique request ID.
  * This is either the value of the UNIQUE_ID envvar (if present) or a
  * randomly-generated 24-character string.
  *
  * @return string
  * @since 1.27
  */
 public static function getRequestId()
 {
     if (!self::$reqId) {
         self::$reqId = isset($_SERVER['UNIQUE_ID']) ? $_SERVER['UNIQUE_ID'] : wfRandomString(24);
     }
     return self::$reqId;
 }
示例#19
0
 /**
  * @param ImportSource $source
  * @return string
  */
 static function registerSource(ImportSource $source)
 {
     $id = wfRandomString();
     self::$sourceRegistrations[$id] = $source;
     return $id;
 }
示例#20
0
 /**
  * Get the ID for this exception.
  *
  * The ID is saved so that one can match the one output to the user (when
  * $wgShowExceptionDetails is set to false), to the entry in the debug log.
  *
  * @since 1.22
  * @param Exception $e
  * @return string
  */
 public static function getLogId(Exception $e)
 {
     if (!isset($e->_mwLogId)) {
         $e->_mwLogId = wfRandomString(8);
     }
     return $e->_mwLogId;
 }
示例#21
0
    /**
     * Dual purpose callback used as both a set_error_handler() callback and
     * a registered shutdown function. Receive a callback from the interpreter
     * for a raised error or system shutdown, check for a fatal error, and log
     * to the 'fatal' logging channel.
     *
     * Special handling is included for missing class errors as they may
     * indicate that the user needs to install 3rd-party libraries via
     * Composer or other means.
     *
     * @since 1.25
     *
     * @param int $level Error level raised
     * @param string $message Error message
     * @param string $file File that error was raised in
     * @param int $line Line number error was raised at
     * @param array $context Active symbol table point of error
     * @param array $trace Backtrace at point of error (undocumented HHVM
     *     feature)
     * @return bool Always returns false
     */
    public static function handleFatalError($level = null, $message = null, $file = null, $line = null, $context = null, $trace = null)
    {
        // Free reserved memory so that we have space to process OOM
        // errors
        self::$reservedMemory = null;
        if ($level === null) {
            // Called as a shutdown handler, get data from error_get_last()
            if (static::$handledFatalCallback) {
                // Already called once (probably as an error handler callback
                // under HHVM) so don't log again.
                return false;
            }
            $lastError = error_get_last();
            if ($lastError !== null) {
                $level = $lastError['type'];
                $message = $lastError['message'];
                $file = $lastError['file'];
                $line = $lastError['line'];
            } else {
                $level = 0;
                $message = '';
            }
        }
        if (!in_array($level, self::$fatalErrorTypes)) {
            // Only interested in fatal errors, others should have been
            // handled by MWExceptionHandler::handleError
            return false;
        }
        $msg = "[{exception_id}] PHP Fatal Error: {$message}";
        // Look at message to see if this is a class not found failure
        // HHVM: Class undefined: foo
        // PHP5: Class 'foo' not found
        if (preg_match("/Class (undefined: \\w+|'\\w+' not found)/", $msg)) {
            // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
            $msg = <<<TXT
{$msg}

MediaWiki or an installed extension requires this class but it is not embedded directly in MediaWiki's git repository and must be installed separately by the end user.

Please see <a href="https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries">mediawiki.org</a> for help on installing the required components.
TXT;
            // @codingStandardsIgnoreEnd
        }
        // We can't just create an exception and log it as it is likely that
        // the interpreter has unwound the stack already. If that is true the
        // stacktrace we would get would be functionally empty. If however we
        // have been called as an error handler callback *and* HHVM is in use
        // we will have been provided with a useful stacktrace that we can
        // log.
        $trace = $trace ?: debug_backtrace();
        $logger = LoggerFactory::getInstance('fatal');
        $logger->error($msg, ['exception' => ['class' => 'ErrorException', 'message' => "PHP Fatal Error: {$message}", 'code' => $level, 'file' => $file, 'line' => $line, 'trace' => static::redactTrace($trace)], 'exception_id' => wfRandomString(8)]);
        // Remember call so we don't double process via HHVM's fatal
        // notifications and the shutdown hook behavior
        static::$handledFatalCallback = true;
        return false;
    }
示例#22
0
 /**
  * Get a random string
  *
  * @return string
  */
 public static function getRandomString()
 {
     return wfRandomString(16);
 }
示例#23
0
 /**
  * Get a random string
  *
  * @return string
  * @deprecated since 1.26; use wfRandomString() instead.
  */
 public static function getRandomString()
 {
     wfDeprecated(__METHOD__, '1.26');
     return wfRandomString(16);
 }
示例#24
0
 /**
  * @dataProvider provider_queueLists
  * @covers JobQueue
  */
 public function testRootDeduplication($queue, $recycles, $desc)
 {
     $queue = $this->{$queue};
     if (!$queue) {
         $this->markTestSkipped($desc);
     }
     $this->assertTrue($queue->isEmpty(), "Queue is empty ({$desc})");
     $queue->flushCaches();
     $this->assertEquals(0, $queue->getSize(), "Queue is empty ({$desc})");
     $this->assertEquals(0, $queue->getAcquiredCount(), "Queue is empty ({$desc})");
     $id = wfRandomString(32);
     $root1 = Job::newRootJobParams("nulljobspam:{$id}");
     // task ID/timestamp
     for ($i = 0; $i < 5; ++$i) {
         $this->assertNull($queue->push($this->newJob(0, $root1)), "Push worked ({$desc})");
     }
     $queue->deduplicateRootJob($this->newJob(0, $root1));
     $root2 = $root1;
     # Add a second to UNIX epoch and format back to TS_MW
     $root2_ts = strtotime($root2['rootJobTimestamp']);
     $root2_ts++;
     $root2['rootJobTimestamp'] = wfTimestamp(TS_MW, $root2_ts);
     $this->assertNotEquals($root1['rootJobTimestamp'], $root2['rootJobTimestamp'], "Root job signatures have different timestamps.");
     for ($i = 0; $i < 5; ++$i) {
         $this->assertNull($queue->push($this->newJob(0, $root2)), "Push worked ({$desc})");
     }
     $queue->deduplicateRootJob($this->newJob(0, $root2));
     $this->assertFalse($queue->isEmpty(), "Queue is not empty ({$desc})");
     $queue->flushCaches();
     $this->assertEquals(10, $queue->getSize(), "Queue size is correct ({$desc})");
     $this->assertEquals(0, $queue->getAcquiredCount(), "No jobs active ({$desc})");
     $dupcount = 0;
     $jobs = [];
     do {
         $job = $queue->pop();
         if ($job) {
             $jobs[] = $job;
             $queue->ack($job);
         }
         if ($job instanceof DuplicateJob) {
             ++$dupcount;
         }
     } while ($job);
     $this->assertEquals(10, count($jobs), "Correct number of jobs popped ({$desc})");
     $this->assertEquals(5, $dupcount, "Correct number of duplicate jobs popped ({$desc})");
 }
示例#25
0
 /**
  * @see JobQueue::doPop()
  * @return Job|bool
  */
 protected function doPop()
 {
     $dbw = $this->getMasterDB();
     try {
         $dbw->commit(__METHOD__, 'flush');
         // flush existing transaction
         $autoTrx = $dbw->getFlag(DBO_TRX);
         // get current setting
         $dbw->clearFlag(DBO_TRX);
         // make each query its own transaction
         $scopedReset = new ScopedCallback(function () use($dbw, $autoTrx) {
             $dbw->setFlag($autoTrx ? DBO_TRX : 0);
             // restore old setting
         });
         $uuid = wfRandomString(32);
         // pop attempt
         $job = false;
         // job popped off
         do {
             // retry when our row is invalid or deleted as a duplicate
             // Try to reserve a row in the DB...
             if (in_array($this->order, array('fifo', 'timestamp'))) {
                 $row = $this->claimOldest($uuid);
             } else {
                 // random first
                 $rand = mt_rand(0, self::MAX_JOB_RANDOM);
                 // encourage concurrent UPDATEs
                 $gte = (bool) mt_rand(0, 1);
                 // find rows with rand before/after $rand
                 $row = $this->claimRandom($uuid, $rand, $gte);
             }
             // Check if we found a row to reserve...
             if (!$row) {
                 break;
                 // nothing to do
             }
             JobQueue::incrStats('pops', $this->type);
             // Get the job object from the row...
             $title = Title::makeTitle($row->job_namespace, $row->job_title);
             $job = Job::factory($row->job_cmd, $title, self::extractBlob($row->job_params), $row->job_id);
             $job->metadata['id'] = $row->job_id;
             $job->metadata['timestamp'] = $row->job_timestamp;
             break;
             // done
         } while (true);
         if (!$job || mt_rand(0, 9) == 0) {
             // Handled jobs that need to be recycled/deleted;
             // any recycled jobs will be picked up next attempt
             $this->recycleAndDeleteStaleJobs();
         }
     } catch (DBError $e) {
         $this->throwDBException($e);
     }
     return $job;
 }
示例#26
0
 /**
  * @covers ::wfRandomString
  */
 public function testRandomString()
 {
     $this->assertFalse(wfRandomString() == wfRandomString());
     $this->assertEquals(strlen(wfRandomString(10)), 10);
     $this->assertTrue(preg_match('/^[0-9a-f]+$/i', wfRandomString()) === 1);
 }
示例#27
0
 /**
  * Begin a transaction. If a transaction is already in progress,
  * that transaction will be committed before the new transaction is started.
  *
  * Note that when the DBO_TRX flag is set (which is usually the case for web
  * requests, but not for maintenance scripts), any previous database query
  * will have started a transaction automatically.
  *
  * Nesting of transactions is not supported. Attempts to nest transactions
  * will cause a warning, unless the current transaction was started
  * automatically because of the DBO_TRX flag.
  *
  * @param string $fname
  * @throws DBError
  */
 public final function begin($fname = __METHOD__)
 {
     if ($this->mTrxLevel) {
         // implicit commit
         if ($this->mTrxAtomicLevels) {
             // If the current transaction was an automatic atomic one, then we definitely have
             // a problem. Same if there is any unclosed atomic level.
             $levels = implode(', ', $this->mTrxAtomicLevels);
             throw new DBUnexpectedError($this, "Got explicit BEGIN while atomic sections {$levels} are still open.");
         } elseif (!$this->mTrxAutomatic) {
             // We want to warn about inadvertently nested begin/commit pairs, but not about
             // auto-committing implicit transactions that were started by query() via DBO_TRX
             $msg = "{$fname}: Transaction already in progress (from {$this->mTrxFname}), " . " performing implicit commit!";
             wfWarn($msg);
             wfLogDBError($msg, $this->getLogContext(array('method' => __METHOD__, 'fname' => $fname)));
         } else {
             // if the transaction was automatic and has done write operations
             if ($this->mTrxDoneWrites) {
                 wfDebug("{$fname}: Automatic transaction with writes in progress" . " (from {$this->mTrxFname}), performing implicit commit!\n");
             }
         }
         $this->runOnTransactionPreCommitCallbacks();
         $writeTime = $this->pendingWriteQueryDuration();
         $this->doCommit($fname);
         if ($this->mTrxDoneWrites) {
             $this->mDoneWrites = microtime(true);
             $this->getTransactionProfiler()->transactionWritingOut($this->mServer, $this->mDBname, $this->mTrxShortId, $writeTime);
         }
         $this->runOnTransactionIdleCallbacks();
     }
     # Avoid fatals if close() was called
     $this->assertOpen();
     $this->doBegin($fname);
     $this->mTrxTimestamp = microtime(true);
     $this->mTrxFname = $fname;
     $this->mTrxDoneWrites = false;
     $this->mTrxAutomatic = false;
     $this->mTrxAutomaticAtomic = false;
     $this->mTrxAtomicLevels = array();
     $this->mTrxIdleCallbacks = array();
     $this->mTrxPreCommitCallbacks = array();
     $this->mTrxShortId = wfRandomString(12);
     $this->mTrxWriteDuration = 0.0;
     // First SELECT after BEGIN will establish the snapshot in REPEATABLE-READ.
     // Get an estimate of the slave lag before then, treating estimate staleness
     // as lag itself just to be safe
     $status = $this->getApproximateLagStatus();
     $this->mTrxSlaveLag = $status['lag'] + (microtime(true) - $status['since']);
 }
示例#28
0
 /**
  * Return an RFC4122 compliant v4 UUID
  *
  * @param int $flags Bitfield (supports UIDGenerator::QUICK_RAND)
  * @return string
  * @throws MWException
  */
 public static function newUUIDv4($flags = 0)
 {
     $hex = $flags & self::QUICK_RAND ? wfRandomString(31) : MWCryptRand::generateHex(31);
     return sprintf('%s-%s-%s-%s-%s', substr($hex, 0, 8), substr($hex, 8, 4), '4' . substr($hex, 12, 3), dechex(0x8 | hexdec($hex[15]) & 0x3) . $hex[16] . substr($hex, 17, 2), substr($hex, 19, 12));
 }
示例#29
0
 /**
  * @param File $image
  * @param string $dstPath
  * @param string $dstUrl
  * @param array $params
  * @param int $flags
  * @return bool|MediaTransformError|ThumbnailImage|TransformParameterError
  */
 function doTransform($image, $dstPath, $dstUrl, $params, $flags = 0)
 {
     if (!$this->normaliseParams($image, $params)) {
         return new TransformParameterError($params);
     }
     $clientWidth = $params['width'];
     $clientHeight = $params['height'];
     $physicalWidth = $params['physicalWidth'];
     $physicalHeight = $params['physicalHeight'];
     $lang = isset($params['lang']) ? $params['lang'] : $this->getDefaultRenderLanguage($image);
     if ($flags & self::TRANSFORM_LATER) {
         return new ThumbnailImage($image, $dstUrl, $dstPath, $params);
     }
     $metadata = $this->unpackMetadata($image->getMetadata());
     if (isset($metadata['error'])) {
         // sanity check
         $err = wfMessage('svg-long-error', $metadata['error']['message'])->text();
         return new MediaTransformError('thumbnail_error', $clientWidth, $clientHeight, $err);
     }
     if (!wfMkdirParents(dirname($dstPath), null, __METHOD__)) {
         return new MediaTransformError('thumbnail_error', $clientWidth, $clientHeight, wfMessage('thumbnail_dest_directory')->text());
     }
     $srcPath = $image->getLocalRefPath();
     if ($srcPath === false) {
         // Failed to get local copy
         wfDebugLog('thumbnail', sprintf('Thumbnail failed on %s: could not get local copy of "%s"', wfHostname(), $image->getName()));
         return new MediaTransformError('thumbnail_error', $params['width'], $params['height'], wfMessage('filemissing')->text());
     }
     // Make a temp dir with a symlink to the local copy in it.
     // This plays well with rsvg-convert policy for external entities.
     // https://git.gnome.org/browse/librsvg/commit/?id=f01aded72c38f0e18bc7ff67dee800e380251c8e
     $tmpDir = wfTempDir() . '/svg_' . wfRandomString(24);
     $lnPath = "{$tmpDir}/" . basename($srcPath);
     $ok = mkdir($tmpDir, 0771) && symlink($srcPath, $lnPath);
     /** @noinspection PhpUnusedLocalVariableInspection */
     $cleaner = new ScopedCallback(function () use($tmpDir, $lnPath) {
         MediaWiki\suppressWarnings();
         unlink($lnPath);
         rmdir($tmpDir);
         MediaWiki\restoreWarnings();
     });
     if (!$ok) {
         wfDebugLog('thumbnail', sprintf('Thumbnail failed on %s: could not link %s to %s', wfHostname(), $lnPath, $srcPath));
         return new MediaTransformError('thumbnail_error', $params['width'], $params['height'], wfMessage('thumbnail-temp-create')->text());
     }
     $status = $this->rasterize($lnPath, $dstPath, $physicalWidth, $physicalHeight, $lang);
     if ($status === true) {
         return new ThumbnailImage($image, $dstUrl, $dstPath, $params);
     } else {
         return $status;
         // MediaTransformError
     }
 }
示例#30
0
 /**
  * @see JobQueue::doPop()
  * @return Job|bool
  */
 protected function doPop()
 {
     if ($this->cache->get($this->getCacheKey('empty')) === 'true') {
         return false;
         // queue is empty
     }
     list($dbw, $scope) = $this->getMasterDB();
     $dbw->commit(__METHOD__, 'flush');
     // flush existing transaction
     $autoTrx = $dbw->getFlag(DBO_TRX);
     // get current setting
     $dbw->clearFlag(DBO_TRX);
     // make each query its own transaction
     $scopedReset = new ScopedCallback(function () use($dbw, $autoTrx) {
         $dbw->setFlag($autoTrx ? DBO_TRX : 0);
         // restore old setting
     });
     $uuid = wfRandomString(32);
     // pop attempt
     $job = false;
     // job popped off
     do {
         // retry when our row is invalid or deleted as a duplicate
         // Try to reserve a row in the DB...
         if (in_array($this->order, array('fifo', 'timestamp'))) {
             $row = $this->claimOldest($uuid);
         } else {
             // random first
             $rand = mt_rand(0, self::MAX_JOB_RANDOM);
             // encourage concurrent UPDATEs
             $gte = (bool) mt_rand(0, 1);
             // find rows with rand before/after $rand
             $row = $this->claimRandom($uuid, $rand, $gte);
         }
         // Check if we found a row to reserve...
         if (!$row) {
             $this->cache->set($this->getCacheKey('empty'), 'true', self::CACHE_TTL_LONG);
             break;
             // nothing to do
         }
         JobQueue::incrStats('job-pop', $this->type);
         // Get the job object from the row...
         $title = Title::makeTitleSafe($row->job_namespace, $row->job_title);
         if (!$title) {
             $dbw->delete('job', array('job_id' => $row->job_id), __METHOD__);
             wfDebug("Row has invalid title '{$row->job_title}'.");
             continue;
             // try again
         }
         $job = Job::factory($row->job_cmd, $title, self::extractBlob($row->job_params), $row->job_id);
         $job->metadata['id'] = $row->job_id;
         $job->id = $row->job_id;
         // XXX: work around broken subclasses
         break;
         // done
     } while (true);
     return $job;
 }