Esempio n. 1
0
 /**
  * Return an array of files where the name starts with $prefix.
  *
  * @param string $prefix The prefix to search for
  * @param int $limit The maximum amount of files to return
  * @return array
  */
 public function findFilesByPrefix($prefix, $limit)
 {
     $selectOptions = array('ORDER BY' => 'img_name', 'LIMIT' => intval($limit));
     // Query database
     $dbr = $this->getSlaveDB();
     $res = $dbr->select('image', LocalFile::selectFields(), 'img_name ' . $dbr->buildLike($prefix, $dbr->anyString()), __METHOD__, $selectOptions);
     // Build file objects
     $files = array();
     foreach ($res as $row) {
         $files[] = $this->newFileFromRow($row);
     }
     return $files;
 }
Esempio n. 2
0
 /**
  * Get an array or iterator of file objects for files that have a given 
  * SHA-1 content hash.
  */
 function findBySha1($hash)
 {
     $dbr = $this->getSlaveDB();
     $res = $dbr->select('image', LocalFile::selectFields(), array('img_sha1' => $hash));
     $result = array();
     while ($row = $res->fetchObject()) {
         $result[] = $this->newFileFromRow($row);
     }
     $res->free();
     return $result;
 }
Esempio n. 3
0
 function findFiles($titles)
 {
     // FIXME: Only accepts a $titles array where the keys are the sanitized
     // file names.
     if (count($titles) == 0) {
         return array();
     }
     $dbr = $this->getSlaveDB();
     $res = $dbr->select('image', LocalFile::selectFields(), array('img_name' => array_keys($titles)));
     $result = array();
     while ($row = $res->fetchObject()) {
         $result[$row->img_name] = $this->newFileFromRow($row);
     }
     $res->free();
     return $result;
 }
Esempio n. 4
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);
     }
 }
Esempio n. 5
0
 /**
  * Get an array of arrays or iterators of file objects for files that
  * have the given SHA-1 content hashes.
  *
  * Overrides generic implementation in FileRepo for performance reason
  *
  * @param $hashes array An array of hashes
  * @return array An Array of arrays or iterators of file objects and the hash as key
  */
 function findBySha1s(array $hashes)
 {
     if (!count($hashes)) {
         return array();
         //empty parameter
     }
     $dbr = $this->getSlaveDB();
     $res = $dbr->select('image', LocalFile::selectFields(), array('img_sha1' => $hashes), __METHOD__, array('ORDER BY' => 'img_name'));
     $result = array();
     foreach ($res as $row) {
         $file = $this->newFileFromRow($row);
         $result[$file->getSha1()][] = $file;
     }
     $res->free();
     return $result;
 }
Esempio n. 6
0
 /**
  * @param $resultPageSet ApiPageSet
  * @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');
     }
     $db = $this->getDB();
     $params = $this->extractRequestParams();
     if (!is_null($params['continue'])) {
         $cont = explode('|', $params['continue']);
         if (count($cont) != 1) {
             $this->dieUsage("Invalid continue param. You should pass the " . "original value returned by the previous query", "_badcontinue");
         }
         $op = $params['dir'] == 'descending' ? '<' : '>';
         $cont_from = $db->addQuotes($cont[0]);
         $this->addWhere("img_name {$op}= {$cont_from}");
     }
     // Image filters
     $dir = $params['dir'] == 'descending' ? 'older' : 'newer';
     $from = is_null($params['from']) ? null : $this->titlePartToKey($params['from']);
     $to = is_null($params['to']) ? null : $this->titlePartToKey($params['to']);
     $this->addWhereRange('img_name', $dir, $from, $to);
     if (isset($params['prefix'])) {
         $this->addWhere('img_name' . $db->buildLike($this->titlePartToKey($params['prefix']), $db->anyString()));
     }
     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'])) {
         if (!$this->validateSha1Hash($params['sha1'])) {
             $this->dieUsage('The SHA1 hash provided is not valid', 'invalidsha1hash');
         }
         $sha1 = wfBaseConvert($params['sha1'], 16, 36, 31);
     } elseif (isset($params['sha1base36'])) {
         $sha1 = $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'])) {
         global $wgMiserMode;
         if ($wgMiserMode) {
             $this->dieUsage('MIME search disabled in Miser Mode', 'mimesearchdisabled');
         }
         list($major, $minor) = File::splitMime($params['mime']);
         $this->addWhereFld('img_major_mime', $major);
         $this->addWhereFld('img_minor_mime', $minor);
     }
     $this->addTables('image');
     $prop = array_flip($params['prop']);
     $this->addFields(LocalFile::selectFields());
     $limit = $params['limit'];
     $this->addOption('LIMIT', $limit + 1);
     $sort = $params['dir'] == 'descending' ? ' DESC' : '';
     $this->addOption('ORDER BY', 'img_name' . $sort);
     $res = $this->select(__METHOD__);
     $titles = array();
     $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->img_name);
             break;
         }
         if (is_null($resultPageSet)) {
             $file = $repo->newFileFromRow($row);
             $info = array_merge(array('name' => $row->img_name), ApiQueryImageInfo::getInfo($file, $prop, $result));
             self::addTitleInfo($info, $file->getTitle());
             $fit = $result->addValue(array('query', $this->getModuleName()), null, $info);
             if (!$fit) {
                 $this->setContinueEnumParameter('continue', $row->img_name);
                 break;
             }
         } else {
             $titles[] = Title::makeTitle(NS_FILE, $row->img_name);
         }
     }
     if (is_null($resultPageSet)) {
         $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'img');
     } else {
         $resultPageSet->populateFromTitles($titles);
     }
 }
Esempio n. 7
0
 private function run($resultPageSet = null)
 {
     $repo = RepoGroup::singleton()->getLocalRepo();
     if (!$repo instanceof LocalRepo) {
         $this->dieUsage('Local file repository does not support querying all images', 'unsupportedrepo');
     }
     $db = $this->getDB();
     $params = $this->extractRequestParams();
     // Image filters
     $dir = $params['dir'] == 'descending' ? 'older' : 'newer';
     $from = is_null($params['from']) ? null : $this->titlePartToKey($params['from']);
     $this->addWhereRange('img_name', $dir, $from, null);
     if (isset($params['prefix'])) {
         $this->addWhere("img_name LIKE '" . $db->escapeLike($this->titlePartToKey($params['prefix'])) . "%'");
     }
     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 = wfBaseConvert($params['sha1'], 16, 36, 31);
     } elseif (isset($params['sha1base36'])) {
         $sha1 = $params['sha1base36'];
     }
     if ($sha1) {
         $this->addWhere('img_sha1=' . $db->addQuotes($sha1));
     }
     $this->addTables('image');
     $prop = array_flip($params['prop']);
     $this->addFields(LocalFile::selectFields());
     $limit = $params['limit'];
     $this->addOption('LIMIT', $limit + 1);
     $this->addOption('ORDER BY', 'img_name' . ($params['dir'] == 'descending' ? ' DESC' : ''));
     $res = $this->select(__METHOD__);
     $titles = array();
     $count = 0;
     $result = $this->getResult();
     while ($row = $db->fetchObject($res)) {
         if (++$count > $limit) {
             // We've reached the one extra which shows that there are additional pages to be had. Stop here...
             // TODO: Security issue - if the user has no right to view next title, it will still be shown
             $this->setContinueEnumParameter('from', $this->keyToTitle($row->img_name));
             break;
         }
         if (is_null($resultPageSet)) {
             $file = $repo->newFileFromRow($row);
             $info = array_merge(array('name' => $row->img_name), ApiQueryImageInfo::getInfo($file, $prop, $result));
             $fit = $result->addValue(array('query', $this->getModuleName()), null, $info);
             if (!$fit) {
                 $this->setContinueEnumParameter('from', $this->keyToTitle($row->img_name));
                 break;
             }
         } else {
             $titles[] = Title::makeTitle(NS_IMAGE, $row->img_name);
         }
     }
     $db->freeResult($res);
     if (is_null($resultPageSet)) {
         $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'img');
     } else {
         $resultPageSet->populateFromTitles($titles);
     }
 }
Esempio n. 8
0
 public function execute()
 {
     global $wgUser;
     $wgUser = User::newFromName(self::USER);
     $this->isDryRun = $this->hasOption('dry-run');
     $this->otherLocation = $this->getOption('other-location');
     $this->repo = RepoGroup::singleton()->getLocalRepo();
     $this->dbr = $this->getDB(DB_SLAVE);
     $images = 0;
     $imagesMissing = 0;
     $imagesFixed = 0;
     $res = $this->dbr->select('image', LocalFile::selectFields(), '', __METHOD__);
     $count = $res->numRows();
     $this->output(sprintf("Checking all images (%d images)%s...\n\n", $count, $this->isDryRun ? ' in dry run mode' : ''));
     while ($row = $res->fetchObject()) {
         $file = LocalFile::newFromRow($row, $this->repo);
         // 1. check file size (img_size = 0 in image table)
         $this->checkFileSize($file);
         // 2. check for missing files on FS / Swift storage
         $result = $this->processMissingFile($file);
         switch ($result) {
             case self::RESULT_RESTORED:
                 $imagesFixed++;
                 $imagesMissing++;
                 break;
             case self::RESULT_NOT_RESTORED:
                 $imagesMissing++;
                 break;
         }
         // progress
         if (++$images % 100) {
             $this->output(sprintf("%d%%\r", $images / $count * 100));
         }
     }
     // summary
     if (!empty($this->otherLocation)) {
         $this->output(sprintf("Restored %d images from second location \n", count($this->foundMissing)));
         $this->output("List of restored files: \n");
         $this->output(sprintf("%s\n\n", implode("\t\n", $this->foundMissing)));
     }
     $this->output(sprintf("Detected %d missing images (%.2f%% of %d images) and fixed %d images\n\n", $imagesMissing, $imagesMissing / $count * 100, $count, $imagesFixed));
 }
Esempio n. 9
0
 /**
  * @param $resultPageSet ApiPageSet
  * @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());
     $dir = in_array($params['dir'], array('descending', 'older')) ? 'older' : 'newer';
     if ($params['sort'] == 'name') {
         // Check mutually exclusive params
         $disallowed = array('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']);
             if (count($cont) != 1) {
                 $this->dieUsage('Invalid continue param. You should pass the ' . 'original value returned by the previous query', '_badcontinue');
             }
             $op = $dir == 'older' ? '<' : '>';
             $cont_from = $db->addQuotes($cont[0]);
             $this->addWhere("img_name {$op}= {$cont_from}");
         }
         // Image filters
         $from = is_null($params['from']) ? null : $this->titlePartToKey($params['from']);
         $to = is_null($params['to']) ? null : $this->titlePartToKey($params['to']);
         $this->addWhereRange('img_name', $dir, $from, $to);
         if (isset($params['prefix'])) {
             $this->addWhere('img_name' . $db->buildLike($this->titlePartToKey($params['prefix']), $db->anyString()));
         }
     } else {
         // Check mutually exclusive params
         $disallowed = array('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 'user' and 'filterbots' cannot be used together", 'badparams');
         }
         // Pagination
         $this->addTimestampWhereRange('img_timestamp', $dir, $params['start'], $params['end']);
         // Image filters
         if (!is_null($params['user'])) {
             $this->addWhereFld('img_user_text', $params['user']);
         }
         if ($params['filterbots'] != 'all') {
             $this->addTables('user_groups');
             $groupCond = $params['filterbots'] == 'nobots' ? 'NULL' : 'NOT NULL';
             $this->addWhere("ug_group IS {$groupCond}");
             $this->addJoinConds(array('user_groups' => array('LEFT JOIN', array('ug_group' => User::getGroupsWithPermission('bot'), 'ug_user = img_user'))));
         }
     }
     // 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'])) {
         if (!$this->validateSha1Hash($params['sha1'])) {
             $this->dieUsage('The SHA1 hash provided is not valid', 'invalidsha1hash');
         }
         $sha1 = wfBaseConvert($params['sha1'], 16, 36, 31);
     } elseif (isset($params['sha1base36'])) {
         $sha1 = $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'])) {
         global $wgMiserMode;
         if ($wgMiserMode) {
             $this->dieUsage('MIME search disabled in Miser Mode', 'mimesearchdisabled');
         }
         list($major, $minor) = File::splitMime($params['mime']);
         $this->addWhereFld('img_major_mime', $major);
         $this->addWhereFld('img_minor_mime', $minor);
     }
     $limit = $params['limit'];
     $this->addOption('LIMIT', $limit + 1);
     $sort = $dir == 'older' ? ' DESC' : '';
     if ($params['sort'] == 'timestamp') {
         $this->addOption('ORDER BY', 'img_timestamp' . $sort);
         if ($params['filterbots'] == 'all') {
             $this->addOption('USE INDEX', array('image' => 'img_timestamp'));
         } else {
             $this->addOption('USE INDEX', array('image' => 'img_usertext_timestamp'));
         }
     } else {
         $this->addOption('ORDER BY', 'img_name' . $sort);
     }
     $res = $this->select(__METHOD__);
     $titles = array();
     $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('start', wfTimestamp(TS_ISO_8601, $row->img_timestamp));
             }
             break;
         }
         if (is_null($resultPageSet)) {
             $file = $repo->newFileFromRow($row);
             $info = array_merge(array('name' => $row->img_name), ApiQueryImageInfo::getInfo($file, $prop, $result));
             self::addTitleInfo($info, $file->getTitle());
             $fit = $result->addValue(array('query', $this->getModuleName()), null, $info);
             if (!$fit) {
                 if ($params['sort'] == 'name') {
                     $this->setContinueEnumParameter('continue', $row->img_name);
                 } else {
                     $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->img_timestamp));
                 }
                 break;
             }
         } else {
             $titles[] = Title::makeTitle(NS_FILE, $row->img_name);
         }
     }
     if (is_null($resultPageSet)) {
         $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'img');
     } else {
         $resultPageSet->populateFromTitles($titles);
     }
 }