limit = 5000; $this->shownavigation = false; } public function isExpensive() { return true; } /** * Query to do. * * This abuses the query cache table by storing mime types as "titles". * * This will store entries like [[Media:BITMAP;image/jpeg;200;20000]] * where the form is Media type;mime type;count;bytes. * * This relies on the behaviour that when value is tied, the order things * come out of querycache table is the order they went in. Which is hacky. * However, other special pages like Special:Deadendpages and * Special:BrokenRedirects also rely on this. * @return array */ public function getQueryInfo() { $dbr = wfGetDB( DB_REPLICA ); $fakeTitle = $dbr->buildConcat( [ 'img_media_type', $dbr->addQuotes( ';' ), 'img_major_mime', $dbr->addQuotes( '/' ), 'img_minor_mime', $dbr->addQuotes( ';' ), $dbr->buildStringCast( 'COUNT(*)' ), $dbr->addQuotes( ';' ), $dbr->buildStringCast( 'SUM( img_size )' ) ] ); return [ 'tables' => [ 'image' ], 'fields' => [ 'title' => $fakeTitle, 'namespace' => NS_MEDIA, /* needs to be something */ 'value' => '1' ], 'options' => [ 'GROUP BY' => [ 'img_media_type', 'img_major_mime', 'img_minor_mime', ] ] ]; } /** * How to sort the results * * It's important that img_media_type come first, otherwise the * tables will be fragmented. * @return array Fields to sort by */ protected function getOrderFields() { return [ 'img_media_type', 'count(*)', 'img_major_mime', 'img_minor_mime' ]; } /** * Output the results of the query. * * @param OutputPage $out * @param Skin $skin (deprecated presumably) * @param IDatabase $dbr * @param IResultWrapper $res Results from query * @param int $num Number of results * @param int $offset Paging offset (Should always be 0 in our case) */ protected function outputResults( $out, $skin, $dbr, $res, $num, $offset ) { $prevMediaType = null; foreach ( $res as $row ) { $mediaStats = $this->splitFakeTitle( $row->title ); if ( count( $mediaStats ) < 4 ) { continue; } list( $mediaType, $mime, $totalCount, $totalBytes ) = $mediaStats; if ( $prevMediaType !== $mediaType ) { if ( $prevMediaType !== null ) { // We're not at beginning, so we have to // close the previous table. $this->outputTableEnd(); } $this->outputMediaType( $mediaType ); $this->totalPerType = 0; $this->outputTableStart( $mediaType ); $prevMediaType = $mediaType; } $this->outputTableRow( $mime, intval( $totalCount ), intval( $totalBytes ) ); } if ( $prevMediaType !== null ) { $this->outputTableEnd(); // add total size of all files $this->outputMediaType( 'total' ); $this->getOutput()->addWikiTextAsInterface( $this->msg( 'mediastatistics-allbytes' ) ->numParams( $this->totalSize ) ->sizeParams( $this->totalSize ) ->text() ); } } /** * Output closing */ protected function outputTableEnd() { $this->getOutput()->addHTML( Html::closeElement( 'tbody' ) . Html::closeElement( 'table' ) ); $this->getOutput()->addWikiTextAsInterface( $this->msg( 'mediastatistics-bytespertype' ) ->numParams( $this->totalPerType ) ->sizeParams( $this->totalPerType ) ->numParams( $this->makePercentPretty( $this->totalPerType / $this->totalBytes ) ) ->text() ); $this->totalSize += $this->totalPerType; } /** * Output a row of the stats table * * @param string $mime mime type (e.g. image/jpeg) * @param int $count Number of images of this type * @param int $bytes Total space for images of this type */ protected function outputTableRow( $mime, $count, $bytes ) { $mimeSearch = SpecialPage::getTitleFor( 'MIMEsearch', $mime ); $linkRenderer = $this->getLinkRenderer(); $row = Html::rawElement( 'td', [], $linkRenderer->makeLink( $mimeSearch, $mime ) ); $row .= Html::rawElement( 'td', [], $this->getExtensionList( $mime ) ); $row .= Html::rawElement( 'td', // Make sure js sorts it in numeric order [ 'data-sort-value' => $count ], $this->msg( 'mediastatistics-nfiles' ) ->numParams( $count ) /** @todo Check to be sure this really should have number formatting */ ->numParams( $this->makePercentPretty( $count / $this->totalCount ) ) ->parse() ); $row .= Html::rawElement( 'td', // Make sure js sorts it in numeric order [ 'data-sort-value' => $bytes ], $this->msg( 'mediastatistics-nbytes' ) ->numParams( $bytes ) ->sizeParams( $bytes ) /** @todo Check to be sure this really should have number formatting */ ->numParams( $this->makePercentPretty( $bytes / $this->totalBytes ) ) ->parse() ); $this->totalPerType += $bytes; $this->getOutput()->addHTML( Html::rawElement( 'tr', [], $row ) ); } /** * @param float $decimal A decimal percentage (ie for 12.3%, this would be 0.123) * @return string The percentage formatted so that 3 significant digits are shown. */ protected function makePercentPretty( $decimal ) { $decimal *= 100; // Always show three useful digits if ( $decimal == 0 ) { return '0'; } if ( $decimal >= 100 ) { return '100'; } $percent = sprintf( "%." . max( 0, 2 - floor( log10( $decimal ) ) ) . "f", $decimal ); // Then remove any trailing 0's return preg_replace( '/\.?0*$/', '', $percent ); } /** * Given a mime type, return a comma separated list of allowed extensions. * * @param string $mime mime type * @return string Comma separated list of allowed extensions (e.g. ".ogg, .oga") */ private function getExtensionList( $mime ) { $exts = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer() ->getExtensionsFromMimeType( $mime ); if ( !$exts ) { return ''; } foreach ( $exts as &$ext ) { $ext = htmlspecialchars( '.' . $ext ); } return $this->getLanguage()->commaList( $exts ); } /** * Output the start of the table * * Including opening