[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Implements Special:MediaStatistics 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 * @ingroup SpecialPage 22 * @author Brian Wolff 23 */ 24 25 /** 26 * @ingroup SpecialPage 27 */ 28 class MediaStatisticsPage extends QueryPage { 29 protected $totalCount = 0, $totalBytes = 0; 30 31 function __construct( $name = 'MediaStatistics' ) { 32 parent::__construct( $name ); 33 // Generally speaking there is only a small number of file types, 34 // so just show all of them. 35 $this->limit = 5000; 36 $this->shownavigation = false; 37 } 38 39 function isExpensive() { 40 return true; 41 } 42 43 /** 44 * Query to do. 45 * 46 * This abuses the query cache table by storing mime types as "titles". 47 * 48 * This will store entries like [[Media:BITMAP;image/jpeg;200;20000]] 49 * where the form is Media type;mime type;count;bytes. 50 * 51 * This relies on the behaviour that when value is tied, the order things 52 * come out of querycache table is the order they went in. Which is hacky. 53 * However, other special pages like Special:Deadendpages and 54 * Special:BrokenRedirects also rely on this. 55 */ 56 public function getQueryInfo() { 57 $dbr = wfGetDB( DB_SLAVE ); 58 $fakeTitle = $dbr->buildConcat( array( 59 'img_media_type', 60 $dbr->addQuotes( ';' ), 61 'img_major_mime', 62 $dbr->addQuotes( '/' ), 63 'img_minor_mime', 64 $dbr->addQuotes( ';' ), 65 'COUNT(*)', 66 $dbr->addQuotes( ';' ), 67 'SUM( img_size )' 68 ) ); 69 return array( 70 'tables' => array( 'image' ), 71 'fields' => array( 72 'title' => $fakeTitle, 73 'namespace' => NS_MEDIA, /* needs to be something */ 74 'value' => '1' 75 ), 76 'options' => array( 77 'GROUP BY' => array( 78 'img_media_type', 79 'img_major_mime', 80 'img_minor_mime', 81 ) 82 ) 83 ); 84 } 85 86 /** 87 * How to sort the results 88 * 89 * It's important that img_media_type come first, otherwise the 90 * tables will be fragmented. 91 * @return Array Fields to sort by 92 */ 93 function getOrderFields() { 94 return array( 'img_media_type', 'count(*)', 'img_major_mime', 'img_minor_mime' ); 95 } 96 97 /** 98 * Output the results of the query. 99 * 100 * @param $out OutputPage 101 * @param $skin Skin (deprecated presumably) 102 * @param $dbr DatabaseBase 103 * @param $res ResultWrapper Results from query 104 * @param $num integer Number of results 105 * @param $offset integer Paging offset (Should always be 0 in our case) 106 */ 107 protected function outputResults( $out, $skin, $dbr, $res, $num, $offset ) { 108 $prevMediaType = null; 109 foreach ( $res as $row ) { 110 list( $mediaType, $mime, $totalCount, $totalBytes ) = $this->splitFakeTitle( $row->title ); 111 if ( $prevMediaType !== $mediaType ) { 112 if ( $prevMediaType !== null ) { 113 // We're not at beginning, so we have to 114 // close the previous table. 115 $this->outputTableEnd(); 116 } 117 $this->outputMediaType( $mediaType ); 118 $this->outputTableStart( $mediaType ); 119 $prevMediaType = $mediaType; 120 } 121 $this->outputTableRow( $mime, intval( $totalCount ), intval( $totalBytes ) ); 122 } 123 if ( $prevMediaType !== null ) { 124 $this->outputTableEnd(); 125 } 126 } 127 128 /** 129 * Output closing </table> 130 */ 131 protected function outputTableEnd() { 132 $this->getOutput()->addHtml( Html::closeElement( 'table' ) ); 133 } 134 135 /** 136 * Output a row of the stats table 137 * 138 * @param $mime String mime type (e.g. image/jpeg) 139 * @param $count integer Number of images of this type 140 * @param $totalBytes integer Total space for images of this type 141 */ 142 protected function outputTableRow( $mime, $count, $bytes ) { 143 $mimeSearch = SpecialPage::getTitleFor( 'MIMEsearch', $mime ); 144 $row = Html::rawElement( 145 'td', 146 array(), 147 Linker::link( $mimeSearch, htmlspecialchars( $mime ) ) 148 ); 149 $row .= Html::element( 150 'td', 151 array(), 152 $this->getExtensionList( $mime ) 153 ); 154 $row .= Html::rawElement( 155 'td', 156 array(), 157 $this->msg( 'mediastatistics-nfiles' ) 158 ->numParams( $count ) 159 /** @todo Check to be sure this really should have number formatting */ 160 ->numParams( $this->makePercentPretty( $count / $this->totalCount ) ) 161 ->parse() 162 ); 163 $row .= Html::rawElement( 164 'td', 165 // Make sure js sorts it in numeric order 166 array( 'data-sort-value' => $bytes ), 167 $this->msg( 'mediastatistics-nbytes' ) 168 ->numParams( $bytes ) 169 ->sizeParams( $bytes ) 170 /** @todo Check to be sure this really should have number formatting */ 171 ->numParams( $this->makePercentPretty( $bytes / $this->totalBytes ) ) 172 ->parse() 173 ); 174 175 $this->getOutput()->addHTML( Html::rawElement( 'tr', array(), $row ) ); 176 } 177 178 /** 179 * @param float $decimal A decimal percentage (ie for 12.3%, this would be 0.123) 180 * @return String The percentage formatted so that 3 significant digits are shown. 181 */ 182 protected function makePercentPretty( $decimal ) { 183 $decimal *= 100; 184 // Always show three useful digits 185 if ( $decimal == 0 ) { 186 return '0'; 187 } 188 $percent = sprintf( "%." . max( 0, 2 - floor( log10( $decimal ) ) ) . "f", $decimal ); 189 // Then remove any trailing 0's 190 return preg_replace( '/\.?0*$/', '', $percent ); 191 } 192 193 /** 194 * Given a mime type, return a comma separated list of allowed extensions. 195 * 196 * @param $mime String mime type 197 * @return String Comma separated list of allowed extensions (e.g. ".ogg, .oga") 198 */ 199 private function getExtensionList( $mime ) { 200 $exts = MimeMagic::singleton()->getExtensionsForType( $mime ); 201 if ( $exts === null ) { 202 return ''; 203 } 204 $extArray = explode( ' ', $exts ); 205 $extArray = array_unique( $extArray ); 206 foreach ( $extArray as &$ext ) { 207 $ext = '.' . $ext; 208 } 209 210 return $this->getLanguage()->commaList( $extArray ); 211 } 212 213 /** 214 * Output the start of the table 215 * 216 * Including opening <table>, and first <tr> with column headers. 217 */ 218 protected function outputTableStart( $mediaType ) { 219 $this->getOutput()->addHTML( 220 Html::openElement( 221 'table', 222 array( 'class' => array( 223 'mw-mediastats-table', 224 'mw-mediastats-table-' . strtolower( $mediaType ), 225 'sortable', 226 'wikitable' 227 )) 228 ) 229 ); 230 $this->getOutput()->addHTML( $this->getTableHeaderRow() ); 231 } 232 233 /** 234 * Get (not output) the header row for the table 235 * 236 * @return String the header row of the able 237 */ 238 protected function getTableHeaderRow() { 239 $headers = array( 'mimetype', 'extensions', 'count', 'totalbytes' ); 240 $ths = ''; 241 foreach ( $headers as $header ) { 242 $ths .= Html::rawElement( 243 'th', 244 array(), 245 // for grep: 246 // mediastatistics-table-mimetype, mediastatistics-table-extensions 247 // tatistics-table-count, mediastatistics-table-totalbytes 248 $this->msg( 'mediastatistics-table-' . $header )->parse() 249 ); 250 } 251 return Html::rawElement( 'tr', array(), $ths ); 252 } 253 254 /** 255 * Output a header for a new media type section 256 * 257 * @param $mediaType string A media type (e.g. from the MEDIATYPE_xxx constants) 258 */ 259 protected function outputMediaType( $mediaType ) { 260 $this->getOutput()->addHTML( 261 Html::element( 262 'h2', 263 array( 'class' => array( 264 'mw-mediastats-mediatype', 265 'mw-mediastats-mediatype-' . strtolower( $mediaType ) 266 )), 267 // for grep 268 // mediastatistics-header-unknown, mediastatistics-header-bitmap, 269 // mediastatistics-header-drawing, mediastatistics-header-audio, 270 // mediastatistics-header-video, mediastatistics-header-multimedia, 271 // mediastatistics-header-office, mediastatistics-header-text, 272 // mediastatistics-header-executable, mediastatistics-header-archive, 273 $this->msg( 'mediastatistics-header-' . strtolower( $mediaType ) )->text() 274 ) 275 ); 276 /** @todo Possibly could add a message here explaining what the different types are. 277 * not sure if it is needed though. 278 */ 279 } 280 281 /** 282 * parse the fake title format that this special page abuses querycache with. 283 * 284 * @param $fakeTitle String A string formatted as <media type>;<mime type>;<count>;<bytes> 285 * @return Array The constituant parts of $fakeTitle 286 */ 287 private function splitFakeTitle( $fakeTitle ) { 288 return explode( ';', $fakeTitle, 4 ); 289 } 290 291 /** 292 * What group to put the page in 293 * @return string 294 */ 295 protected function getGroupName() { 296 return 'media'; 297 } 298 299 /** 300 * This method isn't used, since we override outputResults, but 301 * we need to implement since abstract in parent class. 302 * 303 * @param $skin Skin 304 * @param $result stdObject Result row 305 */ 306 public function formatResult( $skin, $result ) { 307 throw new MWException( "unimplemented" ); 308 } 309 310 /** 311 * Initialize total values so we can figure out percentages later. 312 * 313 * @param $dbr DatabaseBase 314 * @param $res ResultWrapper 315 */ 316 public function preprocessResults( $dbr, $res ) { 317 $this->totalCount = $this->totalBytes = 0; 318 foreach ( $res as $row ) { 319 list( , , $count, $bytes ) = $this->splitFakeTitle( $row->title ); 320 $this->totalCount += $count; 321 $this->totalBytes += $bytes; 322 } 323 $res->seek( 0 ); 324 } 325 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |