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