MediaWiki  master
SpecialMediaStatistics.php
Go to the documentation of this file.
1 <?php
27 
32  protected $totalCount = 0, $totalBytes = 0;
33 
37  protected $totalPerType = 0;
38 
42  protected $totalSize = 0;
43 
44  function __construct( $name = 'MediaStatistics' ) {
45  parent::__construct( $name );
46  // Generally speaking there is only a small number of file types,
47  // so just show all of them.
48  $this->limit = 5000;
49  $this->shownavigation = false;
50  }
51 
52  public function isExpensive() {
53  return true;
54  }
55 
70  public function getQueryInfo() {
71  $dbr = wfGetDB( DB_REPLICA );
72  $fakeTitle = $dbr->buildConcat( [
73  'img_media_type',
74  $dbr->addQuotes( ';' ),
75  'img_major_mime',
76  $dbr->addQuotes( '/' ),
77  'img_minor_mime',
78  $dbr->addQuotes( ';' ),
79  $dbr->buildStringCast( 'COUNT(*)' ),
80  $dbr->addQuotes( ';' ),
81  $dbr->buildStringCast( 'SUM( img_size )' )
82  ] );
83  return [
84  'tables' => [ 'image' ],
85  'fields' => [
86  'title' => $fakeTitle,
87  'namespace' => NS_MEDIA, /* needs to be something */
88  'value' => '1'
89  ],
90  'options' => [
91  'GROUP BY' => [
92  'img_media_type',
93  'img_major_mime',
94  'img_minor_mime',
95  ]
96  ]
97  ];
98  }
99 
107  function getOrderFields() {
108  return [ 'img_media_type', 'count(*)', 'img_major_mime', 'img_minor_mime' ];
109  }
110 
121  protected function outputResults( $out, $skin, $dbr, $res, $num, $offset ) {
122  $prevMediaType = null;
123  foreach ( $res as $row ) {
124  $mediaStats = $this->splitFakeTitle( $row->title );
125  if ( count( $mediaStats ) < 4 ) {
126  continue;
127  }
128  list( $mediaType, $mime, $totalCount, $totalBytes ) = $mediaStats;
129  if ( $prevMediaType !== $mediaType ) {
130  if ( $prevMediaType !== null ) {
131  // We're not at beginning, so we have to
132  // close the previous table.
133  $this->outputTableEnd();
134  }
135  $this->outputMediaType( $mediaType );
136  $this->totalPerType = 0;
137  $this->outputTableStart( $mediaType );
138  $prevMediaType = $mediaType;
139  }
140  $this->outputTableRow( $mime, intval( $totalCount ), intval( $totalBytes ) );
141  }
142  if ( $prevMediaType !== null ) {
143  $this->outputTableEnd();
144  // add total size of all files
145  $this->outputMediaType( 'total' );
146  $this->getOutput()->addWikiTextAsInterface(
147  $this->msg( 'mediastatistics-allbytes' )
148  ->numParams( $this->totalSize )
149  ->sizeParams( $this->totalSize )
150  ->text()
151  );
152  }
153  }
154 
158  protected function outputTableEnd() {
159  $this->getOutput()->addHTML(
160  Html::closeElement( 'tbody' ) .
161  Html::closeElement( 'table' )
162  );
163  $this->getOutput()->addWikiTextAsInterface(
164  $this->msg( 'mediastatistics-bytespertype' )
165  ->numParams( $this->totalPerType )
166  ->sizeParams( $this->totalPerType )
167  ->numParams( $this->makePercentPretty( $this->totalPerType / $this->totalBytes ) )
168  ->text()
169  );
170  $this->totalSize += $this->totalPerType;
171  }
172 
180  protected function outputTableRow( $mime, $count, $bytes ) {
181  $mimeSearch = SpecialPage::getTitleFor( 'MIMEsearch', $mime );
182  $linkRenderer = $this->getLinkRenderer();
183  $row = Html::rawElement(
184  'td',
185  [],
186  $linkRenderer->makeLink( $mimeSearch, $mime )
187  );
188  $row .= Html::rawElement(
189  'td',
190  [],
191  $this->getExtensionList( $mime )
192  );
193  $row .= Html::rawElement(
194  'td',
195  // Make sure js sorts it in numeric order
196  [ 'data-sort-value' => $count ],
197  $this->msg( 'mediastatistics-nfiles' )
198  ->numParams( $count )
200  ->numParams( $this->makePercentPretty( $count / $this->totalCount ) )
201  ->parse()
202  );
203  $row .= Html::rawElement(
204  'td',
205  // Make sure js sorts it in numeric order
206  [ 'data-sort-value' => $bytes ],
207  $this->msg( 'mediastatistics-nbytes' )
208  ->numParams( $bytes )
209  ->sizeParams( $bytes )
211  ->numParams( $this->makePercentPretty( $bytes / $this->totalBytes ) )
212  ->parse()
213  );
214  $this->totalPerType += $bytes;
215  $this->getOutput()->addHTML( Html::rawElement( 'tr', [], $row ) );
216  }
217 
222  protected function makePercentPretty( $decimal ) {
223  $decimal *= 100;
224  // Always show three useful digits
225  if ( $decimal == 0 ) {
226  return '0';
227  }
228  if ( $decimal >= 100 ) {
229  return '100';
230  }
231  $percent = sprintf( "%." . max( 0, 2 - floor( log10( $decimal ) ) ) . "f", $decimal );
232  // Then remove any trailing 0's
233  return preg_replace( '/\.?0*$/', '', $percent );
234  }
235 
242  private function getExtensionList( $mime ) {
243  $exts = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer()
244  ->getExtensionsForType( $mime );
245  if ( $exts === null ) {
246  return '';
247  }
248  $extArray = explode( ' ', $exts );
249  $extArray = array_unique( $extArray );
250  foreach ( $extArray as &$ext ) {
251  $ext = htmlspecialchars( '.' . $ext );
252  }
253 
254  return $this->getLanguage()->commaList( $extArray );
255  }
256 
263  protected function outputTableStart( $mediaType ) {
264  $out = $this->getOutput();
265  $out->addModuleStyles( 'jquery.tablesorter.styles' );
266  $out->addModules( 'jquery.tablesorter' );
267  $out->addHTML(
269  'table',
270  [ 'class' => [
271  'mw-mediastats-table',
272  'mw-mediastats-table-' . strtolower( $mediaType ),
273  'sortable',
274  'wikitable'
275  ] ]
276  ) .
277  Html::rawElement( 'thead', [], $this->getTableHeaderRow() ) .
278  Html::openElement( 'tbody' )
279  );
280  }
281 
287  protected function getTableHeaderRow() {
288  $headers = [ 'mimetype', 'extensions', 'count', 'totalbytes' ];
289  $ths = '';
290  foreach ( $headers as $header ) {
291  $ths .= Html::rawElement(
292  'th',
293  [],
294  // for grep:
295  // mediastatistics-table-mimetype, mediastatistics-table-extensions
296  // tatistics-table-count, mediastatistics-table-totalbytes
297  $this->msg( 'mediastatistics-table-' . $header )->parse()
298  );
299  }
300  return Html::rawElement( 'tr', [], $ths );
301  }
302 
308  protected function outputMediaType( $mediaType ) {
309  $this->getOutput()->addHTML(
311  'h2',
312  [ 'class' => [
313  'mw-mediastats-mediatype',
314  'mw-mediastats-mediatype-' . strtolower( $mediaType )
315  ] ],
316  // for grep
317  // mediastatistics-header-unknown, mediastatistics-header-bitmap,
318  // mediastatistics-header-drawing, mediastatistics-header-audio,
319  // mediastatistics-header-video, mediastatistics-header-multimedia,
320  // mediastatistics-header-office, mediastatistics-header-text,
321  // mediastatistics-header-executable, mediastatistics-header-archive,
322  // mediastatistics-header-3d,
323  $this->msg( 'mediastatistics-header-' . strtolower( $mediaType ) )->text()
324  )
325  );
329  }
330 
337  private function splitFakeTitle( $fakeTitle ) {
338  return explode( ';', $fakeTitle, 4 );
339  }
340 
345  protected function getGroupName() {
346  return 'media';
347  }
348 
358  public function formatResult( $skin, $result ) {
359  throw new MWException( "unimplemented" );
360  }
361 
368  public function preprocessResults( $dbr, $res ) {
370  $this->totalCount = $this->totalBytes = 0;
371  foreach ( $res as $row ) {
372  $mediaStats = $this->splitFakeTitle( $row->title );
373  $this->totalCount += $mediaStats[2] ?? 0;
374  $this->totalBytes += $mediaStats[3] ?? 0;
375  }
376  $res->seek( 0 );
377  }
378 }
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:231
getTableHeaderRow()
Get (not output) the header row for the table.
outputResults( $out, $skin, $dbr, $res, $num, $offset)
Output the results of the query.
getExtensionList( $mime)
Given a mime type, return a comma separated list of allowed extensions.
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing &#39;/&#39;...
Definition: Html.php:251
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:209
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
outputTableRow( $mime, $count, $bytes)
Output a row of the stats table.
getOutput()
Get the OutputPage being used for this instance.
static getInstance()
Returns the global default instance of the top level service locator.
getOrderFields()
How to sort the results.
This is a class for doing query pages; since they&#39;re almost all the same, we factor out some of the f...
Definition: QueryPage.php:36
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
const NS_MEDIA
Definition: Defines.php:48
static closeElement( $element)
Returns "</$element>".
Definition: Html.php:315
int $offset
The offset and limit in use, as passed to the query() function.
Definition: QueryPage.php:41
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don&#39;t need a full Title object...
Definition: SpecialPage.php:83
$header
__construct( $name='MediaStatistics')
outputMediaType( $mediaType)
Output a header for a new media type section.
splitFakeTitle( $fakeTitle)
parse the fake title format that this special page abuses querycache with.
outputTableStart( $mediaType)
Output the start of the table.
if(!is_readable( $file)) $ext
Definition: router.php:48
getLanguage()
Shortcut to get user&#39;s language.
preprocessResults( $dbr, $res)
Initialize total values so we can figure out percentages later.
const DB_REPLICA
Definition: defines.php:25
executeLBFromResultWrapper(IResultWrapper $res, $ns=null)
Creates a new LinkBatch object, adds all pages from the passed result wrapper (MUST include title and...
Definition: QueryPage.php:800
getGroupName()
What group to put the page in.
formatResult( $skin, $result)
This method isn&#39;t used, since we override outputResults, but we need to implement since abstract in p...
MediaWiki Linker LinkRenderer null $linkRenderer
Definition: SpecialPage.php:67