MediaWiki 1.40.4
SpecialMediaStatistics.php
Go to the documentation of this file.
1<?php
30
35
36 public const MAX_LIMIT = 5000;
37
38 protected $totalCount = 0, $totalBytes = 0;
39
43 protected $totalPerType = 0;
44
48 protected $countPerType = 0;
49
53 protected $totalSize = 0;
54
56 private $mimeAnalyzer;
57
63 public function __construct(
64 MimeAnalyzer $mimeAnalyzer,
65 ILoadBalancer $loadBalancer,
66 LinkBatchFactory $linkBatchFactory
67 ) {
68 parent::__construct( 'MediaStatistics' );
69 // Generally speaking there is only a small number of file types,
70 // so just show all of them.
71 $this->limit = self::MAX_LIMIT;
72 $this->shownavigation = false;
73 $this->mimeAnalyzer = $mimeAnalyzer;
74 $this->setDBLoadBalancer( $loadBalancer );
75 $this->setLinkBatchFactory( $linkBatchFactory );
76 }
77
78 public function isExpensive() {
79 return true;
80 }
81
96 public function getQueryInfo() {
97 $dbr = $this->getDBLoadBalancer()->getConnectionRef( ILoadBalancer::DB_REPLICA );
98 $fakeTitle = $dbr->buildConcat( [
99 'img_media_type',
100 $dbr->addQuotes( ';' ),
101 'img_major_mime',
102 $dbr->addQuotes( '/' ),
103 'img_minor_mime',
104 $dbr->addQuotes( ';' ),
105 $dbr->buildStringCast( 'COUNT(*)' ),
106 $dbr->addQuotes( ';' ),
107 $dbr->buildStringCast( 'SUM( img_size )' )
108 ] );
109 return [
110 'tables' => [ 'image' ],
111 'fields' => [
112 'title' => $fakeTitle,
113 'namespace' => NS_MEDIA, /* needs to be something */
114 'value' => '1'
115 ],
116 'options' => [
117 'GROUP BY' => [
118 'img_media_type',
119 'img_major_mime',
120 'img_minor_mime',
121 ]
122 ]
123 ];
124 }
125
133 protected function getOrderFields() {
134 return [ 'img_media_type', 'count(*)', 'img_major_mime', 'img_minor_mime' ];
135 }
136
147 protected function outputResults( $out, $skin, $dbr, $res, $num, $offset ) {
148 $prevMediaType = null;
149 foreach ( $res as $row ) {
150 $mediaStats = $this->splitFakeTitle( $row->title );
151 if ( count( $mediaStats ) < 4 ) {
152 continue;
153 }
154 [ $mediaType, $mime, $totalCount, $totalBytes ] = $mediaStats;
155 if ( $prevMediaType !== $mediaType ) {
156 if ( $prevMediaType !== null ) {
157 // We're not at beginning, so we have to
158 // close the previous table.
159 $this->outputTableEnd();
160 }
161 $this->outputMediaType( $mediaType );
162 $this->totalPerType = 0;
163 $this->countPerType = 0;
164 $this->outputTableStart( $mediaType );
165 $prevMediaType = $mediaType;
166 }
167 $this->outputTableRow( $mime, intval( $totalCount ), intval( $totalBytes ) );
168 }
169 if ( $prevMediaType !== null ) {
170 $this->outputTableEnd();
171 // add total size of all files
172 $this->outputMediaType( 'total' );
173 $this->getOutput()->addWikiTextAsInterface(
174 $this->msg( 'mediastatistics-allbytes' )
175 ->numParams( $this->totalSize )
176 ->sizeParams( $this->totalSize )
177 ->numParams( $this->totalCount )
178 ->text()
179 );
180 }
181 }
182
186 protected function outputTableEnd() {
187 $this->getOutput()->addHTML(
188 Html::closeElement( 'tbody' ) .
189 Html::closeElement( 'table' )
190 );
191 $this->getOutput()->addWikiTextAsInterface(
192 $this->msg( 'mediastatistics-bytespertype' )
193 ->numParams( $this->totalPerType )
194 ->sizeParams( $this->totalPerType )
195 ->numParams( $this->makePercentPretty( $this->totalPerType / $this->totalBytes ) )
196 ->numParams( $this->countPerType )
197 ->numParams( $this->makePercentPretty( $this->countPerType / $this->totalCount ) )
198 ->text()
199 );
200 $this->totalSize += $this->totalPerType;
201 }
202
210 protected function outputTableRow( $mime, $count, $bytes ) {
211 $mimeSearch = SpecialPage::getTitleFor( 'MIMEsearch', $mime );
212 $linkRenderer = $this->getLinkRenderer();
213 $row = Html::rawElement(
214 'td',
215 [],
216 $linkRenderer->makeLink( $mimeSearch, $mime )
217 );
218 $row .= Html::rawElement(
219 'td',
220 [],
221 $this->getExtensionList( $mime )
222 );
223 $row .= Html::rawElement(
224 'td',
225 // Make sure js sorts it in numeric order
226 [ 'data-sort-value' => $count ],
227 $this->msg( 'mediastatistics-nfiles' )
228 ->numParams( $count )
230 ->numParams( $this->makePercentPretty( $count / $this->totalCount ) )
231 ->parse()
232 );
233 $row .= Html::rawElement(
234 'td',
235 // Make sure js sorts it in numeric order
236 [ 'data-sort-value' => $bytes ],
237 $this->msg( 'mediastatistics-nbytes' )
238 ->numParams( $bytes )
239 ->sizeParams( $bytes )
241 ->numParams( $this->makePercentPretty( $bytes / $this->totalBytes ) )
242 ->parse()
243 );
244 $this->totalPerType += $bytes;
245 $this->countPerType += $count;
246 $this->getOutput()->addHTML( Html::rawElement( 'tr', [], $row ) );
247 }
248
253 protected function makePercentPretty( $decimal ) {
254 $decimal *= 100;
255 // Always show three useful digits
256 if ( $decimal == 0 ) {
257 return '0';
258 }
259 if ( $decimal >= 100 ) {
260 return '100';
261 }
262 $percent = sprintf( "%." . max( 0, 2 - floor( log10( $decimal ) ) ) . "f", $decimal );
263 // Then remove any trailing 0's
264 return preg_replace( '/\.?0*$/', '', $percent );
265 }
266
273 private function getExtensionList( $mime ) {
274 $exts = $this->mimeAnalyzer->getExtensionsFromMimeType( $mime );
275 if ( !$exts ) {
276 return '';
277 }
278 foreach ( $exts as &$ext ) {
279 $ext = htmlspecialchars( '.' . $ext );
280 }
281
282 return $this->getLanguage()->commaList( $exts );
283 }
284
291 protected function outputTableStart( $mediaType ) {
292 $out = $this->getOutput();
293 $out->addModuleStyles( 'jquery.tablesorter.styles' );
294 $out->addModules( 'jquery.tablesorter' );
295 $out->addHTML(
296 Html::openElement(
297 'table',
298 [ 'class' => [
299 'mw-mediastats-table',
300 'mw-mediastats-table-' . strtolower( $mediaType ),
301 'sortable',
302 'wikitable'
303 ] ]
304 ) .
305 Html::rawElement( 'thead', [], $this->getTableHeaderRow() ) .
306 Html::openElement( 'tbody' )
307 );
308 }
309
315 protected function getTableHeaderRow() {
316 $headers = [ 'mimetype', 'extensions', 'count', 'totalbytes' ];
317 $ths = '';
318 foreach ( $headers as $header ) {
319 $ths .= Html::rawElement(
320 'th',
321 [],
322 // for grep:
323 // mediastatistics-table-mimetype, mediastatistics-table-extensions
324 // mediastatistics-table-count, mediastatistics-table-totalbytes
325 $this->msg( 'mediastatistics-table-' . $header )->parse()
326 );
327 }
328 return Html::rawElement( 'tr', [], $ths );
329 }
330
336 protected function outputMediaType( $mediaType ) {
337 $this->getOutput()->addHTML(
338 Html::element(
339 'h2',
340 [ 'class' => [
341 'mw-mediastats-mediatype',
342 'mw-mediastats-mediatype-' . strtolower( $mediaType )
343 ] ],
344 // for grep
345 // mediastatistics-header-unknown, mediastatistics-header-bitmap,
346 // mediastatistics-header-drawing, mediastatistics-header-audio,
347 // mediastatistics-header-video, mediastatistics-header-multimedia,
348 // mediastatistics-header-office, mediastatistics-header-text,
349 // mediastatistics-header-executable, mediastatistics-header-archive,
350 // mediastatistics-header-3d,
351 $this->msg( 'mediastatistics-header-' . strtolower( $mediaType ) )->text()
352 )
353 );
357 }
358
365 private function splitFakeTitle( $fakeTitle ) {
366 return explode( ';', $fakeTitle, 4 );
367 }
368
373 protected function getGroupName() {
374 return 'media';
375 }
376
386 public function formatResult( $skin, $result ) {
387 throw new LogicException( "unimplemented" );
388 }
389
396 public function preprocessResults( $dbr, $res ) {
398 $this->totalCount = $this->totalBytes = 0;
399 foreach ( $res as $row ) {
400 $mediaStats = $this->splitFakeTitle( $row->title );
401 $this->totalCount += $mediaStats[2] ?? 0;
402 $this->totalBytes += $mediaStats[3] ?? 0;
403 }
404 $res->seek( 0 );
405 }
406}
const NS_MEDIA
Definition Defines.php:52
This class is a collection of static functions that serve two purposes:
Definition Html.php:55
This is a class for doing query pages; since they're almost all the same, we factor out some of the f...
Definition QueryPage.php:45
executeLBFromResultWrapper(IResultWrapper $res, $ns=null)
Creates a new LinkBatch object, adds all pages from the passed result wrapper (MUST include title and...
setDBLoadBalancer(ILoadBalancer $loadBalancer)
int $offset
The offset and limit in use, as passed to the query() function.
Definition QueryPage.php:50
setLinkBatchFactory(LinkBatchFactory $linkBatchFactory)
getDBLoadBalancer()
formatResult( $skin, $result)
This method isn't used, since we override outputResults, but we need to implement since abstract in p...
getGroupName()
What group to put the page in.
preprocessResults( $dbr, $res)
Initialize total values so we can figure out percentages later.
int $totalSize
Combined file size of all files.
int $totalPerType
Combined file size of all files in a section.
__construct(MimeAnalyzer $mimeAnalyzer, ILoadBalancer $loadBalancer, LinkBatchFactory $linkBatchFactory)
int $countPerType
Combined file count of all files in a section.
outputResults( $out, $skin, $dbr, $res, $num, $offset)
Output the results of the query.
outputTableStart( $mediaType)
Output the start of the table.
getTableHeaderRow()
Get (not output) the header row for the table.
outputTableRow( $mime, $count, $bytes)
Output a row of the stats table.
isExpensive()
Should this query page only be updated offline on large wikis?
getOrderFields()
How to sort the results.
outputMediaType( $mediaType)
Output a header for a new media type section.
getOutput()
Get the OutputPage being used for this instance.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getLanguage()
Shortcut to get user's language.
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:36
This class is a delegate to ILBFactory for a given database cluster.
Result wrapper for grabbing data queried from an IDatabase object.
$mime
Definition router.php:60
if(!is_readable( $file)) $ext
Definition router.php:48
$header