示例#1
0
 /**
  * Test that generated UIDs have the expected properties
  *
  * @dataProvider provider_testTimestampedUID
  * @covers UIDGenerator::newTimestampedUID128
  * @covers UIDGenerator::newTimestampedUID88
  */
 public function testTimestampedUID($method, $digitlen, $bits, $tbits, $hostbits)
 {
     $id = call_user_func(['UIDGenerator', $method]);
     $this->assertEquals(true, ctype_digit($id), "UID made of digit characters");
     $this->assertLessThanOrEqual($digitlen, strlen($id), "UID has the right number of digits");
     $this->assertLessThanOrEqual($bits, strlen(Wikimedia\base_convert($id, 10, 2)), "UID has the right number of bits");
     $ids = [];
     for ($i = 0; $i < 300; $i++) {
         $ids[] = call_user_func(['UIDGenerator', $method]);
     }
     $lastId = array_shift($ids);
     $this->assertSame(array_unique($ids), $ids, "All generated IDs are unique.");
     foreach ($ids as $id) {
         // Convert string to binary and pad to full length so we can
         // extract segments
         $id_bin = Wikimedia\base_convert($id, 10, 2, $bits);
         $lastId_bin = Wikimedia\base_convert($lastId, 10, 2, $bits);
         $timestamp_bin = substr($id_bin, 0, $tbits);
         $last_timestamp_bin = substr($lastId_bin, 0, $tbits);
         $this->assertGreaterThanOrEqual($last_timestamp_bin, $timestamp_bin, "timestamp ({$timestamp_bin}) of current ID ({$id_bin}) >= timestamp ({$last_timestamp_bin}) " . "of prior one ({$lastId_bin})");
         $hostbits_bin = substr($id_bin, -$hostbits);
         $last_hostbits_bin = substr($lastId_bin, -$hostbits);
         if ($hostbits) {
             $this->assertEquals($hostbits_bin, $last_hostbits_bin, "Host ID ({$hostbits_bin}) of current ID ({$id_bin}) is same as host ID ({$last_hostbits_bin}) " . "of prior one ({$lastId_bin}).");
         }
         $lastId = $id;
     }
 }
示例#2
0
 /**
  * Get a statistically unique ID string
  *
  * @return string <9 char TS_MW timestamp in base 36><22 random base 36 chars>
  */
 public final function getTimestampedUUID()
 {
     $s = '';
     for ($i = 0; $i < 5; $i++) {
         $s .= mt_rand(0, 2147483647);
     }
     $s = Wikimedia\base_convert(sha1($s), 16, 36, 31);
     return substr(Wikimedia\base_convert(wfTimestamp(TS_MW), 10, 36, 9) . $s, 0, 31);
 }
示例#3
0
 protected function getSourceSha1Base36()
 {
     MediaWiki\suppressWarnings();
     $hash = sha1_file($this->params['src']);
     MediaWiki\restoreWarnings();
     if ($hash !== false) {
         $hash = Wikimedia\base_convert($hash, 16, 36, 31);
     }
     return $hash;
 }
示例#4
0
 /**
  * @see JobQueue::doBatchPush
  *
  * @param IJobSpecification[] $jobs
  * @param int $flags
  */
 protected function doBatchPush(array $jobs, $flags)
 {
     $unclaimed =& $this->getQueueData('unclaimed', array());
     foreach ($jobs as $job) {
         if ($job->ignoreDuplicates()) {
             $sha1 = Wikimedia\base_convert(sha1(serialize($job->getDeduplicationInfo())), 16, 36, 31);
             if (!isset($unclaimed[$sha1])) {
                 $unclaimed[$sha1] = $job;
             }
         } else {
             $unclaimed[] = $job;
         }
     }
 }
示例#5
0
 /**
  * @see ExternalStoreMedium::store()
  */
 public function store($backend, $data)
 {
     $be = FileBackendGroup::singleton()->get($backend);
     if ($be instanceof FileBackend) {
         // Get three random base 36 characters to act as shard directories
         $rand = Wikimedia\base_convert(mt_rand(0, 46655), 10, 36, 3);
         // Make sure ID is roughly lexicographically increasing for performance
         $id = str_pad(UIDGenerator::newTimestampedUID128(32), 26, '0', STR_PAD_LEFT);
         // Segregate items by wiki ID for the sake of bookkeeping
         $wiki = isset($this->params['wiki']) ? $this->params['wiki'] : wfWikiID();
         $url = $be->getContainerStoragePath('data') . '/' . rawurlencode($wiki);
         $url .= $be instanceof FSFileBackend ? "/{$rand[0]}/{$rand[1]}/{$rand[2]}/{$id}" : "/{$rand[0]}/{$rand[1]}/{$id}";
         // container sharding is only 2-levels
         $be->prepare(array('dir' => dirname($url), 'noAccess' => 1, 'noListing' => 1));
         if ($be->create(array('dst' => $url, 'content' => $data))->isOK()) {
             return $url;
         }
     }
     return false;
 }
 /**
  * @dataProvider provider_testTimestampedUID
  * @covers UIDGenerator::newTimestampedUID128
  * @covers UIDGenerator::newTimestampedUID88
  */
 public function testTimestampedUID($method, $digitlen, $bits, $tbits, $hostbits)
 {
     $id = call_user_func(array('UIDGenerator', $method));
     $this->assertEquals(true, ctype_digit($id), "UID made of digit characters");
     $this->assertLessThanOrEqual($digitlen, strlen($id), "UID has the right number of digits");
     $this->assertLessThanOrEqual($bits, strlen(Wikimedia\base_convert($id, 10, 2)), "UID has the right number of bits");
     $ids = array();
     for ($i = 0; $i < 300; $i++) {
         $ids[] = call_user_func(array('UIDGenerator', $method));
     }
     $lastId = array_shift($ids);
     $this->assertSame(array_unique($ids), $ids, "All generated IDs are unique.");
     foreach ($ids as $id) {
         $id_bin = Wikimedia\base_convert($id, 10, 2);
         $lastId_bin = Wikimedia\base_convert($lastId, 10, 2);
         $this->assertGreaterThanOrEqual(substr($lastId_bin, 0, $tbits), substr($id_bin, 0, $tbits), "New ID timestamp ({$id_bin}) >= prior one ({$lastId_bin}).");
         if ($hostbits) {
             $this->assertEquals(substr($id_bin, -$hostbits), substr($lastId_bin, -$hostbits), "Host ID of ({$id_bin}) is same as prior one ({$lastId_bin}).");
         }
         $lastId = $id;
     }
 }
 protected function doGetLocksOnServer($lockSrv, array $paths, $type)
 {
     $status = StatusValue::newGood();
     if (!count($paths)) {
         return $status;
         // nothing to lock
     }
     $db = $this->getConnection($lockSrv);
     // checked in isServerUp()
     $bigints = array_unique(array_map(function ($key) {
         return Wikimedia\base_convert(substr($key, 0, 15), 16, 10);
     }, array_map([$this, 'sha1Base16Absolute'], $paths)));
     // Try to acquire all the locks...
     $fields = [];
     foreach ($bigints as $bigint) {
         $fields[] = $type == self::LOCK_SH ? "pg_try_advisory_lock_shared({$db->addQuotes($bigint)}) AS K{$bigint}" : "pg_try_advisory_lock({$db->addQuotes($bigint)}) AS K{$bigint}";
     }
     $res = $db->query('SELECT ' . implode(', ', $fields), __METHOD__);
     $row = $res->fetchRow();
     if (in_array('f', $row)) {
         // Release any acquired locks if some could not be acquired...
         $fields = [];
         foreach ($row as $kbigint => $ok) {
             if ($ok === 't') {
                 // locked
                 $bigint = substr($kbigint, 1);
                 // strip off the "K"
                 $fields[] = $type == self::LOCK_SH ? "pg_advisory_unlock_shared({$db->addQuotes($bigint)})" : "pg_advisory_unlock({$db->addQuotes($bigint)})";
             }
         }
         if (count($fields)) {
             $db->query('SELECT ' . implode(', ', $fields), __METHOD__);
         }
         foreach ($paths as $path) {
             $status->fatal('lockmanager-fail-acquirelock', $path);
         }
     }
     return $status;
 }
示例#8
0
 /**
  * Load a block from the database which affects the already-set $this->target:
  *     1) A block directly on the given user or IP
  *     2) A rangeblock encompassing the given IP (smallest first)
  *     3) An autoblock on the given IP
  * @param User|string $vagueTarget Also search for blocks affecting this target.  Doesn't
  *     make any sense to use TYPE_AUTO / TYPE_ID here. Leave blank to skip IP lookups.
  * @throws MWException
  * @return bool Whether a relevant block was found
  */
 protected function newLoad($vagueTarget = null)
 {
     $db = wfGetDB($this->mFromMaster ? DB_MASTER : DB_SLAVE);
     if ($this->type !== null) {
         $conds = array('ipb_address' => array((string) $this->target));
     } else {
         $conds = array('ipb_address' => array());
     }
     # Be aware that the != '' check is explicit, since empty values will be
     # passed by some callers (bug 29116)
     if ($vagueTarget != '') {
         list($target, $type) = self::parseTarget($vagueTarget);
         switch ($type) {
             case self::TYPE_USER:
                 # Slightly weird, but who are we to argue?
                 $conds['ipb_address'][] = (string) $target;
                 break;
             case self::TYPE_IP:
                 $conds['ipb_address'][] = (string) $target;
                 $conds[] = self::getRangeCond(IP::toHex($target));
                 $conds = $db->makeList($conds, LIST_OR);
                 break;
             case self::TYPE_RANGE:
                 list($start, $end) = IP::parseRange($target);
                 $conds['ipb_address'][] = (string) $target;
                 $conds[] = self::getRangeCond($start, $end);
                 $conds = $db->makeList($conds, LIST_OR);
                 break;
             default:
                 throw new MWException("Tried to load block with invalid type");
         }
     }
     $res = $db->select('ipblocks', self::selectFields(), $conds, __METHOD__);
     # This result could contain a block on the user, a block on the IP, and a russian-doll
     # set of rangeblocks.  We want to choose the most specific one, so keep a leader board.
     $bestRow = null;
     # Lower will be better
     $bestBlockScore = 100;
     # This is begging for $this = $bestBlock, but that's not allowed in PHP :(
     $bestBlockPreventsEdit = null;
     foreach ($res as $row) {
         $block = self::newFromRow($row);
         # Don't use expired blocks
         if ($block->isExpired()) {
             continue;
         }
         # Don't use anon only blocks on users
         if ($this->type == self::TYPE_USER && !$block->isHardblock()) {
             continue;
         }
         if ($block->getType() == self::TYPE_RANGE) {
             # This is the number of bits that are allowed to vary in the block, give
             # or take some floating point errors
             $end = Wikimedia\base_convert($block->getRangeEnd(), 16, 10);
             $start = Wikimedia\base_convert($block->getRangeStart(), 16, 10);
             $size = log($end - $start + 1, 2);
             # This has the nice property that a /32 block is ranked equally with a
             # single-IP block, which is exactly what it is...
             $score = self::TYPE_RANGE - 1 + $size / 128;
         } else {
             $score = $block->getType();
         }
         if ($score < $bestBlockScore) {
             $bestBlockScore = $score;
             $bestRow = $row;
             $bestBlockPreventsEdit = $block->prevents('edit');
         }
     }
     if ($bestRow !== null) {
         $this->initFromRow($bestRow);
         $this->prevents('edit', $bestBlockPreventsEdit);
         return true;
     } else {
         return false;
     }
 }
示例#9
0
 /**
  * Get the base 36 SHA-1 value for a string of text
  * @param string $text
  * @return string
  */
 public static function base36Sha1($text)
 {
     return Wikimedia\base_convert(sha1($text), 16, 36, 31);
 }
示例#10
0
 /**
  * @since 1.26
  * @param string $value
  * @return string Hash
  */
 public static function makeHash($value)
 {
     $hash = hash('fnv132', $value);
     return Wikimedia\base_convert($hash, 16, 36, 7);
 }
示例#11
0
 /**
  * @param IJobSpecification $job
  * @return array
  */
 protected function getNewJobFields(IJobSpecification $job)
 {
     return array('type' => $job->getType(), 'namespace' => $job->getTitle()->getNamespace(), 'title' => $job->getTitle()->getDBkey(), 'params' => $job->getParams(), 'rtimestamp' => $job->getReleaseTimestamp() ?: 0, 'uuid' => UIDGenerator::newRawUUIDv4(UIDGenerator::QUICK_RAND), 'sha1' => $job->ignoreDuplicates() ? Wikimedia\base_convert(sha1(serialize($job->getDeduplicationInfo())), 16, 36, 31) : '', 'timestamp' => time());
 }
示例#12
0
文件: IP.php 项目: OrBin/mediawiki
 /**
  * Given a string range in a number of formats, return the
  * start and end of the range in hexadecimal. For IPv6.
  *
  * Formats are:
  *     2001:0db8:85a3::7344/96                       CIDR
  *     2001:0db8:85a3::7344 - 2001:0db8:85a3::7344   Explicit range
  *     2001:0db8:85a3::7344/96                       Single IP
  *
  * @param string $range
  *
  * @return array(string, string)
  */
 private static function parseRange6($range)
 {
     # Expand any IPv6 IP
     $range = IP::sanitizeIP($range);
     // CIDR notation...
     if (strpos($range, '/') !== false) {
         list($network, $bits) = self::parseCIDR6($range);
         if ($network === false) {
             $start = $end = false;
         } else {
             $start = Wikimedia\base_convert($network, 10, 16, 32, false);
             # Turn network to binary (again)
             $end = Wikimedia\base_convert($network, 10, 2, 128);
             # Truncate the last (128-$bits) bits and replace them with ones
             $end = str_pad(substr($end, 0, $bits), 128, 1, STR_PAD_RIGHT);
             # Convert to hex
             $end = Wikimedia\base_convert($end, 2, 16, 32, false);
             # see toHex() comment
             $start = "v6-{$start}";
             $end = "v6-{$end}";
         }
         // Explicit range notation...
     } elseif (strpos($range, '-') !== false) {
         list($start, $end) = array_map('trim', explode('-', $range, 2));
         $start = self::toHex($start);
         $end = self::toHex($end);
         if ($start > $end) {
             $start = $end = false;
         }
     } else {
         # Single IP
         $start = $end = self::toHex($range);
     }
     if ($start === false || $end === false) {
         return array(false, false);
     } else {
         return array($start, $end);
     }
 }
示例#13
0
 /**
  * Get a list of full container shard suffixes for a container
  *
  * @param string $container
  * @return array
  */
 protected final function getContainerSuffixes($container)
 {
     $shards = [];
     list($digits, $base) = $this->getContainerHashLevels($container);
     if ($digits > 0) {
         $numShards = pow($base, $digits);
         for ($index = 0; $index < $numShards; $index++) {
             $shards[] = '.' . Wikimedia\base_convert($index, 10, $base, $digits);
         }
     }
     return $shards;
 }
 public function execute()
 {
     $user = $this->getUser();
     // Before doing anything at all, let's check permissions
     if (!$user->isAllowed('deletedhistory')) {
         $this->dieUsage('You don\'t have permission to view deleted file information', 'permissiondenied');
     }
     $db = $this->getDB();
     $params = $this->extractRequestParams();
     $prop = array_flip($params['prop']);
     $fld_sha1 = isset($prop['sha1']);
     $fld_timestamp = isset($prop['timestamp']);
     $fld_user = isset($prop['user']);
     $fld_size = isset($prop['size']);
     $fld_dimensions = isset($prop['dimensions']);
     $fld_description = isset($prop['description']) || isset($prop['parseddescription']);
     $fld_mime = isset($prop['mime']);
     $fld_mediatype = isset($prop['mediatype']);
     $fld_metadata = isset($prop['metadata']);
     $fld_bitdepth = isset($prop['bitdepth']);
     $fld_archivename = isset($prop['archivename']);
     $this->addTables('filearchive');
     $this->addFields(ArchivedFile::selectFields());
     $this->addFields(['fa_id', 'fa_name', 'fa_timestamp', 'fa_deleted']);
     $this->addFieldsIf('fa_sha1', $fld_sha1);
     $this->addFieldsIf(['fa_user', 'fa_user_text'], $fld_user);
     $this->addFieldsIf(['fa_height', 'fa_width', 'fa_size'], $fld_dimensions || $fld_size);
     $this->addFieldsIf('fa_description', $fld_description);
     $this->addFieldsIf(['fa_major_mime', 'fa_minor_mime'], $fld_mime);
     $this->addFieldsIf('fa_media_type', $fld_mediatype);
     $this->addFieldsIf('fa_metadata', $fld_metadata);
     $this->addFieldsIf('fa_bits', $fld_bitdepth);
     $this->addFieldsIf('fa_archive_name', $fld_archivename);
     if (!is_null($params['continue'])) {
         $cont = explode('|', $params['continue']);
         $this->dieContinueUsageIf(count($cont) != 3);
         $op = $params['dir'] == 'descending' ? '<' : '>';
         $cont_from = $db->addQuotes($cont[0]);
         $cont_timestamp = $db->addQuotes($db->timestamp($cont[1]));
         $cont_id = (int) $cont[2];
         $this->dieContinueUsageIf($cont[2] !== (string) $cont_id);
         $this->addWhere("fa_name {$op} {$cont_from} OR " . "(fa_name = {$cont_from} AND " . "(fa_timestamp {$op} {$cont_timestamp} OR " . "(fa_timestamp = {$cont_timestamp} AND " . "fa_id {$op}= {$cont_id} )))");
     }
     // Image filters
     $dir = $params['dir'] == 'descending' ? 'older' : 'newer';
     $from = $params['from'] === null ? null : $this->titlePartToKey($params['from'], NS_FILE);
     $to = $params['to'] === null ? null : $this->titlePartToKey($params['to'], NS_FILE);
     $this->addWhereRange('fa_name', $dir, $from, $to);
     if (isset($params['prefix'])) {
         $this->addWhere('fa_name' . $db->buildLike($this->titlePartToKey($params['prefix'], NS_FILE), $db->anyString()));
     }
     $sha1Set = isset($params['sha1']);
     $sha1base36Set = isset($params['sha1base36']);
     if ($sha1Set || $sha1base36Set) {
         $sha1 = false;
         if ($sha1Set) {
             $sha1 = strtolower($params['sha1']);
             if (!$this->validateSha1Hash($sha1)) {
                 $this->dieUsage('The SHA1 hash provided is not valid', 'invalidsha1hash');
             }
             $sha1 = Wikimedia\base_convert($sha1, 16, 36, 31);
         } elseif ($sha1base36Set) {
             $sha1 = strtolower($params['sha1base36']);
             if (!$this->validateSha1Base36Hash($sha1)) {
                 $this->dieUsage('The SHA1Base36 hash provided is not valid', 'invalidsha1base36hash');
             }
         }
         if ($sha1) {
             $this->addWhereFld('fa_sha1', $sha1);
         }
     }
     // Exclude files this user can't view.
     if (!$user->isAllowed('deletedtext')) {
         $bitmask = File::DELETED_FILE;
     } elseif (!$user->isAllowedAny('suppressrevision', 'viewsuppressed')) {
         $bitmask = File::DELETED_FILE | File::DELETED_RESTRICTED;
     } else {
         $bitmask = 0;
     }
     if ($bitmask) {
         $this->addWhere($this->getDB()->bitAnd('fa_deleted', $bitmask) . " != {$bitmask}");
     }
     $limit = $params['limit'];
     $this->addOption('LIMIT', $limit + 1);
     $sort = $params['dir'] == 'descending' ? ' DESC' : '';
     $this->addOption('ORDER BY', ['fa_name' . $sort, 'fa_timestamp' . $sort, 'fa_id' . $sort]);
     $res = $this->select(__METHOD__);
     $count = 0;
     $result = $this->getResult();
     foreach ($res as $row) {
         if (++$count > $limit) {
             // We've reached the one extra which shows that there are
             // additional pages to be had. Stop here...
             $this->setContinueEnumParameter('continue', "{$row->fa_name}|{$row->fa_timestamp}|{$row->fa_id}");
             break;
         }
         $file = [];
         $file['id'] = (int) $row->fa_id;
         $file['name'] = $row->fa_name;
         $title = Title::makeTitle(NS_FILE, $row->fa_name);
         self::addTitleInfo($file, $title);
         if ($fld_description && Revision::userCanBitfield($row->fa_deleted, File::DELETED_COMMENT, $user)) {
             $file['description'] = $row->fa_description;
             if (isset($prop['parseddescription'])) {
                 $file['parseddescription'] = Linker::formatComment($row->fa_description, $title);
             }
         }
         if ($fld_user && Revision::userCanBitfield($row->fa_deleted, File::DELETED_USER, $user)) {
             $file['userid'] = (int) $row->fa_user;
             $file['user'] = $row->fa_user_text;
         }
         if ($fld_sha1) {
             $file['sha1'] = Wikimedia\base_convert($row->fa_sha1, 36, 16, 40);
         }
         if ($fld_timestamp) {
             $file['timestamp'] = wfTimestamp(TS_ISO_8601, $row->fa_timestamp);
         }
         if ($fld_size || $fld_dimensions) {
             $file['size'] = $row->fa_size;
             $pageCount = ArchivedFile::newFromRow($row)->pageCount();
             if ($pageCount !== false) {
                 $file['pagecount'] = $pageCount;
             }
             $file['height'] = $row->fa_height;
             $file['width'] = $row->fa_width;
         }
         if ($fld_mediatype) {
             $file['mediatype'] = $row->fa_media_type;
         }
         if ($fld_metadata) {
             $file['metadata'] = $row->fa_metadata ? ApiQueryImageInfo::processMetaData(unserialize($row->fa_metadata), $result) : null;
         }
         if ($fld_bitdepth) {
             $file['bitdepth'] = $row->fa_bits;
         }
         if ($fld_mime) {
             $file['mime'] = "{$row->fa_major_mime}/{$row->fa_minor_mime}";
         }
         if ($fld_archivename && !is_null($row->fa_archive_name)) {
             $file['archivename'] = $row->fa_archive_name;
         }
         if ($row->fa_deleted & File::DELETED_FILE) {
             $file['filehidden'] = true;
         }
         if ($row->fa_deleted & File::DELETED_COMMENT) {
             $file['commenthidden'] = true;
         }
         if ($row->fa_deleted & File::DELETED_USER) {
             $file['userhidden'] = true;
         }
         if ($row->fa_deleted & File::DELETED_RESTRICTED) {
             // This file is deleted for normal admins
             $file['suppressed'] = true;
         }
         $fit = $result->addValue(['query', $this->getModuleName()], null, $file);
         if (!$fit) {
             $this->setContinueEnumParameter('continue', "{$row->fa_name}|{$row->fa_timestamp}|{$row->fa_id}");
             break;
         }
     }
     $result->addIndexedTagName(['query', $this->getModuleName()], 'fa');
 }
示例#15
0
 /**
  * @param IJobSpecification $job
  * @return array
  */
 protected function insertFields(IJobSpecification $job)
 {
     $dbw = $this->getMasterDB();
     return array('job_cmd' => $job->getType(), 'job_namespace' => $job->getTitle()->getNamespace(), 'job_title' => $job->getTitle()->getDBkey(), 'job_params' => self::makeBlob($job->getParams()), 'job_id' => $dbw->nextSequenceValue('job_job_id_seq'), 'job_timestamp' => $dbw->timestamp(), 'job_sha1' => Wikimedia\base_convert(sha1(serialize($job->getDeduplicationInfo())), 16, 36, 31), 'job_random' => mt_rand(0, self::MAX_JOB_RANDOM));
 }
示例#16
0
/**
 * Convert an arbitrarily-long digit string from one numeric base
 * to another, optionally zero-padding to a minimum column width.
 *
 * Supports base 2 through 36; digit values 10-36 are represented
 * as lowercase letters a-z. Input is case-insensitive.
 *
 * @param string $input Input number
 * @param int $sourceBase Base of the input number
 * @param int $destBase Desired base of the output
 * @param int $pad Minimum number of digits in the output (pad with zeroes)
 * @param bool $lowercase Whether to output in lowercase or uppercase
 * @param string $engine Either "gmp", "bcmath", or "php"
 * @return string|bool The output number as a string, or false on error
 */
function wfBaseConvert($input, $sourceBase, $destBase, $pad = 1, $lowercase = true, $engine = 'auto')
{
    return Wikimedia\base_convert($input, $sourceBase, $destBase, $pad, $lowercase, $engine);
}
示例#17
0
 /**
  * Get result information for an image revision
  *
  * @param File $file
  * @param array $prop Array of properties to get (in the keys)
  * @param ApiResult $result
  * @param array $thumbParams Containing 'width' and 'height' items, or null
  * @param array|bool|string $opts Options for data fetching.
  *   This is an array consisting of the keys:
  *    'version': The metadata version for the metadata option
  *    'language': The language for extmetadata property
  *    'multilang': Return all translations in extmetadata property
  *    'revdelUser': User to use when checking whether to show revision-deleted fields.
  * @return array Result array
  */
 public static function getInfo($file, $prop, $result, $thumbParams = null, $opts = false)
 {
     global $wgContLang;
     $anyHidden = false;
     if (!$opts || is_string($opts)) {
         $opts = ['version' => $opts ?: 'latest', 'language' => $wgContLang, 'multilang' => false, 'extmetadatafilter' => [], 'revdelUser' => null];
     }
     $version = $opts['version'];
     $vals = [ApiResult::META_TYPE => 'assoc'];
     // Timestamp is shown even if the file is revdelete'd in interface
     // so do same here.
     if (isset($prop['timestamp'])) {
         $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $file->getTimestamp());
     }
     // Handle external callers who don't pass revdelUser
     if (isset($opts['revdelUser']) && $opts['revdelUser']) {
         $revdelUser = $opts['revdelUser'];
         $canShowField = function ($field) use($file, $revdelUser) {
             return $file->userCan($field, $revdelUser);
         };
     } else {
         $canShowField = function ($field) use($file) {
             return !$file->isDeleted($field);
         };
     }
     $user = isset($prop['user']);
     $userid = isset($prop['userid']);
     if ($user || $userid) {
         if ($file->isDeleted(File::DELETED_USER)) {
             $vals['userhidden'] = true;
             $anyHidden = true;
         }
         if ($canShowField(File::DELETED_USER)) {
             if ($user) {
                 $vals['user'] = $file->getUser();
             }
             if ($userid) {
                 $vals['userid'] = $file->getUser('id');
             }
             if (!$file->getUser('id')) {
                 $vals['anon'] = true;
             }
         }
     }
     // This is shown even if the file is revdelete'd in interface
     // so do same here.
     if (isset($prop['size']) || isset($prop['dimensions'])) {
         $vals['size'] = intval($file->getSize());
         $vals['width'] = intval($file->getWidth());
         $vals['height'] = intval($file->getHeight());
         $pageCount = $file->pageCount();
         if ($pageCount !== false) {
             $vals['pagecount'] = $pageCount;
         }
         // length as in how many seconds long a video is.
         $length = $file->getLength();
         if ($length) {
             // Call it duration, because "length" can be ambiguous.
             $vals['duration'] = (double) $length;
         }
     }
     $pcomment = isset($prop['parsedcomment']);
     $comment = isset($prop['comment']);
     if ($pcomment || $comment) {
         if ($file->isDeleted(File::DELETED_COMMENT)) {
             $vals['commenthidden'] = true;
             $anyHidden = true;
         }
         if ($canShowField(File::DELETED_COMMENT)) {
             if ($pcomment) {
                 $vals['parsedcomment'] = Linker::formatComment($file->getDescription(File::RAW), $file->getTitle());
             }
             if ($comment) {
                 $vals['comment'] = $file->getDescription(File::RAW);
             }
         }
     }
     $canonicaltitle = isset($prop['canonicaltitle']);
     $url = isset($prop['url']);
     $sha1 = isset($prop['sha1']);
     $meta = isset($prop['metadata']);
     $extmetadata = isset($prop['extmetadata']);
     $commonmeta = isset($prop['commonmetadata']);
     $mime = isset($prop['mime']);
     $mediatype = isset($prop['mediatype']);
     $archive = isset($prop['archivename']);
     $bitdepth = isset($prop['bitdepth']);
     $uploadwarning = isset($prop['uploadwarning']);
     if ($uploadwarning) {
         $vals['html'] = SpecialUpload::getExistsWarning(UploadBase::getExistsWarning($file));
     }
     if ($file->isDeleted(File::DELETED_FILE)) {
         $vals['filehidden'] = true;
         $anyHidden = true;
     }
     if ($anyHidden && $file->isDeleted(File::DELETED_RESTRICTED)) {
         $vals['suppressed'] = true;
     }
     if (!$canShowField(File::DELETED_FILE)) {
         // Early return, tidier than indenting all following things one level
         return $vals;
     }
     if ($canonicaltitle) {
         $vals['canonicaltitle'] = $file->getTitle()->getPrefixedText();
     }
     if ($url) {
         if (!is_null($thumbParams)) {
             $mto = $file->transform($thumbParams);
             self::$transformCount++;
             if ($mto && !$mto->isError()) {
                 $vals['thumburl'] = wfExpandUrl($mto->getUrl(), PROTO_CURRENT);
                 // bug 23834 - If the URL's are the same, we haven't resized it, so shouldn't give the wanted
                 // thumbnail sizes for the thumbnail actual size
                 if ($mto->getUrl() !== $file->getUrl()) {
                     $vals['thumbwidth'] = intval($mto->getWidth());
                     $vals['thumbheight'] = intval($mto->getHeight());
                 } else {
                     $vals['thumbwidth'] = intval($file->getWidth());
                     $vals['thumbheight'] = intval($file->getHeight());
                 }
                 if (isset($prop['thumbmime']) && $file->getHandler()) {
                     list(, $mime) = $file->getHandler()->getThumbType($mto->getExtension(), $file->getMimeType(), $thumbParams);
                     $vals['thumbmime'] = $mime;
                 }
             } elseif ($mto && $mto->isError()) {
                 $vals['thumberror'] = $mto->toText();
             }
         }
         $vals['url'] = wfExpandUrl($file->getFullUrl(), PROTO_CURRENT);
         $vals['descriptionurl'] = wfExpandUrl($file->getDescriptionUrl(), PROTO_CURRENT);
         $shortDescriptionUrl = $file->getDescriptionShortUrl();
         if ($shortDescriptionUrl !== null) {
             $vals['descriptionshorturl'] = wfExpandUrl($shortDescriptionUrl, PROTO_CURRENT);
         }
     }
     if ($sha1) {
         $vals['sha1'] = Wikimedia\base_convert($file->getSha1(), 36, 16, 40);
     }
     if ($meta) {
         MediaWiki\suppressWarnings();
         $metadata = unserialize($file->getMetadata());
         MediaWiki\restoreWarnings();
         if ($metadata && $version !== 'latest') {
             $metadata = $file->convertMetadataVersion($metadata, $version);
         }
         $vals['metadata'] = $metadata ? static::processMetaData($metadata, $result) : null;
     }
     if ($commonmeta) {
         $metaArray = $file->getCommonMetaArray();
         $vals['commonmetadata'] = $metaArray ? static::processMetaData($metaArray, $result) : [];
     }
     if ($extmetadata) {
         // Note, this should return an array where all the keys
         // start with a letter, and all the values are strings.
         // Thus there should be no issue with format=xml.
         $format = new FormatMetadata();
         $format->setSingleLanguage(!$opts['multilang']);
         $format->getContext()->setLanguage($opts['language']);
         $extmetaArray = $format->fetchExtendedMetadata($file);
         if ($opts['extmetadatafilter']) {
             $extmetaArray = array_intersect_key($extmetaArray, array_flip($opts['extmetadatafilter']));
         }
         $vals['extmetadata'] = $extmetaArray;
     }
     if ($mime) {
         $vals['mime'] = $file->getMimeType();
     }
     if ($mediatype) {
         $vals['mediatype'] = $file->getMediaType();
     }
     if ($archive && $file->isOld()) {
         $vals['archivename'] = $file->getArchiveName();
     }
     if ($bitdepth) {
         $vals['bitdepth'] = $file->getBitDepth();
     }
     return $vals;
 }
示例#18
0
 /**
  * Stash a file in a temp directory and record that we did this in the
  * database, along with other metadata.
  *
  * @param string $path Path to file you want stashed
  * @param string $sourceType The type of upload that generated this file
  *   (currently, I believe, 'file' or null)
  * @throws UploadStashBadPathException
  * @throws UploadStashFileException
  * @throws UploadStashNotLoggedInException
  * @return UploadStashFile|null File, or null on failure
  */
 public function stashFile($path, $sourceType = null)
 {
     if (!is_file($path)) {
         wfDebug(__METHOD__ . " tried to stash file at '{$path}', but it doesn't exist\n");
         throw new UploadStashBadPathException("path doesn't exist");
     }
     $mwProps = new MWFileProps(MimeMagic::singleton());
     $fileProps = $mwProps->getPropsFromPath($path, true);
     wfDebug(__METHOD__ . " stashing file at '{$path}'\n");
     // we will be initializing from some tmpnam files that don't have extensions.
     // most of MediaWiki assumes all uploaded files have good extensions. So, we fix this.
     $extension = self::getExtensionForPath($path);
     if (!preg_match("/\\.\\Q{$extension}\\E\$/", $path)) {
         $pathWithGoodExtension = "{$path}.{$extension}";
     } else {
         $pathWithGoodExtension = $path;
     }
     // If no key was supplied, make one.  a mysql insertid would be totally
     // reasonable here, except that for historical reasons, the key is this
     // random thing instead.  At least it's not guessable.
     // Some things that when combined will make a suitably unique key.
     // see: http://www.jwz.org/doc/mid.html
     list($usec, $sec) = explode(' ', microtime());
     $usec = substr($usec, 2);
     $key = Wikimedia\base_convert($sec . $usec, 10, 36) . '.' . Wikimedia\base_convert(mt_rand(), 10, 36) . '.' . $this->userId . '.' . $extension;
     $this->fileProps[$key] = $fileProps;
     if (!preg_match(self::KEY_FORMAT_REGEX, $key)) {
         throw new UploadStashBadPathException("key '{$key}' is not in a proper format");
     }
     wfDebug(__METHOD__ . " key for '{$path}': {$key}\n");
     // if not already in a temporary area, put it there
     $storeStatus = $this->repo->storeTemp(basename($pathWithGoodExtension), $path);
     if (!$storeStatus->isOK()) {
         // It is a convention in MediaWiki to only return one error per API
         // exception, even if multiple errors are available. We use reset()
         // to pick the "first" thing that was wrong, preferring errors to
         // warnings. This is a bit lame, as we may have more info in the
         // $storeStatus and we're throwing it away, but to fix it means
         // redesigning API errors significantly.
         // $storeStatus->value just contains the virtual URL (if anything)
         // which is probably useless to the caller.
         $error = $storeStatus->getErrorsArray();
         $error = reset($error);
         if (!count($error)) {
             $error = $storeStatus->getWarningsArray();
             $error = reset($error);
             if (!count($error)) {
                 $error = ['unknown', 'no error recorded'];
             }
         }
         // At this point, $error should contain the single "most important"
         // error, plus any parameters.
         $errorMsg = array_shift($error);
         throw new UploadStashFileException("Error storing file in '{$path}': " . wfMessage($errorMsg, $error)->text());
     }
     $stashPath = $storeStatus->value;
     // fetch the current user ID
     if (!$this->isLoggedIn) {
         throw new UploadStashNotLoggedInException(__METHOD__ . ' No user is logged in, files must belong to users');
     }
     // insert the file metadata into the db.
     wfDebug(__METHOD__ . " inserting {$stashPath} under {$key}\n");
     $dbw = $this->repo->getMasterDB();
     $serializedFileProps = serialize($fileProps);
     if (strlen($serializedFileProps) > self::MAX_US_PROPS_SIZE) {
         // Database is going to truncate this and make the field invalid.
         // Prioritize important metadata over file handler metadata.
         // File handler should be prepared to regenerate invalid metadata if needed.
         $fileProps['metadata'] = false;
         $serializedFileProps = serialize($fileProps);
     }
     $this->fileMetadata[$key] = ['us_id' => $dbw->nextSequenceValue('uploadstash_us_id_seq'), 'us_user' => $this->userId, 'us_key' => $key, 'us_orig_path' => $path, 'us_path' => $stashPath, 'us_props' => $dbw->encodeBlob($serializedFileProps), 'us_size' => $fileProps['size'], 'us_sha1' => $fileProps['sha1'], 'us_mime' => $fileProps['mime'], 'us_media_type' => $fileProps['media_type'], 'us_image_width' => $fileProps['width'], 'us_image_height' => $fileProps['height'], 'us_image_bits' => $fileProps['bits'], 'us_source_type' => $sourceType, 'us_timestamp' => $dbw->timestamp(), 'us_status' => 'finished'];
     $dbw->insert('uploadstash', $this->fileMetadata[$key], __METHOD__);
     // store the insertid in the class variable so immediate retrieval
     // (possibly laggy) isn't necesary.
     $this->fileMetadata[$key]['us_id'] = $dbw->insertId();
     # create the UploadStashFile object for this file.
     $this->initFile($key);
     return $this->getFile($key);
 }
 public function execute()
 {
     $user = $this->getUser();
     // Before doing anything at all, let's check permissions
     if (!$user->isAllowed('deletedhistory')) {
         $this->dieUsage('You don\'t have permission to view deleted revision information', 'permissiondenied');
     }
     $this->setWarning('list=deletedrevs has been deprecated. Please use prop=deletedrevisions or ' . 'list=alldeletedrevisions instead.');
     $this->logFeatureUsage('action=query&list=deletedrevs');
     $db = $this->getDB();
     $params = $this->extractRequestParams(false);
     $prop = array_flip($params['prop']);
     $fld_parentid = isset($prop['parentid']);
     $fld_revid = isset($prop['revid']);
     $fld_user = isset($prop['user']);
     $fld_userid = isset($prop['userid']);
     $fld_comment = isset($prop['comment']);
     $fld_parsedcomment = isset($prop['parsedcomment']);
     $fld_minor = isset($prop['minor']);
     $fld_len = isset($prop['len']);
     $fld_sha1 = isset($prop['sha1']);
     $fld_content = isset($prop['content']);
     $fld_token = isset($prop['token']);
     $fld_tags = isset($prop['tags']);
     if (isset($prop['token'])) {
         $p = $this->getModulePrefix();
         $this->setWarning("{$p}prop=token has been deprecated. Please use action=query&meta=tokens instead.");
     }
     // If we're in a mode that breaks the same-origin policy, no tokens can
     // be obtained
     if ($this->lacksSameOriginSecurity()) {
         $fld_token = false;
     }
     // If user can't undelete, no tokens
     if (!$user->isAllowed('undelete')) {
         $fld_token = false;
     }
     $result = $this->getResult();
     $pageSet = $this->getPageSet();
     $titles = $pageSet->getTitles();
     // This module operates in three modes:
     // 'revs': List deleted revs for certain titles (1)
     // 'user': List deleted revs by a certain user (2)
     // 'all': List all deleted revs in NS (3)
     $mode = 'all';
     if (count($titles) > 0) {
         $mode = 'revs';
     } elseif (!is_null($params['user'])) {
         $mode = 'user';
     }
     if ($mode == 'revs' || $mode == 'user') {
         // Ignore namespace and unique due to inability to know whether they were purposely set
         foreach (array('from', 'to', 'prefix') as $p) {
             if (!is_null($params[$p])) {
                 $this->dieUsage("The '{$p}' parameter cannot be used in modes 1 or 2", 'badparams');
             }
         }
     } else {
         foreach (array('start', 'end') as $p) {
             if (!is_null($params[$p])) {
                 $this->dieUsage("The {$p} parameter cannot be used in mode 3", 'badparams');
             }
         }
     }
     if (!is_null($params['user']) && !is_null($params['excludeuser'])) {
         $this->dieUsage('user and excludeuser cannot be used together', 'badparams');
     }
     $this->addTables('archive');
     $this->addFields(array('ar_title', 'ar_namespace', 'ar_timestamp', 'ar_deleted', 'ar_id'));
     $this->addFieldsIf('ar_parent_id', $fld_parentid);
     $this->addFieldsIf('ar_rev_id', $fld_revid);
     $this->addFieldsIf('ar_user_text', $fld_user);
     $this->addFieldsIf('ar_user', $fld_userid);
     $this->addFieldsIf('ar_comment', $fld_comment || $fld_parsedcomment);
     $this->addFieldsIf('ar_minor_edit', $fld_minor);
     $this->addFieldsIf('ar_len', $fld_len);
     $this->addFieldsIf('ar_sha1', $fld_sha1);
     if ($fld_tags) {
         $this->addTables('tag_summary');
         $this->addJoinConds(array('tag_summary' => array('LEFT JOIN', array('ar_rev_id=ts_rev_id'))));
         $this->addFields('ts_tags');
     }
     if (!is_null($params['tag'])) {
         $this->addTables('change_tag');
         $this->addJoinConds(array('change_tag' => array('INNER JOIN', array('ar_rev_id=ct_rev_id'))));
         $this->addWhereFld('ct_tag', $params['tag']);
     }
     if ($fld_content) {
         // Modern MediaWiki has the content for deleted revs in the 'text'
         // table using fields old_text and old_flags. But revisions deleted
         // pre-1.5 store the content in the 'archive' table directly using
         // fields ar_text and ar_flags, and no corresponding 'text' row. So
         // we have to LEFT JOIN and fetch all four fields, plus ar_text_id
         // to be able to tell the difference.
         $this->addTables('text');
         $this->addJoinConds(array('text' => array('LEFT JOIN', array('ar_text_id=old_id'))));
         $this->addFields(array('ar_text', 'ar_flags', 'ar_text_id', 'old_text', 'old_flags'));
         // This also means stricter restrictions
         if (!$user->isAllowedAny('undelete', 'deletedtext')) {
             $this->dieUsage('You don\'t have permission to view deleted revision content', 'permissiondenied');
         }
     }
     // Check limits
     $userMax = $fld_content ? ApiBase::LIMIT_SML1 : ApiBase::LIMIT_BIG1;
     $botMax = $fld_content ? ApiBase::LIMIT_SML2 : ApiBase::LIMIT_BIG2;
     $limit = $params['limit'];
     if ($limit == 'max') {
         $limit = $this->getMain()->canApiHighLimits() ? $botMax : $userMax;
         $this->getResult()->addParsedLimit($this->getModuleName(), $limit);
     }
     $this->validateLimit('limit', $limit, 1, $userMax, $botMax);
     if ($fld_token) {
         // Undelete tokens are identical for all pages, so we cache one here
         $token = $user->getEditToken('', $this->getMain()->getRequest());
     }
     $dir = $params['dir'];
     // We need a custom WHERE clause that matches all titles.
     if ($mode == 'revs') {
         $lb = new LinkBatch($titles);
         $where = $lb->constructSet('ar', $db);
         $this->addWhere($where);
     } elseif ($mode == 'all') {
         $this->addWhereFld('ar_namespace', $params['namespace']);
         $from = $params['from'] === null ? null : $this->titlePartToKey($params['from'], $params['namespace']);
         $to = $params['to'] === null ? null : $this->titlePartToKey($params['to'], $params['namespace']);
         $this->addWhereRange('ar_title', $dir, $from, $to);
         if (isset($params['prefix'])) {
             $this->addWhere('ar_title' . $db->buildLike($this->titlePartToKey($params['prefix'], $params['namespace']), $db->anyString()));
         }
     }
     if (!is_null($params['user'])) {
         $this->addWhereFld('ar_user_text', $params['user']);
     } elseif (!is_null($params['excludeuser'])) {
         $this->addWhere('ar_user_text != ' . $db->addQuotes($params['excludeuser']));
     }
     if (!is_null($params['user']) || !is_null($params['excludeuser'])) {
         // Paranoia: avoid brute force searches (bug 17342)
         // (shouldn't be able to get here without 'deletedhistory', but
         // check it again just in case)
         if (!$user->isAllowed('deletedhistory')) {
             $bitmask = Revision::DELETED_USER;
         } elseif (!$user->isAllowedAny('suppressrevision', 'viewsuppressed')) {
             $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
         } else {
             $bitmask = 0;
         }
         if ($bitmask) {
             $this->addWhere($db->bitAnd('ar_deleted', $bitmask) . " != {$bitmask}");
         }
     }
     if (!is_null($params['continue'])) {
         $cont = explode('|', $params['continue']);
         $op = $dir == 'newer' ? '>' : '<';
         if ($mode == 'all' || $mode == 'revs') {
             $this->dieContinueUsageIf(count($cont) != 4);
             $ns = intval($cont[0]);
             $this->dieContinueUsageIf(strval($ns) !== $cont[0]);
             $title = $db->addQuotes($cont[1]);
             $ts = $db->addQuotes($db->timestamp($cont[2]));
             $ar_id = (int) $cont[3];
             $this->dieContinueUsageIf(strval($ar_id) !== $cont[3]);
             $this->addWhere("ar_namespace {$op} {$ns} OR " . "(ar_namespace = {$ns} AND " . "(ar_title {$op} {$title} OR " . "(ar_title = {$title} AND " . "(ar_timestamp {$op} {$ts} OR " . "(ar_timestamp = {$ts} AND " . "ar_id {$op}= {$ar_id})))))");
         } else {
             $this->dieContinueUsageIf(count($cont) != 2);
             $ts = $db->addQuotes($db->timestamp($cont[0]));
             $ar_id = (int) $cont[1];
             $this->dieContinueUsageIf(strval($ar_id) !== $cont[1]);
             $this->addWhere("ar_timestamp {$op} {$ts} OR " . "(ar_timestamp = {$ts} AND " . "ar_id {$op}= {$ar_id})");
         }
     }
     $this->addOption('LIMIT', $limit + 1);
     $this->addOption('USE INDEX', array('archive' => $mode == 'user' ? 'usertext_timestamp' : 'name_title_timestamp'));
     if ($mode == 'all') {
         if ($params['unique']) {
             // @todo Does this work on non-MySQL?
             $this->addOption('GROUP BY', 'ar_title');
         } else {
             $sort = $dir == 'newer' ? '' : ' DESC';
             $this->addOption('ORDER BY', array('ar_title' . $sort, 'ar_timestamp' . $sort, 'ar_id' . $sort));
         }
     } else {
         if ($mode == 'revs') {
             // Sort by ns and title in the same order as timestamp for efficiency
             $this->addWhereRange('ar_namespace', $dir, null, null);
             $this->addWhereRange('ar_title', $dir, null, null);
         }
         $this->addTimestampWhereRange('ar_timestamp', $dir, $params['start'], $params['end']);
         // Include in ORDER BY for uniqueness
         $this->addWhereRange('ar_id', $dir, null, null);
     }
     $res = $this->select(__METHOD__);
     $pageMap = array();
     // Maps ns&title to (fake) pageid
     $count = 0;
     $newPageID = 0;
     foreach ($res as $row) {
         if (++$count > $limit) {
             // We've had enough
             if ($mode == 'all' || $mode == 'revs') {
                 $this->setContinueEnumParameter('continue', "{$row->ar_namespace}|{$row->ar_title}|{$row->ar_timestamp}|{$row->ar_id}");
             } else {
                 $this->setContinueEnumParameter('continue', "{$row->ar_timestamp}|{$row->ar_id}");
             }
             break;
         }
         $rev = array();
         $anyHidden = false;
         $rev['timestamp'] = wfTimestamp(TS_ISO_8601, $row->ar_timestamp);
         if ($fld_revid) {
             $rev['revid'] = intval($row->ar_rev_id);
         }
         if ($fld_parentid && !is_null($row->ar_parent_id)) {
             $rev['parentid'] = intval($row->ar_parent_id);
         }
         if ($fld_user || $fld_userid) {
             if ($row->ar_deleted & Revision::DELETED_USER) {
                 $rev['userhidden'] = true;
                 $anyHidden = true;
             }
             if (Revision::userCanBitfield($row->ar_deleted, Revision::DELETED_USER, $user)) {
                 if ($fld_user) {
                     $rev['user'] = $row->ar_user_text;
                 }
                 if ($fld_userid) {
                     $rev['userid'] = (int) $row->ar_user;
                 }
             }
         }
         if ($fld_comment || $fld_parsedcomment) {
             if ($row->ar_deleted & Revision::DELETED_COMMENT) {
                 $rev['commenthidden'] = true;
                 $anyHidden = true;
             }
             if (Revision::userCanBitfield($row->ar_deleted, Revision::DELETED_COMMENT, $user)) {
                 if ($fld_comment) {
                     $rev['comment'] = $row->ar_comment;
                 }
                 if ($fld_parsedcomment) {
                     $title = Title::makeTitle($row->ar_namespace, $row->ar_title);
                     $rev['parsedcomment'] = Linker::formatComment($row->ar_comment, $title);
                 }
             }
         }
         if ($fld_minor) {
             $rev['minor'] = $row->ar_minor_edit == 1;
         }
         if ($fld_len) {
             $rev['len'] = $row->ar_len;
         }
         if ($fld_sha1) {
             if ($row->ar_deleted & Revision::DELETED_TEXT) {
                 $rev['sha1hidden'] = true;
                 $anyHidden = true;
             }
             if (Revision::userCanBitfield($row->ar_deleted, Revision::DELETED_TEXT, $user)) {
                 if ($row->ar_sha1 != '') {
                     $rev['sha1'] = Wikimedia\base_convert($row->ar_sha1, 36, 16, 40);
                 } else {
                     $rev['sha1'] = '';
                 }
             }
         }
         if ($fld_content) {
             if ($row->ar_deleted & Revision::DELETED_TEXT) {
                 $rev['texthidden'] = true;
                 $anyHidden = true;
             }
             if (Revision::userCanBitfield($row->ar_deleted, Revision::DELETED_TEXT, $user)) {
                 if (isset($row->ar_text) && !$row->ar_text_id) {
                     // Pre-1.5 ar_text row (if condition from Revision::newFromArchiveRow)
                     ApiResult::setContentValue($rev, 'text', Revision::getRevisionText($row, 'ar_'));
                 } else {
                     ApiResult::setContentValue($rev, 'text', Revision::getRevisionText($row));
                 }
             }
         }
         if ($fld_tags) {
             if ($row->ts_tags) {
                 $tags = explode(',', $row->ts_tags);
                 ApiResult::setIndexedTagName($tags, 'tag');
                 $rev['tags'] = $tags;
             } else {
                 $rev['tags'] = array();
             }
         }
         if ($anyHidden && $row->ar_deleted & Revision::DELETED_RESTRICTED) {
             $rev['suppressed'] = true;
         }
         if (!isset($pageMap[$row->ar_namespace][$row->ar_title])) {
             $pageID = $newPageID++;
             $pageMap[$row->ar_namespace][$row->ar_title] = $pageID;
             $a['revisions'] = array($rev);
             ApiResult::setIndexedTagName($a['revisions'], 'rev');
             $title = Title::makeTitle($row->ar_namespace, $row->ar_title);
             ApiQueryBase::addTitleInfo($a, $title);
             if ($fld_token) {
                 $a['token'] = $token;
             }
             $fit = $result->addValue(array('query', $this->getModuleName()), $pageID, $a);
         } else {
             $pageID = $pageMap[$row->ar_namespace][$row->ar_title];
             $fit = $result->addValue(array('query', $this->getModuleName(), $pageID, 'revisions'), null, $rev);
         }
         if (!$fit) {
             if ($mode == 'all' || $mode == 'revs') {
                 $this->setContinueEnumParameter('continue', "{$row->ar_namespace}|{$row->ar_title}|{$row->ar_timestamp}|{$row->ar_id}");
             } else {
                 $this->setContinueEnumParameter('continue', "{$row->ar_timestamp}|{$row->ar_id}");
             }
             break;
         }
     }
     $result->addIndexedTagName(array('query', $this->getModuleName()), 'page');
 }
示例#20
0
 /**
  * Generate a random string suitable for a password
  *
  * @param int $minLength Minimum length of password to generate
  * @return string
  */
 public static function generateRandomPasswordString($minLength = 10)
 {
     // Decide the final password length based on our min password length,
     // stopping at a minimum of 10 chars.
     $length = max(10, $minLength);
     // Multiply by 1.25 to get the number of hex characters we need
     // Generate random hex chars
     $hex = MWCryptRand::generateHex(ceil($length * 1.25));
     // Convert from base 16 to base 32 to get a proper password like string
     return substr(Wikimedia\base_convert($hex, 16, 32, $length), -$length);
 }
示例#21
0
 /**
  * @param array $time Result of UIDGenerator::millitime()
  * @param integer $delta Number of intervals to add on to the timestamp
  * @return string 60 bits of "100ns intervals since 15 October 1582" (rolls over in 3400)
  * @throws RuntimeException
  */
 protected function intervalsSinceGregorianBinary(array $time, $delta = 0)
 {
     list($sec, $msec) = $time;
     $offset = '122192928000000000';
     if (PHP_INT_SIZE >= 8) {
         // 64 bit integers
         $ts = (1000 * $sec + $msec) * 10000 + (int) $offset + $delta;
         $id_bin = str_pad(decbin($ts % pow(2, 60)), 60, '0', STR_PAD_LEFT);
     } elseif (extension_loaded('gmp')) {
         $ts = gmp_add(gmp_mul((string) $sec, '1000'), (string) $msec);
         // ms
         $ts = gmp_add(gmp_mul($ts, '10000'), $offset);
         // 100ns intervals
         $ts = gmp_add($ts, (string) $delta);
         $ts = gmp_mod($ts, gmp_pow('2', '60'));
         // wrap around
         $id_bin = str_pad(gmp_strval($ts, 2), 60, '0', STR_PAD_LEFT);
     } elseif (extension_loaded('bcmath')) {
         $ts = bcadd(bcmul($sec, 1000), $msec);
         // ms
         $ts = bcadd(bcmul($ts, 10000), $offset);
         // 100ns intervals
         $ts = bcadd($ts, $delta);
         $ts = bcmod($ts, bcpow(2, 60));
         // wrap around
         $id_bin = Wikimedia\base_convert($ts, 10, 2, 60);
     } else {
         throw new RuntimeException('bcmath or gmp extension required for 32 bit machines.');
     }
     return $id_bin;
 }
示例#22
0
 /**
  * Extracts from a single sql row the data needed to describe one recent change.
  *
  * @param stdClass $row The row from which to extract the data.
  * @return array An array mapping strings (descriptors) to their respective string values.
  * @access public
  */
 public function extractRowInfo($row)
 {
     /* Determine the title of the page that has been changed. */
     $title = Title::makeTitle($row->rc_namespace, $row->rc_title);
     $user = $this->getUser();
     /* Our output data. */
     $vals = [];
     $type = intval($row->rc_type);
     $vals['type'] = RecentChange::parseFromRCType($type);
     $anyHidden = false;
     /* Create a new entry in the result for the title. */
     if ($this->fld_title || $this->fld_ids) {
         if ($type === RC_LOG && $row->rc_deleted & LogPage::DELETED_ACTION) {
             $vals['actionhidden'] = true;
             $anyHidden = true;
         }
         if ($type !== RC_LOG || LogEventsList::userCanBitfield($row->rc_deleted, LogPage::DELETED_ACTION, $user)) {
             if ($this->fld_title) {
                 ApiQueryBase::addTitleInfo($vals, $title);
             }
             if ($this->fld_ids) {
                 $vals['pageid'] = intval($row->rc_cur_id);
                 $vals['revid'] = intval($row->rc_this_oldid);
                 $vals['old_revid'] = intval($row->rc_last_oldid);
             }
         }
     }
     if ($this->fld_ids) {
         $vals['rcid'] = intval($row->rc_id);
     }
     /* Add user data and 'anon' flag, if user is anonymous. */
     if ($this->fld_user || $this->fld_userid) {
         if ($row->rc_deleted & Revision::DELETED_USER) {
             $vals['userhidden'] = true;
             $anyHidden = true;
         }
         if (Revision::userCanBitfield($row->rc_deleted, Revision::DELETED_USER, $user)) {
             if ($this->fld_user) {
                 $vals['user'] = $row->rc_user_text;
             }
             if ($this->fld_userid) {
                 $vals['userid'] = (int) $row->rc_user;
             }
             if (!$row->rc_user) {
                 $vals['anon'] = true;
             }
         }
     }
     /* Add flags, such as new, minor, bot. */
     if ($this->fld_flags) {
         $vals['bot'] = (bool) $row->rc_bot;
         $vals['new'] = $row->rc_type == RC_NEW;
         $vals['minor'] = (bool) $row->rc_minor;
     }
     /* Add sizes of each revision. (Only available on 1.10+) */
     if ($this->fld_sizes) {
         $vals['oldlen'] = intval($row->rc_old_len);
         $vals['newlen'] = intval($row->rc_new_len);
     }
     /* Add the timestamp. */
     if ($this->fld_timestamp) {
         $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rc_timestamp);
     }
     /* Add edit summary / log summary. */
     if ($this->fld_comment || $this->fld_parsedcomment) {
         if ($row->rc_deleted & Revision::DELETED_COMMENT) {
             $vals['commenthidden'] = true;
             $anyHidden = true;
         }
         if (Revision::userCanBitfield($row->rc_deleted, Revision::DELETED_COMMENT, $user)) {
             if ($this->fld_comment && isset($row->rc_comment)) {
                 $vals['comment'] = $row->rc_comment;
             }
             if ($this->fld_parsedcomment && isset($row->rc_comment)) {
                 $vals['parsedcomment'] = Linker::formatComment($row->rc_comment, $title);
             }
         }
     }
     if ($this->fld_redirect) {
         $vals['redirect'] = (bool) $row->page_is_redirect;
     }
     /* Add the patrolled flag */
     if ($this->fld_patrolled) {
         $vals['patrolled'] = $row->rc_patrolled == 1;
         $vals['unpatrolled'] = ChangesList::isUnpatrolled($row, $user);
     }
     if ($this->fld_loginfo && $row->rc_type == RC_LOG) {
         if ($row->rc_deleted & LogPage::DELETED_ACTION) {
             $vals['actionhidden'] = true;
             $anyHidden = true;
         }
         if (LogEventsList::userCanBitfield($row->rc_deleted, LogPage::DELETED_ACTION, $user)) {
             $vals['logid'] = intval($row->rc_logid);
             $vals['logtype'] = $row->rc_log_type;
             $vals['logaction'] = $row->rc_log_action;
             $vals['logparams'] = LogFormatter::newFromRow($row)->formatParametersForApi();
         }
     }
     if ($this->fld_tags) {
         if ($row->ts_tags) {
             $tags = explode(',', $row->ts_tags);
             ApiResult::setIndexedTagName($tags, 'tag');
             $vals['tags'] = $tags;
         } else {
             $vals['tags'] = [];
         }
     }
     if ($this->fld_sha1 && $row->rev_sha1 !== null) {
         if ($row->rev_deleted & Revision::DELETED_TEXT) {
             $vals['sha1hidden'] = true;
             $anyHidden = true;
         }
         if (Revision::userCanBitfield($row->rev_deleted, Revision::DELETED_TEXT, $user)) {
             if ($row->rev_sha1 !== '') {
                 $vals['sha1'] = Wikimedia\base_convert($row->rev_sha1, 36, 16, 40);
             } else {
                 $vals['sha1'] = '';
             }
         }
     }
     if (!is_null($this->token)) {
         $tokenFunctions = $this->getTokenFunctions();
         foreach ($this->token as $t) {
             $val = call_user_func($tokenFunctions[$t], $row->rc_cur_id, $title, RecentChange::newFromRow($row));
             if ($val === false) {
                 $this->setWarning("Action '{$t}' is not allowed for the current user");
             } else {
                 $vals[$t . 'token'] = $val;
             }
         }
     }
     if ($anyHidden && $row->rc_deleted & Revision::DELETED_RESTRICTED) {
         $vals['suppressed'] = true;
     }
     return $vals;
 }
示例#23
0
 /**
  * @return null|string
  */
 function getSha1()
 {
     return isset($this->mInfo['sha1']) ? Wikimedia\base_convert(strval($this->mInfo['sha1']), 16, 36, 31) : null;
 }
示例#24
0
 /**
  * Get a SHA-1 hash of a file in the local filesystem, in base-36 lower case
  * encoding, zero padded to 31 digits.
  *
  * 160 log 2 / log 36 = 30.95, so the 160-bit hash fills 31 digits in base 36
  * fairly neatly.
  *
  * @param bool $recache
  * @return bool|string False on failure
  */
 public function getSha1Base36($recache = false)
 {
     if ($this->sha1Base36 !== null && !$recache) {
         return $this->sha1Base36;
     }
     MediaWiki\suppressWarnings();
     $this->sha1Base36 = sha1_file($this->path);
     MediaWiki\restoreWarnings();
     if ($this->sha1Base36 !== false) {
         $this->sha1Base36 = Wikimedia\base_convert($this->sha1Base36, 16, 36, 31);
     }
     return $this->sha1Base36;
 }
示例#25
0
 /**
  * @param ApiPageSet $resultPageSet
  * @return void
  */
 private function run($resultPageSet = null)
 {
     $repo = $this->mRepo;
     if (!$repo instanceof LocalRepo) {
         $this->dieUsage('Local file repository does not support querying all images', 'unsupportedrepo');
     }
     $prefix = $this->getModulePrefix();
     $db = $this->getDB();
     $params = $this->extractRequestParams();
     // Table and return fields
     $this->addTables('image');
     $prop = array_flip($params['prop']);
     $this->addFields(LocalFile::selectFields());
     $ascendingOrder = true;
     if ($params['dir'] == 'descending' || $params['dir'] == 'older') {
         $ascendingOrder = false;
     }
     if ($params['sort'] == 'name') {
         // Check mutually exclusive params
         $disallowed = ['start', 'end', 'user'];
         foreach ($disallowed as $pname) {
             if (isset($params[$pname])) {
                 $this->dieUsage("Parameter '{$prefix}{$pname}' can only be used with {$prefix}sort=timestamp", 'badparams');
             }
         }
         if ($params['filterbots'] != 'all') {
             $this->dieUsage("Parameter '{$prefix}filterbots' can only be used with {$prefix}sort=timestamp", 'badparams');
         }
         // Pagination
         if (!is_null($params['continue'])) {
             $cont = explode('|', $params['continue']);
             $this->dieContinueUsageIf(count($cont) != 1);
             $op = $ascendingOrder ? '>' : '<';
             $continueFrom = $db->addQuotes($cont[0]);
             $this->addWhere("img_name {$op}= {$continueFrom}");
         }
         // Image filters
         $from = $params['from'] === null ? null : $this->titlePartToKey($params['from'], NS_FILE);
         $to = $params['to'] === null ? null : $this->titlePartToKey($params['to'], NS_FILE);
         $this->addWhereRange('img_name', $ascendingOrder ? 'newer' : 'older', $from, $to);
         if (isset($params['prefix'])) {
             $this->addWhere('img_name' . $db->buildLike($this->titlePartToKey($params['prefix'], NS_FILE), $db->anyString()));
         }
     } else {
         // Check mutually exclusive params
         $disallowed = ['from', 'to', 'prefix'];
         foreach ($disallowed as $pname) {
             if (isset($params[$pname])) {
                 $this->dieUsage("Parameter '{$prefix}{$pname}' can only be used with {$prefix}sort=name", 'badparams');
             }
         }
         if (!is_null($params['user']) && $params['filterbots'] != 'all') {
             // Since filterbots checks if each user has the bot right, it
             // doesn't make sense to use it with user
             $this->dieUsage("Parameters '{$prefix}user' and '{$prefix}filterbots' cannot be used together", 'badparams');
         }
         // Pagination
         $this->addTimestampWhereRange('img_timestamp', $ascendingOrder ? 'newer' : 'older', $params['start'], $params['end']);
         // Include in ORDER BY for uniqueness
         $this->addWhereRange('img_name', $ascendingOrder ? 'newer' : 'older', null, null);
         if (!is_null($params['continue'])) {
             $cont = explode('|', $params['continue']);
             $this->dieContinueUsageIf(count($cont) != 2);
             $op = $ascendingOrder ? '>' : '<';
             $continueTimestamp = $db->addQuotes($db->timestamp($cont[0]));
             $continueName = $db->addQuotes($cont[1]);
             $this->addWhere("img_timestamp {$op} {$continueTimestamp} OR " . "(img_timestamp = {$continueTimestamp} AND " . "img_name {$op}= {$continueName})");
         }
         // Image filters
         if (!is_null($params['user'])) {
             $this->addWhereFld('img_user_text', $params['user']);
         }
         if ($params['filterbots'] != 'all') {
             $this->addTables('user_groups');
             $this->addJoinConds(['user_groups' => ['LEFT JOIN', ['ug_group' => User::getGroupsWithPermission('bot'), 'ug_user = img_user']]]);
             $groupCond = $params['filterbots'] == 'nobots' ? 'NULL' : 'NOT NULL';
             $this->addWhere("ug_group IS {$groupCond}");
         }
     }
     // Filters not depending on sort
     if (isset($params['minsize'])) {
         $this->addWhere('img_size>=' . intval($params['minsize']));
     }
     if (isset($params['maxsize'])) {
         $this->addWhere('img_size<=' . intval($params['maxsize']));
     }
     $sha1 = false;
     if (isset($params['sha1'])) {
         $sha1 = strtolower($params['sha1']);
         if (!$this->validateSha1Hash($sha1)) {
             $this->dieUsage('The SHA1 hash provided is not valid', 'invalidsha1hash');
         }
         $sha1 = Wikimedia\base_convert($sha1, 16, 36, 31);
     } elseif (isset($params['sha1base36'])) {
         $sha1 = strtolower($params['sha1base36']);
         if (!$this->validateSha1Base36Hash($sha1)) {
             $this->dieUsage('The SHA1Base36 hash provided is not valid', 'invalidsha1base36hash');
         }
     }
     if ($sha1) {
         $this->addWhereFld('img_sha1', $sha1);
     }
     if (!is_null($params['mime'])) {
         if ($this->getConfig()->get('MiserMode')) {
             $this->dieUsage('MIME search disabled in Miser Mode', 'mimesearchdisabled');
         }
         $mimeConds = [];
         foreach ($params['mime'] as $mime) {
             list($major, $minor) = File::splitMime($mime);
             $mimeConds[] = $db->makeList(['img_major_mime' => $major, 'img_minor_mime' => $minor], LIST_AND);
         }
         // safeguard against internal_api_error_DBQueryError
         if (count($mimeConds) > 0) {
             $this->addWhere($db->makeList($mimeConds, LIST_OR));
         } else {
             // no MIME types, no files
             $this->getResult()->addValue('query', $this->getModuleName(), []);
             return;
         }
     }
     $limit = $params['limit'];
     $this->addOption('LIMIT', $limit + 1);
     $sortFlag = '';
     if (!$ascendingOrder) {
         $sortFlag = ' DESC';
     }
     if ($params['sort'] == 'timestamp') {
         $this->addOption('ORDER BY', 'img_timestamp' . $sortFlag);
         if (!is_null($params['user'])) {
             $this->addOption('USE INDEX', ['image' => 'img_usertext_timestamp']);
         } else {
             $this->addOption('USE INDEX', ['image' => 'img_timestamp']);
         }
     } else {
         $this->addOption('ORDER BY', 'img_name' . $sortFlag);
     }
     $res = $this->select(__METHOD__);
     $titles = [];
     $count = 0;
     $result = $this->getResult();
     foreach ($res as $row) {
         if (++$count > $limit) {
             // We've reached the one extra which shows that there are
             // additional pages to be had. Stop here...
             if ($params['sort'] == 'name') {
                 $this->setContinueEnumParameter('continue', $row->img_name);
             } else {
                 $this->setContinueEnumParameter('continue', "{$row->img_timestamp}|{$row->img_name}");
             }
             break;
         }
         if (is_null($resultPageSet)) {
             $file = $repo->newFileFromRow($row);
             $info = array_merge(['name' => $row->img_name], ApiQueryImageInfo::getInfo($file, $prop, $result));
             self::addTitleInfo($info, $file->getTitle());
             $fit = $result->addValue(['query', $this->getModuleName()], null, $info);
             if (!$fit) {
                 if ($params['sort'] == 'name') {
                     $this->setContinueEnumParameter('continue', $row->img_name);
                 } else {
                     $this->setContinueEnumParameter('continue', "{$row->img_timestamp}|{$row->img_name}");
                 }
                 break;
             }
         } else {
             $titles[] = Title::makeTitle(NS_FILE, $row->img_name);
         }
     }
     if (is_null($resultPageSet)) {
         $result->addIndexedTagName(['query', $this->getModuleName()], 'img');
     } else {
         $resultPageSet->populateFromTitles($titles);
     }
 }
示例#26
0
    /**
     * Add data about uploads to the new test DB, and set up the upload
     * directory. This should be called after either setDatabase() or
     * setupDatabase().
     *
     * @param ScopedCallback|null $nextTeardown The next teardown object
     * @return ScopedCallback The teardown object
     */
    public function setupUploads($nextTeardown = null)
    {
        $teardown = [];
        $this->checkSetupDone('setupDatabase', 'setDatabase');
        $teardown[] = $this->markSetupDone('setupUploads');
        // Create the files in the upload directory (or pretend to create them
        // in a MockFileBackend). Append teardown callback.
        $teardown[] = $this->setupUploadBackend();
        // Create a user
        $user = User::createNew('WikiSysop');
        // Register the uploads in the database
        $image = wfLocalFile(Title::makeTitle(NS_FILE, 'Foobar.jpg'));
        # note that the size/width/height/bits/etc of the file
        # are actually set by inspecting the file itself; the arguments
        # to recordUpload2 have no effect.  That said, we try to make things
        # match up so it is less confusing to readers of the code & tests.
        $image->recordUpload2('', 'Upload of some lame file', 'Some lame file', ['size' => 7881, 'width' => 1941, 'height' => 220, 'bits' => 8, 'media_type' => MEDIATYPE_BITMAP, 'mime' => 'image/jpeg', 'metadata' => serialize([]), 'sha1' => Wikimedia\base_convert('1', 16, 36, 31), 'fileExists' => true], $this->db->timestamp('20010115123500'), $user);
        $image = wfLocalFile(Title::makeTitle(NS_FILE, 'Thumb.png'));
        # again, note that size/width/height below are ignored; see above.
        $image->recordUpload2('', 'Upload of some lame thumbnail', 'Some lame thumbnail', ['size' => 22589, 'width' => 135, 'height' => 135, 'bits' => 8, 'media_type' => MEDIATYPE_BITMAP, 'mime' => 'image/png', 'metadata' => serialize([]), 'sha1' => Wikimedia\base_convert('2', 16, 36, 31), 'fileExists' => true], $this->db->timestamp('20130225203040'), $user);
        $image = wfLocalFile(Title::makeTitle(NS_FILE, 'Foobar.svg'));
        $image->recordUpload2('', 'Upload of some lame SVG', 'Some lame SVG', ['size' => 12345, 'width' => 240, 'height' => 180, 'bits' => 0, 'media_type' => MEDIATYPE_DRAWING, 'mime' => 'image/svg+xml', 'metadata' => serialize([]), 'sha1' => Wikimedia\base_convert('', 16, 36, 31), 'fileExists' => true], $this->db->timestamp('20010115123500'), $user);
        # This image will be blacklisted in [[MediaWiki:Bad image list]]
        $image = wfLocalFile(Title::makeTitle(NS_FILE, 'Bad.jpg'));
        $image->recordUpload2('', 'zomgnotcensored', 'Borderline image', ['size' => 12345, 'width' => 320, 'height' => 240, 'bits' => 24, 'media_type' => MEDIATYPE_BITMAP, 'mime' => 'image/jpeg', 'metadata' => serialize([]), 'sha1' => Wikimedia\base_convert('3', 16, 36, 31), 'fileExists' => true], $this->db->timestamp('20010115123500'), $user);
        $image = wfLocalFile(Title::makeTitle(NS_FILE, 'Video.ogv'));
        $image->recordUpload2('', 'A pretty movie', 'Will it play', ['size' => 12345, 'width' => 320, 'height' => 240, 'bits' => 0, 'media_type' => MEDIATYPE_VIDEO, 'mime' => 'application/ogg', 'metadata' => serialize([]), 'sha1' => Wikimedia\base_convert('', 16, 36, 31), 'fileExists' => true], $this->db->timestamp('20010115123500'), $user);
        $image = wfLocalFile(Title::makeTitle(NS_FILE, 'Audio.oga'));
        $image->recordUpload2('', 'An awesome hitsong', 'Will it play', ['size' => 12345, 'width' => 0, 'height' => 0, 'bits' => 0, 'media_type' => MEDIATYPE_AUDIO, 'mime' => 'application/ogg', 'metadata' => serialize([]), 'sha1' => Wikimedia\base_convert('', 16, 36, 31), 'fileExists' => true], $this->db->timestamp('20010115123500'), $user);
        # A DjVu file
        $image = wfLocalFile(Title::makeTitle(NS_FILE, 'LoremIpsum.djvu'));
        $image->recordUpload2('', 'Upload a DjVu', 'A DjVu', ['size' => 3249, 'width' => 2480, 'height' => 3508, 'bits' => 0, 'media_type' => MEDIATYPE_BITMAP, 'mime' => 'image/vnd.djvu', 'metadata' => '<?xml version="1.0" ?>
<!DOCTYPE DjVuXML PUBLIC "-//W3C//DTD DjVuXML 1.1//EN" "pubtext/DjVuXML-s.dtd">
<DjVuXML>
<HEAD></HEAD>
<BODY><OBJECT height="3508" width="2480">
<PARAM name="DPI" value="300" />
<PARAM name="GAMMA" value="2.2" />
</OBJECT>
<OBJECT height="3508" width="2480">
<PARAM name="DPI" value="300" />
<PARAM name="GAMMA" value="2.2" />
</OBJECT>
<OBJECT height="3508" width="2480">
<PARAM name="DPI" value="300" />
<PARAM name="GAMMA" value="2.2" />
</OBJECT>
<OBJECT height="3508" width="2480">
<PARAM name="DPI" value="300" />
<PARAM name="GAMMA" value="2.2" />
</OBJECT>
<OBJECT height="3508" width="2480">
<PARAM name="DPI" value="300" />
<PARAM name="GAMMA" value="2.2" />
</OBJECT>
</BODY>
</DjVuXML>', 'sha1' => Wikimedia\base_convert('', 16, 36, 31), 'fileExists' => true], $this->db->timestamp('20010115123600'), $user);
        return $this->createTeardownObject($teardown, $nextTeardown);
    }
示例#27
0
 protected function doStoreInternal(array $params)
 {
     $status = Status::newGood();
     list($dstCont, $dstRel) = $this->resolveStoragePathReal($params['dst']);
     if ($dstRel === null) {
         $status->fatal('backend-fail-invalidpath', $params['dst']);
         return $status;
     }
     MediaWiki\suppressWarnings();
     $sha1Hash = sha1_file($params['src']);
     MediaWiki\restoreWarnings();
     if ($sha1Hash === false) {
         // source doesn't exist?
         $status->fatal('backend-fail-store', $params['src'], $params['dst']);
         return $status;
     }
     $sha1Hash = Wikimedia\base_convert($sha1Hash, 16, 36, 31);
     $contentType = isset($params['headers']['content-type']) ? $params['headers']['content-type'] : $this->getContentType($params['dst'], null, $params['src']);
     $handle = fopen($params['src'], 'rb');
     if ($handle === false) {
         // source doesn't exist?
         $status->fatal('backend-fail-store', $params['src'], $params['dst']);
         return $status;
     }
     $reqs = array(array('method' => 'PUT', 'url' => array($dstCont, $dstRel), 'headers' => array('content-length' => filesize($params['src']), 'etag' => md5_file($params['src']), 'content-type' => $contentType, 'x-object-meta-sha1base36' => $sha1Hash) + $this->sanitizeHdrs($params), 'body' => $handle));
     $method = __METHOD__;
     $handler = function (array $request, Status $status) use($method, $params) {
         list($rcode, $rdesc, $rhdrs, $rbody, $rerr) = $request['response'];
         if ($rcode === 201) {
             // good
         } elseif ($rcode === 412) {
             $status->fatal('backend-fail-contenttype', $params['dst']);
         } else {
             $this->onError($status, $method, $params, $rerr, $rcode, $rdesc);
         }
     };
     $opHandle = new SwiftFileOpHandle($this, $handler, $reqs);
     if (!empty($params['async'])) {
         // deferred
         $status->value = $opHandle;
     } else {
         // actually write the object in Swift
         $status->merge(current($this->doExecuteOpHandlesInternal(array($opHandle))));
     }
     return $status;
 }
示例#28
0
    function addDBData()
    {
        $this->tablesUsed[] = 'site_stats';
        # disabled for performance
        # $this->tablesUsed[] = 'image';
        # Update certain things in site_stats
        $this->db->insert('site_stats', array('ss_row_id' => 1, 'ss_images' => 2, 'ss_good_articles' => 1), __METHOD__);
        $user = User::newFromId(0);
        LinkCache::singleton()->clear();
        # Avoids the odd failure at creating the nullRevision
        # Upload DB table entries for files.
        # We will upload the actual files later. Note that if anything causes LocalFile::load()
        # to be triggered before then, it will break via maybeUpgrade() setting the fileExists
        # member to false and storing it in cache.
        # note that the size/width/height/bits/etc of the file
        # are actually set by inspecting the file itself; the arguments
        # to recordUpload2 have no effect.  That said, we try to make things
        # match up so it is less confusing to readers of the code & tests.
        $image = wfLocalFile(Title::makeTitle(NS_FILE, 'Foobar.jpg'));
        if (!$this->db->selectField('image', '1', array('img_name' => $image->getName()))) {
            $image->recordUpload2('', 'Upload of some lame file', 'Some lame file', array('size' => 7881, 'width' => 1941, 'height' => 220, 'bits' => 8, 'media_type' => MEDIATYPE_BITMAP, 'mime' => 'image/jpeg', 'metadata' => serialize(array()), 'sha1' => Wikimedia\base_convert('1', 16, 36, 31), 'fileExists' => true), $this->db->timestamp('20010115123500'), $user);
        }
        $image = wfLocalFile(Title::makeTitle(NS_FILE, 'Thumb.png'));
        if (!$this->db->selectField('image', '1', array('img_name' => $image->getName()))) {
            $image->recordUpload2('', 'Upload of some lame thumbnail', 'Some lame thumbnail', array('size' => 22589, 'width' => 135, 'height' => 135, 'bits' => 8, 'media_type' => MEDIATYPE_BITMAP, 'mime' => 'image/png', 'metadata' => serialize(array()), 'sha1' => Wikimedia\base_convert('2', 16, 36, 31), 'fileExists' => true), $this->db->timestamp('20130225203040'), $user);
        }
        # This image will be blacklisted in [[MediaWiki:Bad image list]]
        $image = wfLocalFile(Title::makeTitle(NS_FILE, 'Bad.jpg'));
        if (!$this->db->selectField('image', '1', array('img_name' => $image->getName()))) {
            $image->recordUpload2('', 'zomgnotcensored', 'Borderline image', array('size' => 12345, 'width' => 320, 'height' => 240, 'bits' => 24, 'media_type' => MEDIATYPE_BITMAP, 'mime' => 'image/jpeg', 'metadata' => serialize(array()), 'sha1' => Wikimedia\base_convert('3', 16, 36, 31), 'fileExists' => true), $this->db->timestamp('20010115123500'), $user);
        }
        $image = wfLocalFile(Title::makeTitle(NS_FILE, 'Foobar.svg'));
        if (!$this->db->selectField('image', '1', array('img_name' => $image->getName()))) {
            $image->recordUpload2('', 'Upload of some lame SVG', 'Some lame SVG', array('size' => 12345, 'width' => 240, 'height' => 180, 'bits' => 0, 'media_type' => MEDIATYPE_DRAWING, 'mime' => 'image/svg+xml', 'metadata' => serialize(array()), 'sha1' => Wikimedia\base_convert('', 16, 36, 31), 'fileExists' => true), $this->db->timestamp('20010115123500'), $user);
        }
        # A DjVu file
        $image = wfLocalFile(Title::makeTitle(NS_FILE, 'LoremIpsum.djvu'));
        if (!$this->db->selectField('image', '1', array('img_name' => $image->getName()))) {
            $image->recordUpload2('', 'Upload a DjVu', 'A DjVu', array('size' => 3249, 'width' => 2480, 'height' => 3508, 'bits' => 0, 'media_type' => MEDIATYPE_BITMAP, 'mime' => 'image/vnd.djvu', 'metadata' => '<?xml version="1.0" ?>
<!DOCTYPE DjVuXML PUBLIC "-//W3C//DTD DjVuXML 1.1//EN" "pubtext/DjVuXML-s.dtd">
<DjVuXML>
<HEAD></HEAD>
<BODY><OBJECT height="3508" width="2480">
<PARAM name="DPI" value="300" />
<PARAM name="GAMMA" value="2.2" />
</OBJECT>
<OBJECT height="3508" width="2480">
<PARAM name="DPI" value="300" />
<PARAM name="GAMMA" value="2.2" />
</OBJECT>
<OBJECT height="3508" width="2480">
<PARAM name="DPI" value="300" />
<PARAM name="GAMMA" value="2.2" />
</OBJECT>
<OBJECT height="3508" width="2480">
<PARAM name="DPI" value="300" />
<PARAM name="GAMMA" value="2.2" />
</OBJECT>
<OBJECT height="3508" width="2480">
<PARAM name="DPI" value="300" />
<PARAM name="GAMMA" value="2.2" />
</OBJECT>
</BODY>
</DjVuXML>', 'sha1' => Wikimedia\base_convert('', 16, 36, 31), 'fileExists' => true), $this->db->timestamp('20140115123600'), $user);
        }
    }
示例#29
0
 /**
  * @param string $lockName
  * @return string Integer
  */
 private function bigintFromLockName($lockName)
 {
     return Wikimedia\base_convert(substr(sha1($lockName), 0, 15), 16, 10);
 }
示例#30
0
 /**
  * @return bool|string
  */
 function getSha1()
 {
     if ($this->sha1base36) {
         return Wikimedia\base_convert($this->sha1base36, 36, 16);
     }
     return false;
 }