wikimedia /
mediawiki
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * Show profiling data. |
||
| 4 | * |
||
| 5 | * Copyright 2005 Kate Turner. |
||
| 6 | * |
||
| 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
||
| 8 | * of this software and associated documentation files (the "Software"), to deal |
||
| 9 | * in the Software without restriction, including without limitation the rights |
||
| 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||
| 11 | * copies of the Software, and to permit persons to whom the Software is |
||
| 12 | * furnished to do so, subject to the following conditions: |
||
| 13 | * |
||
| 14 | * The above copyright notice and this permission notice shall be included in |
||
| 15 | * all copies or substantial portions of the Software. |
||
| 16 | * |
||
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
| 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
| 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||
| 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||
| 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||
| 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||
| 23 | * SOFTWARE. |
||
| 24 | * |
||
| 25 | * @file |
||
| 26 | */ |
||
| 27 | |||
| 28 | // This endpoint is supposed to be independent of request cookies and other |
||
| 29 | // details of the session. Log warnings for violations of the no-session |
||
| 30 | // constraint. |
||
| 31 | define( 'MW_NO_SESSION', 'warn' ); |
||
| 32 | |||
| 33 | ini_set( 'zlib.output_compression', 'off' ); |
||
| 34 | |||
| 35 | $wgEnableProfileInfo = false; |
||
| 36 | require __DIR__ . '/includes/WebStart.php'; |
||
| 37 | |||
| 38 | header( 'Content-Type: text/html; charset=utf-8' ); |
||
| 39 | |||
| 40 | ?> |
||
| 41 | <!DOCTYPE html> |
||
| 42 | <html> |
||
| 43 | <head> |
||
| 44 | <meta charset="UTF-8" /> |
||
| 45 | <title>Profiling data</title> |
||
| 46 | <style> |
||
| 47 | /* noc.wikimedia.org/base.css */ |
||
| 48 | |||
| 49 | * { |
||
| 50 | margin: 0; |
||
| 51 | padding: 0; |
||
| 52 | } |
||
| 53 | |||
| 54 | body { |
||
| 55 | padding: 0.5em 1em; |
||
| 56 | background: #fff; |
||
| 57 | font: 14px/1.6 sans-serif; |
||
| 58 | color: #333; |
||
| 59 | } |
||
| 60 | |||
| 61 | p, ul, ol, table { |
||
| 62 | margin: 0.5em 0; |
||
| 63 | } |
||
| 64 | |||
| 65 | a { |
||
| 66 | color: #0645AD; |
||
| 67 | text-decoration: none; |
||
| 68 | } |
||
| 69 | |||
| 70 | a:hover { |
||
| 71 | text-decoration: underline; |
||
| 72 | } |
||
| 73 | |||
| 74 | /*! |
||
| 75 | * Bootstrap v2.1.1 |
||
| 76 | * |
||
| 77 | * Copyright 2012 Twitter, Inc |
||
| 78 | * Licensed under the Apache License v2.0 |
||
| 79 | * http://www.apache.org/licenses/LICENSE-2.0 |
||
| 80 | * |
||
| 81 | * Designed and built with all the love in the world @twitter by @mdo and @fat. |
||
| 82 | */ |
||
| 83 | |||
| 84 | table { |
||
| 85 | max-width: 100%; |
||
| 86 | background-color: transparent; |
||
| 87 | border-collapse: collapse; |
||
| 88 | border-spacing: 0; |
||
| 89 | } |
||
| 90 | |||
| 91 | .table { |
||
| 92 | width: 100%; |
||
| 93 | margin-bottom: 20px; |
||
| 94 | } |
||
| 95 | |||
| 96 | .table th, |
||
| 97 | .table td { |
||
| 98 | padding: 0.1em; |
||
| 99 | text-align: left; |
||
| 100 | vertical-align: top; |
||
| 101 | border-top: 1px solid #ddd; |
||
| 102 | } |
||
| 103 | |||
| 104 | .table th { |
||
| 105 | font-weight: bold; |
||
| 106 | } |
||
| 107 | |||
| 108 | .table thead th { |
||
| 109 | vertical-align: bottom; |
||
| 110 | } |
||
| 111 | |||
| 112 | .table thead:first-child tr:first-child th, |
||
| 113 | .table thead:first-child tr:first-child td { |
||
| 114 | border-top: 0; |
||
| 115 | } |
||
| 116 | |||
| 117 | .table tbody + tbody { |
||
| 118 | border-top: 2px solid #ddd; |
||
| 119 | } |
||
| 120 | |||
| 121 | .table-condensed th, |
||
| 122 | .table-condensed td { |
||
| 123 | padding: 4px 5px; |
||
| 124 | } |
||
| 125 | |||
| 126 | .table-striped tbody tr:nth-child(odd) td, |
||
| 127 | .table-striped tbody tr:nth-child(odd) th { |
||
| 128 | background-color: #f9f9f9; |
||
| 129 | } |
||
| 130 | |||
| 131 | .table-hover tbody tr:hover td, |
||
| 132 | .table-hover tbody tr:hover th { |
||
| 133 | background-color: #f5f5f5; |
||
| 134 | } |
||
| 135 | |||
| 136 | hr { |
||
| 137 | margin: 20px 0; |
||
| 138 | border: 0; |
||
| 139 | border-top: 1px solid #eee; |
||
| 140 | border-bottom: 1px solid #fff; |
||
| 141 | } |
||
| 142 | </style> |
||
| 143 | </head> |
||
| 144 | <body> |
||
| 145 | <?php |
||
| 146 | |||
| 147 | if ( !$wgEnableProfileInfo ) { |
||
| 148 | echo '<p>Disabled</p>' |
||
| 149 | . '</body></html>'; |
||
| 150 | exit( 1 ); |
||
| 151 | } |
||
| 152 | |||
| 153 | $dbr = wfGetDB( DB_SLAVE ); |
||
| 154 | |||
| 155 | if ( !$dbr->tableExists( 'profiling' ) ) { |
||
| 156 | echo '<p>No <code>profiling</code> table exists, so we can\'t show you anything.</p>' |
||
| 157 | . '<p>If you want to log profiling data, enable <code>$wgProfiler[\'output\'] = \'db\'</code>' |
||
| 158 | . ' in your StartProfiler.php and run <code>maintenance/update.php</code> to' |
||
| 159 | . ' create the profiling table.' |
||
| 160 | . '</body></html>'; |
||
| 161 | exit( 1 ); |
||
| 162 | } |
||
| 163 | |||
| 164 | $expand = []; |
||
| 165 | if ( isset( $_REQUEST['expand'] ) ) { |
||
| 166 | foreach ( explode( ',', $_REQUEST['expand'] ) as $f ) { |
||
| 167 | $expand[$f] = true; |
||
| 168 | } |
||
| 169 | } |
||
| 170 | |||
| 171 | // @codingStandardsIgnoreStart |
||
| 172 | class profile_point { |
||
| 173 | // @codingStandardsIgnoreEnd |
||
| 174 | |||
| 175 | public $name; |
||
| 176 | public $count; |
||
| 177 | public $time; |
||
| 178 | public $children; |
||
| 179 | |||
| 180 | public static $totaltime, $totalmemory, $totalcount; |
||
|
0 ignored issues
–
show
|
|||
| 181 | |||
| 182 | public function __construct( $name, $count, $time, $memory ) { |
||
| 183 | $this->name = $name; |
||
| 184 | $this->count = $count; |
||
| 185 | $this->time = $time; |
||
| 186 | $this->memory = $memory; |
||
| 187 | $this->children = []; |
||
| 188 | } |
||
| 189 | |||
| 190 | public function add_child( $child ) { |
||
| 191 | $this->children[] = $child; |
||
| 192 | } |
||
| 193 | |||
| 194 | public function display( $expand, $indent = 0.0 ) { |
||
| 195 | usort( $this->children, 'compare_point' ); |
||
| 196 | |||
| 197 | $ex = isset( $expand[$this->name()] ); |
||
| 198 | |||
| 199 | $anchor = str_replace( '"', '', $this->name() ); |
||
| 200 | |||
| 201 | if ( !$ex ) { |
||
| 202 | if ( count( $this->children ) ) { |
||
| 203 | $url = getEscapedProfileUrl( false, false, $expand + [ $this->name() => true ] ); |
||
| 204 | $extet = " <a id=\"{$anchor}\" href=\"{$url}#{$anchor}\">[+]</a>"; |
||
| 205 | } else { |
||
| 206 | $extet = ''; |
||
| 207 | } |
||
| 208 | } else { |
||
| 209 | $e = []; |
||
| 210 | foreach ( $expand as $name => $ep ) { |
||
| 211 | if ( $name != $this->name() ) { |
||
| 212 | $e += [ $name => $ep ]; |
||
| 213 | } |
||
| 214 | } |
||
| 215 | $url = getEscapedProfileUrl( false, false, $e ); |
||
| 216 | $extet = " <a id=\"{$anchor}\" href=\"{$url}#{$anchor}\">[–]</a>"; |
||
| 217 | } |
||
| 218 | ?> |
||
| 219 | <tr> |
||
| 220 | <th> |
||
| 221 | <div style="margin-left: <?php echo (int)$indent; ?>em;"> |
||
| 222 | <?php echo htmlspecialchars( str_replace( ',', ', ', $this->name() ) ) . $extet ?> |
||
| 223 | </div> |
||
| 224 | </th> |
||
| 225 | <?php //@codingStandardsIgnoreStart ?> |
||
| 226 | <td class="mw-profileinfo-timep"><?php echo @wfPercent( $this->time() / self::$totaltime * 100 ); ?></td> |
||
| 227 | <td class="mw-profileinfo-memoryp"><?php echo @wfPercent( $this->memory() / self::$totalmemory * 100 ); ?></td> |
||
| 228 | <td class="mw-profileinfo-count"><?php echo $this->count(); ?></td> |
||
| 229 | <td class="mw-profileinfo-cpr"><?php echo round( sprintf( '%.2f', $this->callsPerRequest() ), 2 ); ?></td> |
||
| 230 | <td class="mw-profileinfo-tpc"><?php echo round( sprintf( '%.2f', $this->timePerCall() ), 2 ); ?></td> |
||
| 231 | <td class="mw-profileinfo-mpc"><?php echo round( sprintf( '%.2f', $this->memoryPerCall() / 1024 ), 2 ); ?></td> |
||
| 232 | <td class="mw-profileinfo-tpr"><?php echo @round( sprintf( '%.2f', $this->time() / self::$totalcount ), 2 ); ?></td> |
||
| 233 | <td class="mw-profileinfo-mpr"><?php echo @round( sprintf( '%.2f', $this->memory() / self::$totalcount / 1024 ), 2 ); ?></td> |
||
| 234 | <?php //@codingStandardsIgnoreEnd ?> |
||
| 235 | </tr> |
||
| 236 | <?php |
||
| 237 | if ( $ex ) { |
||
| 238 | foreach ( $this->children as $child ) { |
||
| 239 | $child->display( $expand, $indent + 2 ); |
||
| 240 | } |
||
| 241 | } |
||
| 242 | } |
||
| 243 | |||
| 244 | public function name() { |
||
| 245 | return $this->name; |
||
| 246 | } |
||
| 247 | |||
| 248 | public function count() { |
||
| 249 | return $this->count; |
||
| 250 | } |
||
| 251 | |||
| 252 | public function time() { |
||
| 253 | return $this->time; |
||
| 254 | } |
||
| 255 | |||
| 256 | public function memory() { |
||
| 257 | return $this->memory; |
||
| 258 | } |
||
| 259 | |||
| 260 | public function timePerCall() { |
||
| 261 | // @codingStandardsIgnoreStart |
||
| 262 | return @( $this->time / $this->count ); |
||
| 263 | // @codingStandardsIgnoreEnd |
||
| 264 | } |
||
| 265 | |||
| 266 | public function memoryPerCall() { |
||
| 267 | // @codingStandardsIgnoreStart |
||
| 268 | return @( $this->memory / $this->count ); |
||
| 269 | // @codingStandardsIgnoreEnd |
||
| 270 | } |
||
| 271 | |||
| 272 | public function callsPerRequest() { |
||
| 273 | // @codingStandardsIgnoreStart |
||
| 274 | return @( $this->count / self::$totalcount ); |
||
| 275 | // @codingStandardsIgnoreEnd |
||
| 276 | } |
||
| 277 | |||
| 278 | public function timePerRequest() { |
||
| 279 | // @codingStandardsIgnoreStart |
||
| 280 | return @( $this->time / self::$totalcount ); |
||
| 281 | // @codingStandardsIgnoreEnd |
||
| 282 | } |
||
| 283 | |||
| 284 | public function memoryPerRequest() { |
||
| 285 | // @codingStandardsIgnoreStart |
||
| 286 | return @( $this->memory / self::$totalcount ); |
||
| 287 | // @codingStandardsIgnoreEnd |
||
| 288 | } |
||
| 289 | |||
| 290 | public function fmttime() { |
||
| 291 | return sprintf( '%5.02f', $this->time ); |
||
| 292 | } |
||
| 293 | }; |
||
| 294 | |||
| 295 | function compare_point( profile_point $a, profile_point $b ) { |
||
| 296 | // @codingStandardsIgnoreStart |
||
| 297 | global $sort; |
||
| 298 | // @codingStandardsIgnoreEnd |
||
| 299 | switch ( $sort ) { |
||
| 300 | case 'name': |
||
| 301 | return strcmp( $a->name(), $b->name() ); |
||
| 302 | case 'time': |
||
| 303 | return $a->time() > $b->time() ? -1 : 1; |
||
| 304 | case 'memory': |
||
| 305 | return $a->memory() > $b->memory() ? -1 : 1; |
||
| 306 | case 'count': |
||
| 307 | return $a->count() > $b->count() ? -1 : 1; |
||
| 308 | case 'time_per_call': |
||
| 309 | return $a->timePerCall() > $b->timePerCall() ? -1 : 1; |
||
| 310 | case 'memory_per_call': |
||
| 311 | return $a->memoryPerCall() > $b->memoryPerCall() ? -1 : 1; |
||
| 312 | case 'calls_per_req': |
||
| 313 | return $a->callsPerRequest() > $b->callsPerRequest() ? -1 : 1; |
||
| 314 | case 'time_per_req': |
||
| 315 | return $a->timePerRequest() > $b->timePerRequest() ? -1 : 1; |
||
| 316 | case 'memory_per_req': |
||
| 317 | return $a->memoryPerRequest() > $b->memoryPerRequest() ? -1 : 1; |
||
| 318 | } |
||
| 319 | } |
||
| 320 | |||
| 321 | $sorts = [ 'time', 'memory', 'count', 'calls_per_req', 'name', |
||
| 322 | 'time_per_call', 'memory_per_call', 'time_per_req', 'memory_per_req' ]; |
||
| 323 | $sort = 'time'; |
||
| 324 | if ( isset( $_REQUEST['sort'] ) && in_array( $_REQUEST['sort'], $sorts ) ) { |
||
| 325 | $sort = $_REQUEST['sort']; |
||
| 326 | } |
||
| 327 | |||
| 328 | $res = $dbr->select( |
||
| 329 | 'profiling', |
||
| 330 | '*', |
||
| 331 | [], |
||
| 332 | 'profileinfo.php', |
||
| 333 | [ 'ORDER BY' => 'pf_name ASC' ] |
||
| 334 | ); |
||
| 335 | |||
| 336 | if ( isset( $_REQUEST['filter'] ) ) { |
||
| 337 | $filter = $_REQUEST['filter']; |
||
| 338 | } else { |
||
| 339 | $filter = ''; |
||
| 340 | } |
||
| 341 | |||
| 342 | ?> |
||
| 343 | <form method="get" action="profileinfo.php"> |
||
| 344 | <p> |
||
| 345 | <input type="text" name="filter" value="<?php echo htmlspecialchars( $filter ); ?>"> |
||
| 346 | <input type="hidden" name="sort" value="<?php echo htmlspecialchars( $sort ); ?>"> |
||
| 347 | <input type="hidden" name="expand" value="<?php |
||
| 348 | echo htmlspecialchars( implode( ",", array_keys( $expand ) ) ); |
||
| 349 | ?>"> |
||
| 350 | <input type="submit" value="Filter"> |
||
| 351 | </p> |
||
| 352 | </form> |
||
| 353 | |||
| 354 | <table class="mw-profileinfo-table table table-striped table-hover"> |
||
| 355 | <thead> |
||
| 356 | <tr> |
||
| 357 | <th><a href="<?php |
||
| 358 | echo getEscapedProfileUrl( false, 'name' ); |
||
| 359 | ?>">Name</a></th> |
||
| 360 | <th><a href="<?php |
||
| 361 | echo getEscapedProfileUrl( false, 'time' ); |
||
| 362 | ?>">Time (%)</a></th> |
||
| 363 | <th><a href="<?php |
||
| 364 | echo getEscapedProfileUrl( false, 'memory' ); |
||
| 365 | ?>">Memory (%)</a></th> |
||
| 366 | <th><a href="<?php |
||
| 367 | echo getEscapedProfileUrl( false, 'count' ); |
||
| 368 | ?>">Count</a></th> |
||
| 369 | <th><a href="<?php |
||
| 370 | echo getEscapedProfileUrl( false, 'calls_per_req' ); |
||
| 371 | ?>">Calls/req</a></th> |
||
| 372 | <th><a href="<?php |
||
| 373 | echo getEscapedProfileUrl( false, 'time_per_call' ); |
||
| 374 | ?>">ms/call</a></th> |
||
| 375 | <th><a href="<?php |
||
| 376 | echo getEscapedProfileUrl( false, 'memory_per_call' ); |
||
| 377 | ?>">kb/call</a></th> |
||
| 378 | <th><a href="<?php |
||
| 379 | echo getEscapedProfileUrl( false, 'time_per_req' ); |
||
| 380 | ?>">ms/req</a></th> |
||
| 381 | <th><a href="<?php |
||
| 382 | echo getEscapedProfileUrl( false, 'memory_per_req' ); |
||
| 383 | ?>">kb/req</a></th> |
||
| 384 | </tr> |
||
| 385 | </thead> |
||
| 386 | <tbody> |
||
| 387 | <?php |
||
| 388 | profile_point::$totaltime = 0.0; |
||
| 389 | profile_point::$totalcount = 0; |
||
| 390 | profile_point::$totalmemory = 0.0; |
||
| 391 | |||
| 392 | function getEscapedProfileUrl( $_filter = false, $_sort = false, $_expand = false ) { |
||
| 393 | // @codingStandardsIgnoreStart |
||
| 394 | global $filter, $sort, $expand; |
||
| 395 | // @codingStandardsIgnoreEnd |
||
| 396 | |||
| 397 | if ( $_expand === false ) { |
||
| 398 | $_expand = $expand; |
||
| 399 | } |
||
| 400 | |||
| 401 | return htmlspecialchars( |
||
| 402 | '?' . |
||
| 403 | wfArrayToCgi( [ |
||
| 404 | 'filter' => $_filter ? $_filter : $filter, |
||
| 405 | 'sort' => $_sort ? $_sort : $sort, |
||
| 406 | 'expand' => implode( ',', array_keys( $_expand ) ) |
||
| 407 | ] ) |
||
| 408 | ); |
||
| 409 | } |
||
| 410 | |||
| 411 | $points = []; |
||
| 412 | $queries = []; |
||
| 413 | $sqltotal = 0.0; |
||
| 414 | |||
| 415 | $last = false; |
||
| 416 | foreach ( $res as $o ) { |
||
| 417 | $next = new profile_point( $o->pf_name, $o->pf_count, $o->pf_time, $o->pf_memory ); |
||
| 418 | if ( $next->name() == '-total' || $next->name() == 'main()' ) { |
||
| 419 | profile_point::$totaltime = $next->time(); |
||
| 420 | profile_point::$totalcount = $next->count(); |
||
| 421 | profile_point::$totalmemory = $next->memory(); |
||
| 422 | } |
||
| 423 | if ( $last !== false ) { |
||
| 424 | if ( preg_match( '/^' . preg_quote( $last->name(), '/' ) . '/', $next->name() ) ) { |
||
| 425 | $last->add_child( $next ); |
||
| 426 | continue; |
||
| 427 | } |
||
| 428 | } |
||
| 429 | $last = $next; |
||
| 430 | if ( preg_match( '/^query: /', $next->name() ) || preg_match( '/^query-m: /', $next->name() ) ) { |
||
| 431 | $sqltotal += $next->time(); |
||
| 432 | $queries[] = $next; |
||
| 433 | } else { |
||
| 434 | $points[] = $next; |
||
| 435 | } |
||
| 436 | } |
||
| 437 | |||
| 438 | $s = new profile_point( 'SQL Queries', 0, $sqltotal, 0, 0 ); |
||
| 439 | foreach ( $queries as $q ) { |
||
| 440 | $s->add_child( $q ); |
||
| 441 | } |
||
| 442 | $points[] = $s; |
||
| 443 | |||
| 444 | // @codingStandardsIgnoreStart |
||
| 445 | @usort( $points, 'compare_point' ); |
||
| 446 | // @codingStandardsIgnoreEnd |
||
| 447 | |||
| 448 | foreach ( $points as $point ) { |
||
| 449 | if ( strlen( $filter ) && !strstr( $point->name(), $filter ) ) { |
||
| 450 | continue; |
||
| 451 | } |
||
| 452 | |||
| 453 | $point->display( $expand ); |
||
| 454 | } |
||
| 455 | ?> |
||
| 456 | </tbody> |
||
| 457 | </table> |
||
| 458 | <hr /> |
||
| 459 | <p>Total time: <code><?php printf( '%5.02f', profile_point::$totaltime ); ?></code></p> |
||
| 460 | |||
| 461 | <p>Total memory: <code><?php printf( '%5.02f', profile_point::$totalmemory / 1024 ); ?></code></p> |
||
| 462 | <hr /> |
||
| 463 | </body> |
||
| 464 | </html> |
||
| 465 |
Only declaring a single property per statement allows you to later on add doc comments more easily.
It is also recommended by PSR2, so it is a common style that many people expect.