MediaWiki  REL1_24
ApiQueryAllImages.php
Go to the documentation of this file.
00001 <?php
00002 
00034 class ApiQueryAllImages extends ApiQueryGeneratorBase {
00035     protected $mRepo;
00036 
00037     public function __construct( ApiQuery $query, $moduleName ) {
00038         parent::__construct( $query, $moduleName, 'ai' );
00039         $this->mRepo = RepoGroup::singleton()->getLocalRepo();
00040     }
00041 
00049     protected function getDB() {
00050         return $this->mRepo->getSlaveDB();
00051     }
00052 
00053     public function execute() {
00054         $this->run();
00055     }
00056 
00057     public function getCacheMode( $params ) {
00058         return 'public';
00059     }
00060 
00065     public function executeGenerator( $resultPageSet ) {
00066         if ( $resultPageSet->isResolvingRedirects() ) {
00067             $this->dieUsage(
00068                 'Use "gaifilterredir=nonredirects" option instead of "redirects" ' .
00069                     'when using allimages as a generator',
00070                 'params'
00071             );
00072         }
00073 
00074         $this->run( $resultPageSet );
00075     }
00076 
00081     private function run( $resultPageSet = null ) {
00082         $repo = $this->mRepo;
00083         if ( !$repo instanceof LocalRepo ) {
00084             $this->dieUsage(
00085                 'Local file repository does not support querying all images',
00086                 'unsupportedrepo'
00087             );
00088         }
00089 
00090         $prefix = $this->getModulePrefix();
00091 
00092         $db = $this->getDB();
00093 
00094         $params = $this->extractRequestParams();
00095 
00096         // Table and return fields
00097         $this->addTables( 'image' );
00098 
00099         $prop = array_flip( $params['prop'] );
00100         $this->addFields( LocalFile::selectFields() );
00101 
00102         $ascendingOrder = true;
00103         if ( $params['dir'] == 'descending' || $params['dir'] == 'older' ) {
00104             $ascendingOrder = false;
00105         }
00106 
00107         if ( $params['sort'] == 'name' ) {
00108             // Check mutually exclusive params
00109             $disallowed = array( 'start', 'end', 'user' );
00110             foreach ( $disallowed as $pname ) {
00111                 if ( isset( $params[$pname] ) ) {
00112                     $this->dieUsage(
00113                         "Parameter '{$prefix}{$pname}' can only be used with {$prefix}sort=timestamp",
00114                         'badparams'
00115                     );
00116                 }
00117             }
00118             if ( $params['filterbots'] != 'all' ) {
00119                 $this->dieUsage(
00120                     "Parameter '{$prefix}filterbots' can only be used with {$prefix}sort=timestamp",
00121                     'badparams'
00122                 );
00123             }
00124 
00125             // Pagination
00126             if ( !is_null( $params['continue'] ) ) {
00127                 $cont = explode( '|', $params['continue'] );
00128                 $this->dieContinueUsageIf( count( $cont ) != 1 );
00129                 $op = ( $ascendingOrder ? '>' : '<' );
00130                 $continueFrom = $db->addQuotes( $cont[0] );
00131                 $this->addWhere( "img_name $op= $continueFrom" );
00132             }
00133 
00134             // Image filters
00135             $from = ( $params['from'] === null ? null : $this->titlePartToKey( $params['from'], NS_FILE ) );
00136             $to = ( $params['to'] === null ? null : $this->titlePartToKey( $params['to'], NS_FILE ) );
00137             $this->addWhereRange( 'img_name', ( $ascendingOrder ? 'newer' : 'older' ), $from, $to );
00138 
00139             if ( isset( $params['prefix'] ) ) {
00140                 $this->addWhere( 'img_name' . $db->buildLike(
00141                     $this->titlePartToKey( $params['prefix'], NS_FILE ),
00142                     $db->anyString() ) );
00143             }
00144         } else {
00145             // Check mutually exclusive params
00146             $disallowed = array( 'from', 'to', 'prefix' );
00147             foreach ( $disallowed as $pname ) {
00148                 if ( isset( $params[$pname] ) ) {
00149                     $this->dieUsage(
00150                         "Parameter '{$prefix}{$pname}' can only be used with {$prefix}sort=name",
00151                         'badparams'
00152                     );
00153                 }
00154             }
00155             if ( !is_null( $params['user'] ) && $params['filterbots'] != 'all' ) {
00156                 // Since filterbots checks if each user has the bot right, it
00157                 // doesn't make sense to use it with user
00158                 $this->dieUsage(
00159                     "Parameters '{$prefix}user' and '{$prefix}filterbots' cannot be used together",
00160                     'badparams'
00161                 );
00162             }
00163 
00164             // Pagination
00165             $this->addTimestampWhereRange(
00166                 'img_timestamp',
00167                 $ascendingOrder ? 'newer' : 'older',
00168                 $params['start'],
00169                 $params['end']
00170             );
00171             // Include in ORDER BY for uniqueness
00172             $this->addWhereRange( 'img_name', $ascendingOrder ? 'newer' : 'older', null, null );
00173 
00174             if ( !is_null( $params['continue'] ) ) {
00175                 $cont = explode( '|', $params['continue'] );
00176                 $this->dieContinueUsageIf( count( $cont ) != 2 );
00177                 $op = ( $ascendingOrder ? '>' : '<' );
00178                 $continueTimestamp = $db->addQuotes( $db->timestamp( $cont[0] ) );
00179                 $continueName = $db->addQuotes( $cont[1] );
00180                 $this->addWhere( "img_timestamp $op $continueTimestamp OR " .
00181                     "(img_timestamp = $continueTimestamp AND " .
00182                     "img_name $op= $continueName)"
00183                 );
00184             }
00185 
00186             // Image filters
00187             if ( !is_null( $params['user'] ) ) {
00188                 $this->addWhereFld( 'img_user_text', $params['user'] );
00189             }
00190             if ( $params['filterbots'] != 'all' ) {
00191                 $this->addTables( 'user_groups' );
00192                 $this->addJoinConds( array( 'user_groups' => array(
00193                     'LEFT JOIN',
00194                     array(
00195                         'ug_group' => User::getGroupsWithPermission( 'bot' ),
00196                         'ug_user = img_user'
00197                     )
00198                 ) ) );
00199                 $groupCond = ( $params['filterbots'] == 'nobots' ? 'NULL' : 'NOT NULL' );
00200                 $this->addWhere( "ug_group IS $groupCond" );
00201             }
00202         }
00203 
00204         // Filters not depending on sort
00205         if ( isset( $params['minsize'] ) ) {
00206             $this->addWhere( 'img_size>=' . intval( $params['minsize'] ) );
00207         }
00208 
00209         if ( isset( $params['maxsize'] ) ) {
00210             $this->addWhere( 'img_size<=' . intval( $params['maxsize'] ) );
00211         }
00212 
00213         $sha1 = false;
00214         if ( isset( $params['sha1'] ) ) {
00215             $sha1 = strtolower( $params['sha1'] );
00216             if ( !$this->validateSha1Hash( $sha1 ) ) {
00217                 $this->dieUsage( 'The SHA1 hash provided is not valid', 'invalidsha1hash' );
00218             }
00219             $sha1 = wfBaseConvert( $sha1, 16, 36, 31 );
00220         } elseif ( isset( $params['sha1base36'] ) ) {
00221             $sha1 = strtolower( $params['sha1base36'] );
00222             if ( !$this->validateSha1Base36Hash( $sha1 ) ) {
00223                 $this->dieUsage( 'The SHA1Base36 hash provided is not valid', 'invalidsha1base36hash' );
00224             }
00225         }
00226         if ( $sha1 ) {
00227             $this->addWhereFld( 'img_sha1', $sha1 );
00228         }
00229 
00230         if ( !is_null( $params['mime'] ) ) {
00231             if ( $this->getConfig()->get( 'MiserMode' ) ) {
00232                 $this->dieUsage( 'MIME search disabled in Miser Mode', 'mimesearchdisabled' );
00233             }
00234 
00235             list( $major, $minor ) = File::splitMime( $params['mime'] );
00236 
00237             $this->addWhereFld( 'img_major_mime', $major );
00238             $this->addWhereFld( 'img_minor_mime', $minor );
00239         }
00240 
00241         $limit = $params['limit'];
00242         $this->addOption( 'LIMIT', $limit + 1 );
00243         $sortFlag = '';
00244         if ( !$ascendingOrder ) {
00245             $sortFlag = ' DESC';
00246         }
00247         if ( $params['sort'] == 'timestamp' ) {
00248             $this->addOption( 'ORDER BY', 'img_timestamp' . $sortFlag );
00249             if ( !is_null( $params['user'] ) ) {
00250                 $this->addOption( 'USE INDEX', array( 'image' => 'img_usertext_timestamp' ) );
00251             } else {
00252                 $this->addOption( 'USE INDEX', array( 'image' => 'img_timestamp' ) );
00253             }
00254         } else {
00255             $this->addOption( 'ORDER BY', 'img_name' . $sortFlag );
00256         }
00257 
00258         $res = $this->select( __METHOD__ );
00259 
00260         $titles = array();
00261         $count = 0;
00262         $result = $this->getResult();
00263         foreach ( $res as $row ) {
00264             if ( ++$count > $limit ) {
00265                 // We've reached the one extra which shows that there are
00266                 // additional pages to be had. Stop here...
00267                 if ( $params['sort'] == 'name' ) {
00268                     $this->setContinueEnumParameter( 'continue', $row->img_name );
00269                 } else {
00270                     $this->setContinueEnumParameter( 'continue', "$row->img_timestamp|$row->img_name" );
00271                 }
00272                 break;
00273             }
00274 
00275             if ( is_null( $resultPageSet ) ) {
00276                 $file = $repo->newFileFromRow( $row );
00277                 $info = array_merge( array( 'name' => $row->img_name ),
00278                     ApiQueryImageInfo::getInfo( $file, $prop, $result ) );
00279                 self::addTitleInfo( $info, $file->getTitle() );
00280 
00281                 $fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $info );
00282                 if ( !$fit ) {
00283                     if ( $params['sort'] == 'name' ) {
00284                         $this->setContinueEnumParameter( 'continue', $row->img_name );
00285                     } else {
00286                         $this->setContinueEnumParameter( 'continue', "$row->img_timestamp|$row->img_name" );
00287                     }
00288                     break;
00289                 }
00290             } else {
00291                 $titles[] = Title::makeTitle( NS_FILE, $row->img_name );
00292             }
00293         }
00294 
00295         if ( is_null( $resultPageSet ) ) {
00296             $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'img' );
00297         } else {
00298             $resultPageSet->populateFromTitles( $titles );
00299         }
00300     }
00301 
00302     public function getAllowedParams() {
00303         return array(
00304             'sort' => array(
00305                 ApiBase::PARAM_DFLT => 'name',
00306                 ApiBase::PARAM_TYPE => array(
00307                     'name',
00308                     'timestamp'
00309                 )
00310             ),
00311             'dir' => array(
00312                 ApiBase::PARAM_DFLT => 'ascending',
00313                 ApiBase::PARAM_TYPE => array(
00314                     // sort=name
00315                     'ascending',
00316                     'descending',
00317                     // sort=timestamp
00318                     'newer',
00319                     'older'
00320                 )
00321             ),
00322             'from' => null,
00323             'to' => null,
00324             'continue' => null,
00325             'start' => array(
00326                 ApiBase::PARAM_TYPE => 'timestamp'
00327             ),
00328             'end' => array(
00329                 ApiBase::PARAM_TYPE => 'timestamp'
00330             ),
00331             'prop' => array(
00332                 ApiBase::PARAM_TYPE => ApiQueryImageInfo::getPropertyNames( $this->propertyFilter ),
00333                 ApiBase::PARAM_DFLT => 'timestamp|url',
00334                 ApiBase::PARAM_ISMULTI => true
00335             ),
00336             'prefix' => null,
00337             'minsize' => array(
00338                 ApiBase::PARAM_TYPE => 'integer',
00339             ),
00340             'maxsize' => array(
00341                 ApiBase::PARAM_TYPE => 'integer',
00342             ),
00343             'sha1' => null,
00344             'sha1base36' => null,
00345             'user' => array(
00346                 ApiBase::PARAM_TYPE => 'user'
00347             ),
00348             'filterbots' => array(
00349                 ApiBase::PARAM_DFLT => 'all',
00350                 ApiBase::PARAM_TYPE => array(
00351                     'all',
00352                     'bots',
00353                     'nobots'
00354                 )
00355             ),
00356             'mime' => null,
00357             'limit' => array(
00358                 ApiBase::PARAM_DFLT => 10,
00359                 ApiBase::PARAM_TYPE => 'limit',
00360                 ApiBase::PARAM_MIN => 1,
00361                 ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
00362                 ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
00363             ),
00364         );
00365     }
00366 
00367     public function getParamDescription() {
00368         $p = $this->getModulePrefix();
00369 
00370         return array(
00371             'sort' => 'Property to sort by',
00372             'dir' => 'The direction in which to list',
00373             'from' => "The image title to start enumerating from. Can only be used with {$p}sort=name",
00374             'to' => "The image title to stop enumerating at. Can only be used with {$p}sort=name",
00375             'continue' => 'When more results are available, use this to continue',
00376             'start' => "The timestamp to start enumerating from. Can only be used with {$p}sort=timestamp",
00377             'end' => "The timestamp to end enumerating. Can only be used with {$p}sort=timestamp",
00378             'prop' => ApiQueryImageInfo::getPropertyDescriptions( $this->propertyFilter ),
00379             'prefix' => "Search for all image titles that begin with this " .
00380                 "value. Can only be used with {$p}sort=name",
00381             'minsize' => 'Limit to images with at least this many bytes',
00382             'maxsize' => 'Limit to images with at most this many bytes',
00383             'sha1' => "SHA1 hash of image. Overrides {$p}sha1base36",
00384             'sha1base36' => 'SHA1 hash of image in base 36 (used in MediaWiki)',
00385             'user' => "Only return files uploaded by this user. Can only be used " .
00386                 "with {$p}sort=timestamp. Cannot be used together with {$p}filterbots",
00387             'filterbots' => "How to filter files uploaded by bots. Can only be " .
00388                 "used with {$p}sort=timestamp. Cannot be used together with {$p}user",
00389             'mime' => 'What MIME type to search for. e.g. image/jpeg. Disabled in Miser Mode',
00390             'limit' => 'How many images in total to return',
00391         );
00392     }
00393 
00394     private $propertyFilter = array( 'archivename', 'thumbmime', 'uploadwarning' );
00395 
00396     public function getDescription() {
00397         return 'Enumerate all images sequentially.';
00398     }
00399 
00400     public function getExamples() {
00401         return array(
00402             'api.php?action=query&list=allimages&aifrom=B' => array(
00403                 'Simple Use',
00404                 'Show a list of files starting at the letter "B"',
00405             ),
00406             'api.php?action=query&list=allimages&aiprop=user|timestamp|url&' .
00407                 'aisort=timestamp&aidir=older' => array(
00408                 'Simple Use',
00409                 'Show a list of recently uploaded files similar to Special:NewFiles',
00410             ),
00411             'api.php?action=query&generator=allimages&gailimit=4&' .
00412                 'gaifrom=T&prop=imageinfo' => array(
00413                 'Using as Generator',
00414                 'Show info about 4 files starting at the letter "T"',
00415             ),
00416         );
00417     }
00418 
00419     public function getHelpUrls() {
00420         return 'https://www.mediawiki.org/wiki/API:Allimages';
00421     }
00422 }