MediaWiki REL1_39
ApiQueryFilearchive.php
Go to the documentation of this file.
1<?php
32
39
41 private $commentStore;
42
44 private $commentFormatter;
45
52 public function __construct(
53 ApiQuery $query,
54 $moduleName,
55 CommentStore $commentStore,
56 CommentFormatter $commentFormatter
57 ) {
58 parent::__construct( $query, $moduleName, 'fa' );
59 $this->commentStore = $commentStore;
60 $this->commentFormatter = $commentFormatter;
61 }
62
63 public function execute() {
64 $user = $this->getUser();
65 $db = $this->getDB();
66
67 $params = $this->extractRequestParams();
68
69 $prop = array_fill_keys( $params['prop'], true );
70 $fld_sha1 = isset( $prop['sha1'] );
71 $fld_timestamp = isset( $prop['timestamp'] );
72 $fld_user = isset( $prop['user'] );
73 $fld_size = isset( $prop['size'] );
74 $fld_dimensions = isset( $prop['dimensions'] );
75 $fld_description = isset( $prop['description'] ) || isset( $prop['parseddescription'] );
76 $fld_parseddescription = isset( $prop['parseddescription'] );
77 $fld_mime = isset( $prop['mime'] );
78 $fld_mediatype = isset( $prop['mediatype'] );
79 $fld_metadata = isset( $prop['metadata'] );
80 $fld_bitdepth = isset( $prop['bitdepth'] );
81 $fld_archivename = isset( $prop['archivename'] );
82
83 if ( $fld_description && !$this->getAuthority()->isAllowed( 'deletedhistory' ) ) {
84 $this->dieWithError( 'apierror-cantview-deleted-description', 'permissiondenied' );
85 }
86 if ( $fld_metadata && !$this->getAuthority()->isAllowedAny( 'deletedtext', 'undelete' ) ) {
87 $this->dieWithError( 'apierror-cantview-deleted-metadata', 'permissiondenied' );
88 }
89
90 $fileQuery = ArchivedFile::getQueryInfo();
91 $this->addTables( $fileQuery['tables'] );
92 $this->addFields( $fileQuery['fields'] );
93 $this->addJoinConds( $fileQuery['joins'] );
94
95 if ( $params['continue'] !== null ) {
96 $cont = explode( '|', $params['continue'] );
97 $this->dieContinueUsageIf( count( $cont ) != 3 );
98 $op = $params['dir'] == 'descending' ? '<' : '>';
99 $cont_from = $db->addQuotes( $cont[0] );
100 $cont_timestamp = $db->addQuotes( $db->timestamp( $cont[1] ) );
101 $cont_id = (int)$cont[2];
102 $this->dieContinueUsageIf( $cont[2] !== (string)$cont_id );
103 $this->addWhere( "fa_name $op $cont_from OR " .
104 "(fa_name = $cont_from AND " .
105 "(fa_timestamp $op $cont_timestamp OR " .
106 "(fa_timestamp = $cont_timestamp AND " .
107 "fa_id $op= $cont_id )))"
108 );
109 }
110
111 // Image filters
112 $dir = ( $params['dir'] == 'descending' ? 'older' : 'newer' );
113 $from = ( $params['from'] === null ? null : $this->titlePartToKey( $params['from'], NS_FILE ) );
114 $to = ( $params['to'] === null ? null : $this->titlePartToKey( $params['to'], NS_FILE ) );
115 $this->addWhereRange( 'fa_name', $dir, $from, $to );
116 if ( isset( $params['prefix'] ) ) {
117 $this->addWhere( 'fa_name' . $db->buildLike(
118 $this->titlePartToKey( $params['prefix'], NS_FILE ),
119 $db->anyString() ) );
120 }
121
122 $sha1Set = isset( $params['sha1'] );
123 $sha1base36Set = isset( $params['sha1base36'] );
124 if ( $sha1Set || $sha1base36Set ) {
125 $sha1 = false;
126 if ( $sha1Set ) {
127 $sha1 = strtolower( $params['sha1'] );
128 if ( !$this->validateSha1Hash( $sha1 ) ) {
129 $this->dieWithError( 'apierror-invalidsha1hash' );
130 }
131 $sha1 = Wikimedia\base_convert( $sha1, 16, 36, 31 );
132 } elseif ( $sha1base36Set ) {
133 $sha1 = strtolower( $params['sha1base36'] );
134 if ( !$this->validateSha1Base36Hash( $sha1 ) ) {
135 $this->dieWithError( 'apierror-invalidsha1base36hash' );
136 }
137 }
138 if ( $sha1 ) {
139 $this->addWhereFld( 'fa_sha1', $sha1 );
140 // Paranoia: avoid brute force searches (T19342)
141 if ( !$this->getAuthority()->isAllowed( 'deletedtext' ) ) {
142 $bitmask = File::DELETED_FILE;
143 } elseif ( !$this->getAuthority()->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
144 $bitmask = File::DELETED_FILE | File::DELETED_RESTRICTED;
145 } else {
146 $bitmask = 0;
147 }
148 if ( $bitmask ) {
149 $this->addWhere( $this->getDB()->bitAnd( 'fa_deleted', $bitmask ) . " != $bitmask" );
150 }
151 }
152 }
153
154 $limit = $params['limit'];
155 $this->addOption( 'LIMIT', $limit + 1 );
156 $sort = ( $params['dir'] == 'descending' ? ' DESC' : '' );
157 $this->addOption( 'ORDER BY', [
158 'fa_name' . $sort,
159 'fa_timestamp' . $sort,
160 'fa_id' . $sort,
161 ] );
162
163 $res = $this->select( __METHOD__ );
164
165 // Format descriptions in a batch
166 $formattedDescriptions = [];
167 $descriptions = [];
168 if ( $fld_parseddescription ) {
169 $commentItems = [];
170 foreach ( $res as $row ) {
171 $desc = $this->commentStore->getComment( 'fa_description', $row )->text;
172 $descriptions[$row->fa_id] = $desc;
173 $commentItems[$row->fa_id] = ( new CommentItem( $desc ) )
174 ->selfLinkTarget( new TitleValue( NS_FILE, $row->fa_name ) );
175 }
176 $formattedDescriptions = $this->commentFormatter->createBatch()
177 ->comments( $commentItems )
178 ->execute();
179 }
180
181 $count = 0;
182 $result = $this->getResult();
183 foreach ( $res as $row ) {
184 if ( ++$count > $limit ) {
185 // We've reached the one extra which shows that there are
186 // additional pages to be had. Stop here...
188 'continue', "$row->fa_name|$row->fa_timestamp|$row->fa_id"
189 );
190 break;
191 }
192
193 $canViewFile = RevisionRecord::userCanBitfield( $row->fa_deleted, File::DELETED_FILE, $user );
194
195 $file = [];
196 $file['id'] = (int)$row->fa_id;
197 $file['name'] = $row->fa_name;
198 $title = Title::makeTitle( NS_FILE, $row->fa_name );
200
201 if ( $fld_description &&
202 RevisionRecord::userCanBitfield( $row->fa_deleted, File::DELETED_COMMENT, $user )
203 ) {
204 if ( isset( $prop['parseddescription'] ) ) {
205 $file['parseddescription'] = $formattedDescriptions[$row->fa_id];
206 $file['description'] = $descriptions[$row->fa_id];
207 } else {
208 $file['description'] = $this->commentStore->getComment( 'fa_description', $row )->text;
209 }
210 }
211 if ( $fld_user &&
212 RevisionRecord::userCanBitfield( $row->fa_deleted, File::DELETED_USER, $user )
213 ) {
214 $file['userid'] = (int)$row->fa_user;
215 $file['user'] = $row->fa_user_text;
216 }
217 if ( $fld_sha1 && $canViewFile ) {
218 $file['sha1'] = Wikimedia\base_convert( $row->fa_sha1, 36, 16, 40 );
219 }
220 if ( $fld_timestamp ) {
221 $file['timestamp'] = wfTimestamp( TS_ISO_8601, $row->fa_timestamp );
222 }
223 if ( ( $fld_size || $fld_dimensions ) && $canViewFile ) {
224 $file['size'] = $row->fa_size;
225
226 $pageCount = ArchivedFile::newFromRow( $row )->pageCount();
227 if ( $pageCount !== false ) {
228 $file['pagecount'] = $pageCount;
229 }
230
231 $file['height'] = $row->fa_height;
232 $file['width'] = $row->fa_width;
233 }
234 if ( $fld_mediatype && $canViewFile ) {
235 $file['mediatype'] = $row->fa_media_type;
236 }
237 if ( $fld_metadata && $canViewFile ) {
238 $metadataArray = ArchivedFile::newFromRow( $row )->getMetadataArray();
239 $file['metadata'] = $row->fa_metadata
240 ? ApiQueryImageInfo::processMetaData( $metadataArray, $result )
241 : null;
242 }
243 if ( $fld_bitdepth && $canViewFile ) {
244 $file['bitdepth'] = $row->fa_bits;
245 }
246 if ( $fld_mime && $canViewFile ) {
247 $file['mime'] = "$row->fa_major_mime/$row->fa_minor_mime";
248 }
249 if ( $fld_archivename && $row->fa_archive_name !== null ) {
250 $file['archivename'] = $row->fa_archive_name;
251 }
252
253 if ( $row->fa_deleted & File::DELETED_FILE ) {
254 $file['filehidden'] = true;
255 }
256 if ( $row->fa_deleted & File::DELETED_COMMENT ) {
257 $file['commenthidden'] = true;
258 }
259 if ( $row->fa_deleted & File::DELETED_USER ) {
260 $file['userhidden'] = true;
261 }
262 if ( $row->fa_deleted & File::DELETED_RESTRICTED ) {
263 // This file is deleted for normal admins
264 $file['suppressed'] = true;
265 }
266
267 $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $file );
268 if ( !$fit ) {
270 'continue', "$row->fa_name|$row->fa_timestamp|$row->fa_id"
271 );
272 break;
273 }
274 }
275
276 $result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'fa' );
277 }
278
279 public function getAllowedParams() {
280 return [
281 'from' => null,
282 'to' => null,
283 'prefix' => null,
284 'dir' => [
285 ParamValidator::PARAM_DEFAULT => 'ascending',
286 ParamValidator::PARAM_TYPE => [
287 'ascending',
288 'descending'
289 ]
290 ],
291 'sha1' => null,
292 'sha1base36' => null,
293 'prop' => [
294 ParamValidator::PARAM_DEFAULT => 'timestamp',
295 ParamValidator::PARAM_ISMULTI => true,
296 ParamValidator::PARAM_TYPE => [
297 'sha1',
298 'timestamp',
299 'user',
300 'size',
301 'dimensions',
302 'description',
303 'parseddescription',
304 'mime',
305 'mediatype',
306 'metadata',
307 'bitdepth',
308 'archivename',
309 ],
311 ],
312 'limit' => [
313 ParamValidator::PARAM_DEFAULT => 10,
314 ParamValidator::PARAM_TYPE => 'limit',
315 IntegerDef::PARAM_MIN => 1,
316 IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1,
317 IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2
318 ],
319 'continue' => [
320 ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
321 ],
322 ];
323 }
324
325 protected function getExamplesMessages() {
326 return [
327 'action=query&list=filearchive'
328 => 'apihelp-query+filearchive-example-simple',
329 ];
330 }
331
332 public function getHelpUrls() {
333 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Filearchive';
334 }
335}
const NS_FILE
Definition Defines.php:70
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1454
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
Definition ApiBase.php:1643
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, this is an array mapping those values to $msg...
Definition ApiBase.php:196
const LIMIT_BIG1
Fast query, standard limit.
Definition ApiBase.php:221
getResult()
Get the result object.
Definition ApiBase.php:629
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:765
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition ApiBase.php:163
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition ApiBase.php:223
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:498
This is a base class for all Query modules.
static addTitleInfo(&$arr, $title, $prefix='')
Add information (title and namespace) about a Title object to a result array.
setContinueEnumParameter( $paramName, $paramValue)
Set a query-continue value.
validateSha1Base36Hash( $hash)
addWhereRange( $field, $dir, $start, $end, $sort=true)
Add a WHERE clause corresponding to a range, and an ORDER BY clause to sort in the right direction.
validateSha1Hash( $hash)
addFields( $value)
Add a set of fields to select to the internal array.
addOption( $name, $value=null)
Add an option such as LIMIT or USE INDEX.
addTables( $tables, $alias=null)
Add a set of tables to the internal array.
getDB()
Get the Query database connection (read-only)
select( $method, $extraQuery=[], array &$hookData=null)
Execute a SELECT query based on the values in the internal arrays.
addJoinConds( $join_conds)
Add a set of JOIN conditions to the internal array.
addWhereFld( $field, $value)
Equivalent to addWhere( [ $field => $value ] )
titlePartToKey( $titlePart, $namespace=NS_MAIN)
Convert an input title or title prefix into a dbkey.
addWhere( $value)
Add a set of WHERE clauses to the internal array.
Query module to enumerate all deleted files.
getExamplesMessages()
Returns usage examples for this module.
__construct(ApiQuery $query, $moduleName, CommentStore $commentStore, CommentFormatter $commentFormatter)
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
getHelpUrls()
Return links to more detailed help pages about the module.
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
static processMetaData( $metadata, $result)
This is the main query class.
Definition ApiQuery.php:41
static getQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new archivedfile object.
static newFromRow( $row)
Loads a file object from the filearchive table.
Handle database storage of comments such as edit summaries and log reasons.
This is the main service interface for converting single-line comments from various DB comment fields...
An object to represent one of the inputs to a batch formatting operation.
Page revision base class.
Represents a page (or page fragment) title within MediaWiki.
Service for formatting and validating API parameters.
Type definition for integer types.
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition router.php:42