Query Monitor - Version 2.6.3

Version Description

  • Clickable stack traces and file names if you've configured Xdebug's file_link_format setting
  • Show the number of times each PHP error has been triggered
  • Visual bugfixes when using Firefox
  • Fix a bug which was preventing AJAX debugging from being output
  • Fix a fatal error when using PHP 5.2 on Windows
  • Display HTTP proxy information when appropriate
  • Introduce the QM_DISABLE constant for unconditionally disabling Query Monitor
  • Always return true from our PHP error handler to suppress unwanted PHP error output (eg. from Xdebug)
  • Internals: Much more robust logic and even more separation of data collection and output
  • Internals: Many performance improvements
Download this release

Release Info

Developer johnbillion
Plugin Icon 128x128 Query Monitor
Version 2.6.3
Comparing to
See all releases

Code changes from version 2.6.2 to 2.6.3

Backtrace.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
@@ -54,8 +54,11 @@ class QM_Backtrace {
54
  protected static $filtered = false;
55
  protected $trace = null;
56
  protected $filtered_trace = null;
 
 
57
 
58
  public function __construct( array $args = array() ) {
 
59
  $args = array_merge( array(
60
  'ignore_current_filter' => true,
61
  'ignore_items' => 0,
@@ -73,17 +76,7 @@ class QM_Backtrace {
73
  public function get_stack() {
74
 
75
  $trace = $this->get_filtered_trace();
76
- $stack = array();
77
-
78
- if ( empty( $trace ) ) {
79
- if ( isset( $this->trace[0]['file'] ) ) {
80
- $stack[] = QM_Util::standard_dir( $this->trace[0]['file'], '' );
81
- } else {
82
- $stack[] = __( 'Unknown', 'query-monitor' );
83
- }
84
- } else {
85
- $stack = wp_list_pluck( $trace, 'display' );
86
- }
87
 
88
  return $stack;
89
 
@@ -93,11 +86,7 @@ class QM_Backtrace {
93
 
94
  $trace = $this->get_filtered_trace();
95
 
96
- if ( empty( $trace ) ) {
97
- return reset( $this->trace );
98
- } else {
99
- return reset( $trace );
100
- }
101
 
102
  }
103
 
@@ -112,9 +101,15 @@ class QM_Backtrace {
112
  if ( isset( $item['file'] ) ) {
113
  $file = $item['file'];
114
  } else if ( isset( $item['class'] ) ) {
 
 
 
 
115
  $ref = new ReflectionMethod( $item['class'], $item['function'] );
116
  $file = $ref->getFileName();
117
  } else {
 
 
118
  $ref = new ReflectionFunction( $item['function'] );
119
  $file = $ref->getFileName();
120
  }
@@ -143,9 +138,24 @@ class QM_Backtrace {
143
  public function get_filtered_trace() {
144
 
145
  if ( !isset( $this->filtered_trace ) ) {
146
- $trace = array_map( 'QM_Backtrace::filter_trace', $this->trace );
 
147
  $trace = array_values( array_filter( $trace ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  $this->filtered_trace = $trace;
 
149
  }
150
 
151
  return $this->filtered_trace;
@@ -168,7 +178,7 @@ class QM_Backtrace {
168
 
169
  }
170
 
171
- public static function filter_trace( array $trace ) {
172
 
173
  if ( !self::$filtered and function_exists( 'did_action' ) and did_action( 'plugins_loaded' ) ) {
174
 
@@ -181,55 +191,70 @@ class QM_Backtrace {
181
 
182
  }
183
 
 
 
184
  if ( isset( $trace['class'] ) ) {
185
 
186
  if ( isset( self::$ignore_class[$trace['class']] ) ) {
187
- return null;
188
  } else if ( isset( self::$ignore_method[$trace['class']][$trace['function']] ) ) {
189
- return null;
190
  } else if ( 0 === strpos( $trace['class'], 'QM_' ) ) {
191
- return null;
192
  } else {
193
- $trace['id'] = $trace['class'] . $trace['type'] . $trace['function'] . '()';
194
- $trace['display'] = $trace['class'] . $trace['type'] . $trace['function'] . '()';
195
- return $trace;
196
  }
197
 
198
  } else {
199
 
200
  if ( isset( self::$ignore_func[$trace['function']] ) ) {
201
 
202
- return null;
203
 
204
  } else if ( isset( self::$show_args[$trace['function']] ) ) {
205
 
206
  $show = self::$show_args[$trace['function']];
 
207
  if ( 'dir' === $show ) {
208
  if ( isset( $trace['args'][0] ) ) {
209
  $arg = QM_Util::standard_dir( $trace['args'][0], '&hellip;/' );
210
- $trace['id'] = $trace['function'] . '()';
211
- $trace['display'] = $trace['function'] . "('{$arg}')";
212
- return $trace;
213
  }
214
  } else {
215
  $args = array();
216
  for ( $i = 0; $i < $show; $i++ ) {
217
  if ( isset( $trace['args'][$i] ) )
218
- $args[] = sprintf( "'%s'", $trace['args'][$i] );
219
  }
220
- $trace['id'] = $trace['function'] . '()';
221
- $trace['display'] = $trace['function'] . '(' . implode( ',', $args ) . ')';
222
- return $trace;
223
  }
224
 
 
 
 
 
 
225
  }
226
 
227
- $trace['id'] = $trace['function'] . '()';
228
- $trace['display'] = $trace['function'] . '()';
229
- return $trace;
 
 
 
230
 
231
  }
232
 
 
 
 
 
 
 
 
233
  }
234
 
235
  }
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
54
  protected static $filtered = false;
55
  protected $trace = null;
56
  protected $filtered_trace = null;
57
+ protected $calling_line = 0;
58
+ protected $calling_file = '';
59
 
60
  public function __construct( array $args = array() ) {
61
+ # @TODO save the args as a property and process the trace JIT
62
  $args = array_merge( array(
63
  'ignore_current_filter' => true,
64
  'ignore_items' => 0,
76
  public function get_stack() {
77
 
78
  $trace = $this->get_filtered_trace();
79
+ $stack = wp_list_pluck( $trace, 'display' );
 
 
 
 
 
 
 
 
 
 
80
 
81
  return $stack;
82
 
86
 
87
  $trace = $this->get_filtered_trace();
88
 
89
+ return reset( $trace );
 
 
 
 
90
 
91
  }
92
 
101
  if ( isset( $item['file'] ) ) {
102
  $file = $item['file'];
103
  } else if ( isset( $item['class'] ) ) {
104
+ if ( !is_object( $item['class'] ) and !class_exists( $item['class'], false ) )
105
+ continue;
106
+ if ( !method_exists( $item['class'], $item['function'] ) )
107
+ continue;
108
  $ref = new ReflectionMethod( $item['class'], $item['function'] );
109
  $file = $ref->getFileName();
110
  } else {
111
+ if ( !function_exists( $item['function'] ) )
112
+ continue;
113
  $ref = new ReflectionFunction( $item['function'] );
114
  $file = $ref->getFileName();
115
  }
138
  public function get_filtered_trace() {
139
 
140
  if ( !isset( $this->filtered_trace ) ) {
141
+
142
+ $trace = array_map( array( $this, 'filter_trace' ), $this->trace );
143
  $trace = array_values( array_filter( $trace ) );
144
+
145
+ if ( empty( $trace ) ) {
146
+ $lowest = $this->trace[0];
147
+ $file = QM_Util::standard_dir( $lowest['file'], '' );
148
+ $lowest['calling_file'] = $lowest['file'];
149
+ $lowest['calling_line'] = $lowest['line'];
150
+ $lowest['function'] = $file;
151
+ $lowest['display'] = $file;
152
+ $lowest['id'] = $file;
153
+ unset( $lowest['class'], $lowest['args'], $lowest['type'] );
154
+ $trace[0] = $lowest;
155
+ }
156
+
157
  $this->filtered_trace = $trace;
158
+
159
  }
160
 
161
  return $this->filtered_trace;
178
 
179
  }
180
 
181
+ public function filter_trace( array $trace ) {
182
 
183
  if ( !self::$filtered and function_exists( 'did_action' ) and did_action( 'plugins_loaded' ) ) {
184
 
191
 
192
  }
193
 
194
+ $return = $trace;
195
+
196
  if ( isset( $trace['class'] ) ) {
197
 
198
  if ( isset( self::$ignore_class[$trace['class']] ) ) {
199
+ $return = null;
200
  } else if ( isset( self::$ignore_method[$trace['class']][$trace['function']] ) ) {
201
+ $return = null;
202
  } else if ( 0 === strpos( $trace['class'], 'QM_' ) ) {
203
+ $return = null;
204
  } else {
205
+ $return['id'] = $trace['class'] . $trace['type'] . $trace['function'] . '()';
206
+ $return['display'] = $trace['class'] . $trace['type'] . $trace['function'] . '()';
 
207
  }
208
 
209
  } else {
210
 
211
  if ( isset( self::$ignore_func[$trace['function']] ) ) {
212
 
213
+ $return = null;
214
 
215
  } else if ( isset( self::$show_args[$trace['function']] ) ) {
216
 
217
  $show = self::$show_args[$trace['function']];
218
+
219
  if ( 'dir' === $show ) {
220
  if ( isset( $trace['args'][0] ) ) {
221
  $arg = QM_Util::standard_dir( $trace['args'][0], '&hellip;/' );
222
+ $return['id'] = $trace['function'] . '()';
223
+ $return['display'] = $trace['function'] . "('{$arg}')";
 
224
  }
225
  } else {
226
  $args = array();
227
  for ( $i = 0; $i < $show; $i++ ) {
228
  if ( isset( $trace['args'][$i] ) )
229
+ $args[] = '\'' . $trace['args'][$i] . '\'';
230
  }
231
+ $return['id'] = $trace['function'] . '()';
232
+ $return['display'] = $trace['function'] . '(' . implode( ',', $args ) . ')';
 
233
  }
234
 
235
+ } else {
236
+
237
+ $return['id'] = $trace['function'] . '()';
238
+ $return['display'] = $trace['function'] . '()';
239
+
240
  }
241
 
242
+ }
243
+
244
+ if ( $return ) {
245
+
246
+ $return['calling_file'] = $this->calling_file;
247
+ $return['calling_line'] = $this->calling_line;
248
 
249
  }
250
 
251
+ if ( isset( $trace['line'] ) )
252
+ $this->calling_line = $trace['line'];
253
+ if ( isset( $trace['file'] ) )
254
+ $this->calling_file = $trace['file'];
255
+
256
+ return $return;
257
+
258
  }
259
 
260
  }
Collector.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
@@ -53,6 +53,18 @@ abstract class QM_Collector {
53
 
54
  }
55
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  final public function get_data() {
57
  return $this->data;
58
  }
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
53
 
54
  }
55
 
56
+ public static function timer_stop_float() {
57
+ global $timestart;
58
+ return microtime( true ) - $timestart;
59
+ }
60
+
61
+ public static function format_bool_constant( $constant ) {
62
+ if ( !defined( $constant ) or !constant( $constant ) )
63
+ return 'false';
64
+ else
65
+ return 'true';
66
+ }
67
+
68
  final public function get_data() {
69
  return $this->data;
70
  }
Dispatcher.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
@@ -40,9 +40,12 @@ abstract class QM_Dispatcher {
40
  public function output( QM_Collector $collector ) {
41
 
42
  $filter = 'query_monitor_output_' . $this->id . '_' . $collector->id;
43
-
44
  $output = apply_filters( $filter, null, $collector );
45
 
 
 
 
 
46
  if ( !is_a( $output, 'QM_Output' ) ) {
47
  $output = $this->get_outputter( $collector );
48
  }
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
40
  public function output( QM_Collector $collector ) {
41
 
42
  $filter = 'query_monitor_output_' . $this->id . '_' . $collector->id;
 
43
  $output = apply_filters( $filter, null, $collector );
44
 
45
+ if ( false === $output ) {
46
+ return;
47
+ }
48
+
49
  if ( !is_a( $output, 'QM_Output' ) ) {
50
  $output = $this->get_outputter( $collector );
51
  }
Output.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
Plugin.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
Util.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
@@ -22,11 +22,6 @@ class QM_Util {
22
 
23
  private function __construct() {}
24
 
25
- public static function timer_stop_float() {
26
- global $timestart;
27
- return microtime( true ) - $timestart;
28
- }
29
-
30
  public static function sort( $a, $b ) {
31
  if ( $a['ltime'] == $b['ltime'] )
32
  return 0;
@@ -59,8 +54,10 @@ class QM_Util {
59
  $dir = str_replace( '\\', '/', $dir );
60
  $dir = preg_replace( '|/+|', '/', $dir );
61
 
62
- if ( is_string( $abspath_replace ) )
 
63
  $dir = str_replace( self::standard_dir( ABSPATH ), $abspath_replace, $dir );
 
64
 
65
  return $dir;
66
 
@@ -176,6 +173,14 @@ class QM_Util {
176
  return false;
177
  }
178
 
 
 
 
 
 
 
 
 
179
  public static function wpv() {
180
  return 'qm-wp-' . ( floatval( $GLOBALS['wp_version'] ) * 10 );
181
  }
@@ -187,41 +192,8 @@ class QM_Util {
187
  return get_role( 'administrator' );
188
  }
189
 
190
- public static function format_sql( $sql ) {
191
-
192
- $sql = str_replace( array( "\r\n", "\r", "\n", "\t" ), ' ', $sql );
193
- $sql = esc_html( $sql );
194
- $sql = trim( $sql );
195
-
196
- foreach( array(
197
- 'ALTER', 'AND', 'COMMIT', 'CREATE', 'DESCRIBE', 'DELETE', 'DROP', 'ELSE', 'END', 'FROM', 'GROUP',
198
- 'HAVING', 'INNER', 'INSERT', 'LIMIT', 'ON', 'OR', 'ORDER', 'REPLACE', 'ROLLBACK', 'SELECT', 'SET',
199
- 'SHOW', 'START', 'THEN', 'TRUNCATE', 'UPDATE', 'VALUES', 'WHEN', 'WHERE'
200
- ) as $cmd )
201
- $sql = trim( str_replace( " $cmd ", "<br>$cmd ", $sql ) );
202
-
203
- return $sql;
204
-
205
- }
206
-
207
- public static function format_bool_constant( $constant ) {
208
- if ( !defined( $constant ) or !constant( $constant ) )
209
- return 'false';
210
- else
211
- return 'true';
212
- }
213
-
214
- public static function format_url( $url ) {
215
- $url = str_replace( array(
216
- '=',
217
- '&',
218
- '?',
219
- ), array(
220
- '<span class="qm-equals">=</span>',
221
- '<br><span class="qm-param">&amp;</span>',
222
- '<br><span class="qm-param">?</span>',
223
- ), $url );
224
- return $url;
225
  }
226
 
227
  }
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
22
 
23
  private function __construct() {}
24
 
 
 
 
 
 
25
  public static function sort( $a, $b ) {
26
  if ( $a['ltime'] == $b['ltime'] )
27
  return 0;
54
  $dir = str_replace( '\\', '/', $dir );
55
  $dir = preg_replace( '|/+|', '/', $dir );
56
 
57
+ if ( is_string( $abspath_replace ) ) {
58
+ # @TODO cache the value of self::standard_dir( ABSPATH )
59
  $dir = str_replace( self::standard_dir( ABSPATH ), $abspath_replace, $dir );
60
+ }
61
 
62
  return $dir;
63
 
173
  return false;
174
  }
175
 
176
+ public static function is_async() {
177
+ if ( self::is_ajax() )
178
+ return true;
179
+ if ( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) and 'xmlhttprequest' == strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) )
180
+ return true;
181
+ return false;
182
+ }
183
+
184
  public static function wpv() {
185
  return 'qm-wp-' . ( floatval( $GLOBALS['wp_version'] ) * 10 );
186
  }
192
  return get_role( 'administrator' );
193
  }
194
 
195
+ public static function get_current_url() {
196
+ return ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  }
198
 
199
  }
assets/query-monitor.css CHANGED
@@ -1,6 +1,6 @@
1
  /*
2
 
3
- Copyright 2013 John Blackbourn
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
@@ -14,7 +14,6 @@ GNU General Public License for more details.
14
 
15
  */
16
 
17
-
18
  #wpadminbar .quicklinks .menupop ul li.qm-true > a {
19
  color: #8c8 !important;
20
  }
@@ -190,7 +189,7 @@ body:not(.iframe).sticky-menu.folded #qm {
190
 
191
  #qm-wrapper {
192
  margin: 0 auto;
193
- max-width: 85em;
194
  }
195
 
196
  #qm-wrapper > p {
@@ -217,12 +216,11 @@ body:not(.iframe).sticky-menu.folded #qm {
217
  }
218
 
219
  .qm>table {
220
- border-collapse: collapse !important;
221
  color: #555 !important;
 
222
  border-style: hidden !important;
223
- box-shadow: 0 1px 2px 1px rgba(0,0,0,0.05) !important;
224
  width: 100% !important;
225
- outline: 1px solid #ddd !important;
226
  }
227
 
228
  .qm td,
@@ -268,10 +266,6 @@ body:not(.iframe).sticky-menu.folded #qm {
268
 
269
  .qm-inner td,
270
  .qm-inner th {
271
- text-align: left !important;
272
- font-family: Menlo, Monaco, Consolas, 'Courier New', monospace !important;
273
- font-size: 11px !important;
274
- line-height: 16px !important;
275
  border: none !important;
276
  padding: 1px 0 !important;
277
  }
@@ -286,6 +280,18 @@ body:not(.iframe).sticky-menu.folded #qm {
286
  margin-bottom: 2px !important;
287
  }
288
 
 
 
 
 
 
 
 
 
 
 
 
 
289
  .qm span.qm-true,
290
  .qm td.qm-true {
291
  color: #4a4 !important;
@@ -323,7 +329,7 @@ body:not(.iframe).sticky-menu.folded #qm {
323
  }
324
 
325
  .qm a {
326
- color: #0074a2 !important;
327
  text-decoration: none !important;
328
  text-shadow: none !important;
329
  font-weight: normal !important;
@@ -339,7 +345,7 @@ body:not(.iframe).sticky-menu.folded #qm {
339
  }
340
 
341
  .qm a.qm-toggle {
342
- color: #ddd !important;
343
  padding: 0 3px !important;
344
  border: 1px solid transparent !important;
345
  }
@@ -367,7 +373,7 @@ body:not(.iframe).sticky-menu.folded #qm {
367
 
368
  .qm td.qm-var {
369
  text-align: right !important;
370
- padding: 1px 1.5em 1px 0 !important;
371
  }
372
 
373
  /* Filters */
1
  /*
2
 
3
+ Copyright 2014 John Blackbourn
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
14
 
15
  */
16
 
 
17
  #wpadminbar .quicklinks .menupop ul li.qm-true > a {
18
  color: #8c8 !important;
19
  }
189
 
190
  #qm-wrapper {
191
  margin: 0 auto;
192
+ max-width: 100em;
193
  }
194
 
195
  #qm-wrapper > p {
216
  }
217
 
218
  .qm>table {
 
219
  color: #555 !important;
220
+ border-collapse: collapse !important;
221
  border-style: hidden !important;
222
+ box-shadow: 0 0 0 1px #ddd, 0 1px 2px 1px rgba(0,0,0,0.05) !important;
223
  width: 100% !important;
 
224
  }
225
 
226
  .qm td,
266
 
267
  .qm-inner td,
268
  .qm-inner th {
 
 
 
 
269
  border: none !important;
270
  padding: 1px 0 !important;
271
  }
280
  margin-bottom: 2px !important;
281
  }
282
 
283
+ .qm code {
284
+ font-family: Menlo, Monaco, Consolas, 'Courier New', monospace !important;
285
+ font-size: 11px !important;
286
+ font-weight: normal !important;
287
+ font-style: normal !important;
288
+ line-height: 16px !important;
289
+ color: inherit !important;
290
+ background: #f3f3f3 !important;
291
+ padding: 3px 4px 2px !important;
292
+ margin: 0 !important;
293
+ }
294
+
295
  .qm span.qm-true,
296
  .qm td.qm-true {
297
  color: #4a4 !important;
329
  }
330
 
331
  .qm a {
332
+ color: #2ea2cc !important;
333
  text-decoration: none !important;
334
  text-shadow: none !important;
335
  font-weight: normal !important;
345
  }
346
 
347
  .qm a.qm-toggle {
348
+ color: #ccc !important;
349
  padding: 0 3px !important;
350
  border: 1px solid transparent !important;
351
  }
373
 
374
  .qm td.qm-var {
375
  text-align: right !important;
376
+ padding: 1px 1em 1px 0 !important;
377
  }
378
 
379
  /* Filters */
assets/query-monitor.js CHANGED
@@ -1,6 +1,6 @@
1
  /*
2
 
3
- Copyright 2013 John Blackbourn
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
1
  /*
2
 
3
+ Copyright 2014 John Blackbourn
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
collectors/admin.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
@@ -24,13 +24,6 @@ class QM_Collector_Admin extends QM_Collector {
24
 
25
  public function __construct() {
26
  parent::__construct();
27
- add_filter( 'current_screen', array( $this, 'filter_current_screen' ), 99 );
28
- }
29
-
30
- public function filter_current_screen( WP_Screen $screen ) {
31
- if ( empty( $this->data['admin'] ) )
32
- $this->data['admin'] = wp_clone( $screen );
33
- return $screen;
34
  }
35
 
36
  public function process() {
@@ -42,9 +35,6 @@ class QM_Collector_Admin extends QM_Collector {
42
  else
43
  $this->data['base'] = $pagenow;
44
 
45
- if ( !isset( $this->data['admin'] ) )
46
- $this->data['admin'] = __( 'n/a', 'query-monitor' );
47
-
48
  $this->data['pagenow'] = $pagenow;
49
  $this->data['current_screen'] = get_current_screen();
50
 
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
24
 
25
  public function __construct() {
26
  parent::__construct();
 
 
 
 
 
 
 
27
  }
28
 
29
  public function process() {
35
  else
36
  $this->data['base'] = $pagenow;
37
 
 
 
 
38
  $this->data['pagenow'] = $pagenow;
39
  $this->data['current_screen'] = get_current_screen();
40
 
collectors/authentication.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
@@ -34,7 +34,7 @@ class QM_Collector_Authentication extends QM_Collector {
34
 
35
  }
36
 
37
- public function show_query_monitor() {
38
  if ( isset( $_COOKIE[QM_COOKIE] ) )
39
  return $this->verify_nonce( $_COOKIE[QM_COOKIE], 'view_query_monitor' );
40
  return false;
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
34
 
35
  }
36
 
37
+ public function user_can_view() {
38
  if ( isset( $_COOKIE[QM_COOKIE] ) )
39
  return $this->verify_nonce( $_COOKIE[QM_COOKIE], 'view_query_monitor' );
40
  return false;
collectors/conditionals.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
collectors/db_callers.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
collectors/db_components.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
collectors/db_queries.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
@@ -149,8 +149,10 @@ class QM_Collector_DB_Queries extends QM_Collector {
149
  $stack = $query['stack'];
150
  $has_component = isset( $query['trace'] );
151
  $has_results = isset( $query['result'] );
 
 
152
 
153
- if ( $has_results )
154
  $result = $query['result'];
155
  else
156
  $result = null;
@@ -158,22 +160,24 @@ class QM_Collector_DB_Queries extends QM_Collector {
158
  $total_time += $ltime;
159
 
160
  if ( isset( $query['trace'] ) ) {
161
- $component = $query['trace']->get_component();
162
- $trace = $query['trace'];
 
 
 
 
 
163
  } else {
164
- $component = null;
165
- $trace = null;
166
- }
167
 
168
- # @TODO we should grab this from the trace instead for increased accuracy in case
169
- # the caller contains multiple comma separated arguments (see QM_Backtrace::$show_args)
170
- $callers = explode( ',', $stack );
171
- $caller = trim( end( $callers ) );
172
 
173
- if ( false !== strpos( $caller, '(' ) )
174
- $caller_name = substr( $caller, 0, strpos( $caller, '(' ) ) . '()';
175
- else
176
- $caller_name = $caller;
 
 
177
 
178
  $sql = trim( $sql );
179
  $type = preg_split( '/\b/', $sql );
@@ -195,7 +199,7 @@ class QM_Collector_DB_Queries extends QM_Collector {
195
  else
196
  $types[$type]['callers'][$caller]++;
197
 
198
- $row = compact( 'caller', 'caller_name', 'stack', 'sql', 'ltime', 'result', 'type', 'component' );
199
 
200
  if ( is_wp_error( $result ) )
201
  $this->data['errors'][] = $row;
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
149
  $stack = $query['stack'];
150
  $has_component = isset( $query['trace'] );
151
  $has_results = isset( $query['result'] );
152
+ $trace = null;
153
+ $component = null;
154
 
155
+ if ( isset( $query['result'] ) )
156
  $result = $query['result'];
157
  else
158
  $result = null;
160
  $total_time += $ltime;
161
 
162
  if ( isset( $query['trace'] ) ) {
163
+
164
+ $trace = $query['trace'];
165
+ $component = $query['trace']->get_component();
166
+ $caller = $query['trace']->get_caller();
167
+ $caller_name = $caller['id'];
168
+ $caller = $caller['display'];
169
+
170
  } else {
 
 
 
171
 
172
+ $callers = explode( ',', $stack );
173
+ $caller = trim( end( $callers ) );
 
 
174
 
175
+ if ( false !== strpos( $caller, '(' ) )
176
+ $caller_name = substr( $caller, 0, strpos( $caller, '(' ) ) . '()';
177
+ else
178
+ $caller_name = $caller;
179
+
180
+ }
181
 
182
  $sql = trim( $sql );
183
  $type = preg_split( '/\b/', $sql );
199
  else
200
  $types[$type]['callers'][$caller]++;
201
 
202
+ $row = compact( 'caller', 'caller_name', 'stack', 'sql', 'ltime', 'result', 'type', 'component', 'trace' );
203
 
204
  if ( is_wp_error( $result ) )
205
  $this->data['errors'][] = $row;
collectors/environment.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
@@ -164,8 +164,8 @@ class QM_Collector_Environment extends QM_Collector {
164
  # @TODO put WP's other debugging constants in here, eg. SCRIPT_DEBUG
165
  $this->data['wp'] = array(
166
  'version' => $wp_version,
167
- 'WP_DEBUG' => QM_Util::format_bool_constant( 'WP_DEBUG' ),
168
- 'WP_LOCAL_DEV' => QM_Util::format_bool_constant( 'WP_LOCAL_DEV' ),
169
  );
170
 
171
  if ( is_multisite() )
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
164
  # @TODO put WP's other debugging constants in here, eg. SCRIPT_DEBUG
165
  $this->data['wp'] = array(
166
  'version' => $wp_version,
167
+ 'WP_DEBUG' => self::format_bool_constant( 'WP_DEBUG' ),
168
+ 'WP_LOCAL_DEV' => self::format_bool_constant( 'WP_LOCAL_DEV' ),
169
  );
170
 
171
  if ( is_multisite() )
collectors/hooks.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
collectors/http.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
@@ -138,6 +138,13 @@ class QM_Collector_HTTP extends QM_Collector {
138
  $this->data['errors']['warning'][] = $key;
139
  }
140
 
 
 
 
 
 
 
 
141
  }
142
 
143
  }
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
138
  $this->data['errors']['warning'][] = $key;
139
  }
140
 
141
+ $http['ltime'] = ( $http['end'] - $http['start'] );
142
+
143
+ }
144
+
145
+ foreach ( array( 'WP_PROXY_HOST', 'WP_PROXY_PORT' ) as $var ) {
146
+ if ( defined( $var ) and constant( $var ) )
147
+ $this->data['vars'][$var] = constant( $var );
148
  }
149
 
150
  }
collectors/overview.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
@@ -28,7 +28,7 @@ class QM_Collector_Overview extends QM_Collector {
28
 
29
  public function process() {
30
 
31
- $this->data['time'] = QM_Util::timer_stop_float();
32
  $this->data['time_limit'] = ini_get( 'max_execution_time' );
33
 
34
  if ( !empty( $this->data['time_limit'] ) )
@@ -36,11 +36,7 @@ class QM_Collector_Overview extends QM_Collector {
36
  else
37
  $this->data['time_usage'] = 0;
38
 
39
- if ( function_exists( 'memory_get_peak_usage' ) )
40
- $this->data['memory'] = memory_get_peak_usage();
41
- else
42
- $this->data['memory'] = memory_get_usage();
43
-
44
  $this->data['memory_limit'] = QM_Util::convert_hr_to_bytes( ini_get( 'memory_limit' ) );
45
  $this->data['memory_usage'] = ( 100 / $this->data['memory_limit'] ) * $this->data['memory'];
46
 
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
28
 
29
  public function process() {
30
 
31
+ $this->data['time'] = self::timer_stop_float();
32
  $this->data['time_limit'] = ini_get( 'max_execution_time' );
33
 
34
  if ( !empty( $this->data['time_limit'] ) )
36
  else
37
  $this->data['time_usage'] = 0;
38
 
39
+ $this->data['memory'] = memory_get_peak_usage();
 
 
 
 
40
  $this->data['memory_limit'] = QM_Util::convert_hr_to_bytes( ini_get( 'memory_limit' ) );
41
  $this->data['memory_usage'] = ( 100 / $this->data['memory_limit'] ) * $this->data['memory'];
42
 
collectors/php_errors.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
@@ -74,10 +74,9 @@ class QM_Collector_PHP_Errors extends QM_Collector {
74
 
75
  if ( error_reporting() > 0 ) {
76
 
77
- $trace = new QM_Backtrace;
78
- $stack = $trace->get_stack();
79
- $func = reset( $stack );
80
- $key = md5( $message . $file . $line . $func );
81
 
82
  $filename = QM_Util::standard_dir( $file, '' );
83
 
@@ -109,17 +108,4 @@ function register_qm_collector_php_errors( array $qm ) {
109
  return $qm;
110
  }
111
 
112
- function qm_php_errors_return_value( $return ) {
113
- if ( QM_Util::is_ajax() )
114
- return true;
115
- if ( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) and 'xmlhttprequest' == strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) )
116
- return true;
117
- # If Xdebug is enabled we'll return false so Xdebug's error handler can do its thing.
118
- if ( function_exists( 'xdebug_is_enabled' ) and xdebug_is_enabled() )
119
- return false;
120
- else
121
- return $return;
122
- }
123
-
124
  add_filter( 'query_monitor_collectors', 'register_qm_collector_php_errors', 110 );
125
- add_filter( 'query_monitor_php_errors_return_value', 'qm_php_errors_return_value' );
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
74
 
75
  if ( error_reporting() > 0 ) {
76
 
77
+ $trace = new QM_Backtrace;
78
+ $caller = $trace->get_caller();
79
+ $key = md5( $message . $file . $line . $caller['id'] );
 
80
 
81
  $filename = QM_Util::standard_dir( $file, '' );
82
 
108
  return $qm;
109
  }
110
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  add_filter( 'query_monitor_collectors', 'register_qm_collector_php_errors', 110 );
 
collectors/redirects.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
@@ -31,16 +31,12 @@ class QM_Collector_Redirects extends QM_Collector {
31
 
32
  if ( !$location )
33
  return $location;
34
- if ( !QueryMonitor::init()->show_query_monitor() )
35
- return $location;
36
- if ( headers_sent() )
37
- return $location;
38
 
39
  $trace = new QM_Backtrace;
40
 
41
- header( sprintf( 'X-QM-Redirect-Trace: %s',
42
- implode( ', ', $trace->get_stack() )
43
- ) );
44
 
45
  return $location;
46
 
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
31
 
32
  if ( !$location )
33
  return $location;
 
 
 
 
34
 
35
  $trace = new QM_Backtrace;
36
 
37
+ $this->data['trace'] = $trace;
38
+ $this->data['location'] = $location;
39
+ $this->data['status'] = $status;
40
 
41
  return $location;
42
 
collectors/request.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
collectors/theme.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
@@ -36,14 +36,15 @@ class QM_Collector_Theme extends QM_Collector {
36
 
37
  global $template;
38
 
39
- $template_file = QM_Util::standard_dir( $template );
40
  $stylesheet_directory = QM_Util::standard_dir( get_stylesheet_directory() );
41
  $template_directory = QM_Util::standard_dir( get_template_directory() );
42
 
43
- $template_file = str_replace( array( $stylesheet_directory, $template_directory ), '', $template_file );
44
  $template_file = ltrim( $template_file, '/' );
45
 
46
- $this->data['template_file'] = apply_filters( 'query_monitor_template', $template_file, $template );
 
47
  $this->data['stylesheet'] = get_stylesheet();
48
  $this->data['template'] = get_template();
49
 
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
36
 
37
  global $template;
38
 
39
+ $template_path = QM_Util::standard_dir( $template );
40
  $stylesheet_directory = QM_Util::standard_dir( get_stylesheet_directory() );
41
  $template_directory = QM_Util::standard_dir( get_template_directory() );
42
 
43
+ $template_file = str_replace( array( $stylesheet_directory, $template_directory ), '', $template_path );
44
  $template_file = ltrim( $template_file, '/' );
45
 
46
+ $this->data['template_path'] = $template_path;
47
+ $this->data['template_file'] = $template_file;
48
  $this->data['stylesheet'] = get_stylesheet();
49
  $this->data['template'] = get_template();
50
 
collectors/transients.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Copyright 2013 John Blackbourn
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
1
  <?php
2
  /*
3
+ Copyright 2014 John Blackbourn
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
dispatchers/Headers.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
@@ -25,8 +25,13 @@ class QM_Dispatcher_Headers extends QM_Dispatcher {
25
 
26
  public function init() {
27
 
28
- if ( QM_Util::is_ajax() )
 
 
 
 
29
  ob_start();
 
30
 
31
  }
32
 
@@ -43,8 +48,9 @@ class QM_Dispatcher_Headers extends QM_Dispatcher {
43
  public function after_output() {
44
 
45
  # flush once, because we're nice
46
- if ( ob_get_length() )
47
  ob_flush();
 
48
 
49
  }
50
 
@@ -54,11 +60,11 @@ class QM_Dispatcher_Headers extends QM_Dispatcher {
54
 
55
  public function active() {
56
 
57
- if ( !$this->qm->show_query_monitor() ) {
58
  return false;
59
  }
60
 
61
- # if the headers have already been sent then we can't do anything about it
62
  if ( headers_sent() ) {
63
  return false;
64
  }
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
25
 
26
  public function init() {
27
 
28
+ if ( ! $this->qm->user_can_view() ) {
29
+ return;
30
+ }
31
+
32
+ if ( QM_Util::is_ajax() ) {
33
  ob_start();
34
+ }
35
 
36
  }
37
 
48
  public function after_output() {
49
 
50
  # flush once, because we're nice
51
+ if ( ob_get_length() ) {
52
  ob_flush();
53
+ }
54
 
55
  }
56
 
60
 
61
  public function active() {
62
 
63
+ if ( ! $this->qm->user_can_view() ) {
64
  return false;
65
  }
66
 
67
+ # If the headers have already been sent then we can't do anything about it
68
  if ( headers_sent() ) {
69
  return false;
70
  }
dispatchers/Html.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
@@ -29,8 +29,9 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
29
 
30
  public function action_admin_bar_menu( WP_Admin_Bar $wp_admin_bar ) {
31
 
32
- if ( !$this->qm->show_query_monitor() )
33
  return;
 
34
 
35
  $class = implode( ' ', array( 'hide-if-js', QM_Util::wpv() ) );
36
  $title = __( 'Query Monitor', 'query-monitor' );
@@ -57,8 +58,13 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
57
 
58
  global $wp_locale;
59
 
60
- if ( !defined( 'DONOTCACHEPAGE' ) )
 
 
 
 
61
  define( 'DONOTCACHEPAGE', 1 );
 
62
 
63
  wp_enqueue_style(
64
  'query-monitor',
@@ -96,7 +102,7 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
96
  include $output;
97
  }
98
 
99
- if ( !function_exists( 'is_admin_bar_showing' ) or !is_admin_bar_showing() )
100
  $class = 'qm-show';
101
  else
102
  $class = '';
@@ -152,11 +158,20 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
152
 
153
  public function active() {
154
 
155
- if ( !$this->qm->show_query_monitor() ) {
 
 
 
 
 
 
 
 
156
  return false;
157
  }
158
 
159
- return $this->qm->did_footer();
 
160
  }
161
 
162
  }
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
29
 
30
  public function action_admin_bar_menu( WP_Admin_Bar $wp_admin_bar ) {
31
 
32
+ if ( ! $this->qm->user_can_view() ) {
33
  return;
34
+ }
35
 
36
  $class = implode( ' ', array( 'hide-if-js', QM_Util::wpv() ) );
37
  $title = __( 'Query Monitor', 'query-monitor' );
58
 
59
  global $wp_locale;
60
 
61
+ if ( ! $this->qm->user_can_view() ) {
62
+ return;
63
+ }
64
+
65
+ if ( ! defined( 'DONOTCACHEPAGE' ) ) {
66
  define( 'DONOTCACHEPAGE', 1 );
67
+ }
68
 
69
  wp_enqueue_style(
70
  'query-monitor',
102
  include $output;
103
  }
104
 
105
+ if ( !is_admin_bar_showing() )
106
  $class = 'qm-show';
107
  else
108
  $class = '';
158
 
159
  public function active() {
160
 
161
+ if ( ! $this->qm->user_can_view() ) {
162
+ return false;
163
+ }
164
+
165
+ if ( ! ( did_action( 'wp_footer' ) or did_action( 'admin_footer' ) or did_action( 'login_footer' ) ) ) {
166
+ return false;
167
+ }
168
+
169
+ if ( QM_Util::is_async() ) {
170
  return false;
171
  }
172
 
173
+ return true;
174
+
175
  }
176
 
177
  }
output/Headers.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
output/Html.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
@@ -17,6 +17,8 @@ GNU General Public License for more details.
17
 
18
  class QM_Output_Html implements QM_Output {
19
 
 
 
20
  public function __construct( QM_Collector $collector ) {
21
  $this->collector = $collector;
22
  }
@@ -82,6 +84,61 @@ class QM_Output_Html implements QM_Output {
82
 
83
  }
84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  final public function get_type() {
86
  return 'html';
87
  }
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
17
 
18
  class QM_Output_Html implements QM_Output {
19
 
20
+ protected static $file_link_format = null;
21
+
22
  public function __construct( QM_Collector $collector ) {
23
  $this->collector = $collector;
24
  }
84
 
85
  }
86
 
87
+ public static function format_sql( $sql ) {
88
+
89
+ $sql = str_replace( array( "\r\n", "\r", "\n", "\t" ), ' ', $sql );
90
+ $sql = esc_html( $sql );
91
+ $sql = trim( $sql );
92
+
93
+ foreach( array(
94
+ 'ALTER', 'AND', 'COMMIT', 'CREATE', 'DESCRIBE', 'DELETE', 'DROP', 'ELSE', 'END', 'FROM', 'GROUP',
95
+ 'HAVING', 'INNER', 'INSERT', 'LIMIT', 'ON', 'OR', 'ORDER', 'REPLACE', 'ROLLBACK', 'SELECT', 'SET',
96
+ 'SHOW', 'START', 'THEN', 'TRUNCATE', 'UPDATE', 'VALUES', 'WHEN', 'WHERE'
97
+ ) as $cmd )
98
+ $sql = trim( str_replace( " $cmd ", "<br>$cmd ", $sql ) );
99
+
100
+ return $sql;
101
+
102
+ }
103
+
104
+ public static function format_url( $url ) {
105
+ $url = str_replace( array(
106
+ '=',
107
+ '&',
108
+ '?',
109
+ ), array(
110
+ '<span class="qm-equals">=</span>',
111
+ '<br><span class="qm-param">&amp;</span>',
112
+ '<br><span class="qm-param">?</span>',
113
+ ), $url );
114
+ return $url;
115
+
116
+ }
117
+
118
+ public static function output_filename( $text, $file, $line = 1 ) {
119
+
120
+ # Further reading:
121
+ # http://simonwheatley.co.uk/2012/07/clickable-stack-traces/
122
+ # https://github.com/dhoulb/subl
123
+
124
+ if ( !isset( self::$file_link_format ) ) {
125
+ $format = ini_get( 'xdebug.file_link_format' );
126
+ $format = apply_filters( 'query_monitor_file_link_format', $format );
127
+ if ( empty( $format ) )
128
+ self::$file_link_format = false;
129
+ else
130
+ self::$file_link_format = str_replace( array( '%f', '%l' ), array( '%1$s', '%2$d' ), $format );
131
+ }
132
+
133
+ if ( false === self::$file_link_format ) {
134
+ return $text;
135
+ }
136
+
137
+ $link = sprintf( self::$file_link_format, urlencode( $file ), $line );
138
+ return sprintf( '<a href="%s">%s</a>', $link, $text );
139
+
140
+ }
141
+
142
  final public function get_type() {
143
  return 'html';
144
  }
output/headers/php_errors.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
output/headers/redirects.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+
4
+ Copyright 2014 John Blackbourn
5
+
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation; either version 2 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ */
17
+
18
+ class QM_Output_Headers_Redirects extends QM_Output_Headers {
19
+
20
+ public function output() {
21
+
22
+ $data = $this->collector->get_data();
23
+
24
+ if ( empty( $data ) )
25
+ return;
26
+
27
+ header( sprintf( 'X-QM-Redirect-Trace: %s',
28
+ implode( ', ', $data['trace']->get_stack() )
29
+ ) );
30
+
31
+ }
32
+
33
+ }
34
+
35
+ function register_qm_output_headers_redirects( QM_Output $output = null, QM_Collector $collector ) {
36
+ return new QM_Output_Headers_Redirects( $collector );
37
+ }
38
+
39
+ add_filter( 'query_monitor_output_headers_redirects', 'register_qm_output_headers_redirects', 10, 2 );
output/html/admin.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ class QM_Output_Html_Admin extends QM_Output_Html {
33
  echo '<table cellspacing="0">';
34
  echo '<thead>';
35
  echo '<tr>';
36
- echo '<th colspan="3">' . $this->collector->name() . '</th>';
37
  echo '</tr>';
38
  echo '</thead>';
39
  echo '<tbody>';
@@ -42,24 +42,16 @@ class QM_Output_Html_Admin extends QM_Output_Html {
42
  echo '<td class="qm-ltr">get_current_screen()</td>';
43
  echo '<td>';
44
 
45
- if ( is_object( $data['admin'] ) ) {
46
- echo '<table class="qm-inner" cellspacing="0">';
47
- echo '<tbody>';
48
- foreach ( $data['admin'] as $key => $value ) {
49
- echo '<tr>';
50
- echo "<td class='qm-var'>{$key}:</td>";
51
- echo '<td>';
52
- echo $value;
53
- if ( !empty( $value ) and ( $data['current_screen']->$key != $value ) )
54
- echo '&nbsp;(<a href="http://core.trac.wordpress.org/ticket/14886" class="qm-warn" title="' . esc_attr__( 'This value may not be as expected. Please see WordPress bug #14886.', 'query-monitor' ) . '" target="_blank">!</a>)';
55
- echo '</td>';
56
- echo '</tr>';
57
- }
58
- echo '</tbody>';
59
- echo '</table>';
60
- } else {
61
- echo $data['admin'];
62
  }
 
 
63
 
64
  echo '</td>';
65
  echo '</tr>';
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
33
  echo '<table cellspacing="0">';
34
  echo '<thead>';
35
  echo '<tr>';
36
+ echo '<th colspan="2">' . $this->collector->name() . '</th>';
37
  echo '</tr>';
38
  echo '</thead>';
39
  echo '<tbody>';
42
  echo '<td class="qm-ltr">get_current_screen()</td>';
43
  echo '<td>';
44
 
45
+ echo '<table class="qm-inner" cellspacing="0">';
46
+ echo '<tbody>';
47
+ foreach ( $data['current_screen'] as $key => $value ) {
48
+ echo '<tr>';
49
+ echo '<td class="qm-var">' . esc_html( $key ) . ':</td>';
50
+ echo '<td>' . esc_html( $value ) . '</td>';
51
+ echo '</tr>';
 
 
 
 
 
 
 
 
 
 
52
  }
53
+ echo '</tbody>';
54
+ echo '</table>';
55
 
56
  echo '</td>';
57
  echo '</tr>';
output/html/authentication.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
output/html/conditionals.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
output/html/db_callers.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
@@ -30,7 +30,6 @@ class QM_Output_Html_DB_Callers extends QM_Output_Html {
30
  return;
31
 
32
  $total_time = 0;
33
- $total_calls = 0;
34
  $span = count( $data['types'] ) + 2;
35
 
36
  echo '<div class="qm qm-half" id="' . $this->collector->id() . '">';
@@ -59,7 +58,6 @@ class QM_Output_Html_DB_Callers extends QM_Output_Html {
59
 
60
  foreach ( $data['times'] as $caller => $row ) {
61
  $total_time += $row['ltime'];
62
- $total_calls += $row['calls'];
63
  $stime = number_format_i18n( $row['ltime'], 4 );
64
  $ltime = number_format_i18n( $row['ltime'], 10 );
65
 
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
30
  return;
31
 
32
  $total_time = 0;
 
33
  $span = count( $data['types'] ) + 2;
34
 
35
  echo '<div class="qm qm-half" id="' . $this->collector->id() . '">';
58
 
59
  foreach ( $data['times'] as $caller => $row ) {
60
  $total_time += $row['ltime'];
 
61
  $stime = number_format_i18n( $row['ltime'], 4 );
62
  $ltime = number_format_i18n( $row['ltime'], 10 );
63
 
output/html/db_components.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
output/html/db_queries.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
@@ -28,71 +28,103 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
28
 
29
  $data = $this->collector->get_data();
30
 
31
- if ( empty( $data['dbs'] ) )
 
32
  return;
 
33
 
34
  if ( !empty( $data['errors'] ) ) {
 
 
35
 
36
- echo '<div class="qm qm-queries" id="qm-query-errors">';
37
- echo '<table cellspacing="0">';
38
- echo '<thead>';
39
- echo '<tr>';
40
- echo '<th colspan="4">' . __( 'Database Errors', 'query-monitor' ) . '</th>';
41
- echo '</tr>';
42
- echo '<tr>';
43
- echo '<th>' . __( 'Query', 'query-monitor' ) . '</th>';
44
- echo '<th>' . __( 'Call Stack', 'query-monitor' ) . '</th>';
45
- echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
46
- echo '<th>' . __( 'Error', 'query-monitor' ) . '</th>';
47
- echo '</tr>';
48
- echo '</thead>';
49
- echo '<tbody>';
50
 
51
- foreach ( $data['errors'] as $row )
52
- $this->output_query_row( $row, array( 'sql', 'stack', 'component', 'result' ) );
 
53
 
54
- echo '</tbody>';
55
- echo '</table>';
56
- echo '</div>';
57
 
58
- }
59
 
60
- if ( !empty( $data['expensive'] ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
- $dp = strlen( substr( strrchr( QM_DB_EXPENSIVE, '.' ), 1 ) );
63
 
64
- echo '<div class="qm qm-queries" id="qm-query-expensive">';
65
- echo '<table cellspacing="0">';
66
- echo '<thead>';
67
- echo '<tr>';
68
- echo '<th colspan="5" class="qm-expensive">' . sprintf( __( 'Slow Database Queries (above %ss)', 'query-monitor' ), '<span class="qm-expensive">' . number_format_i18n( QM_DB_EXPENSIVE, $dp ) . '</span>' ) . '</th>';
69
- echo '</tr>';
70
- echo '<tr>';
71
- echo '<th scope="col">' . __( 'Query', 'query-monitor' ) . '</th>';
72
- echo '<th scope="col">' . __( 'Caller', 'query-monitor' ) . '</th>';
73
 
74
- if ( isset( $data['expensive'][0]['component'] ) )
75
- echo '<th scope="col">' . __( 'Component', 'query-monitor' ) . '</th>';
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
- if ( isset( $data['expensive'][0]['result'] ) )
78
- echo '<th scope="col">' . __( 'Affected Rows', 'query-monitor' ) . '</th>';
79
 
80
- echo '<th>' . __( 'Time', 'query-monitor' ) . '</th>';
81
- echo '</tr>';
82
- echo '</thead>';
83
- echo '<tbody>';
84
 
85
- foreach ( $data['expensive'] as $row )
86
- $this->output_query_row( $row, array( 'sql', 'caller', 'component', 'result', 'time' ) );
87
 
88
- echo '</tbody>';
89
- echo '</table>';
90
- echo '</div>';
91
 
92
- }
93
 
94
- foreach ( $data['dbs'] as $name => $db )
95
- $this->output_queries( $name, $db, $data );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
  }
98
 
@@ -116,7 +148,7 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
116
 
117
  if ( ! $db->has_component ) {
118
  echo '<tr>';
119
- echo '<td colspan="' . $span . '" class="qm-warn">' . sprintf( __( 'Extended query information such as the component and affected rows is not available. Query Monitor was unable to symlink its db.php file into place. <a href="%s" target="_blank">See this wiki page for more information.</a>', 'query-monitor' ),
120
  'https://github.com/johnbillion/query-monitor/wiki/db.php-Symlink'
121
  ) . '</td>';
122
  echo '</tr>';
@@ -189,11 +221,11 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
189
 
190
  $cols = array_flip( $cols );
191
 
192
- if ( is_null( $row['component'] ) )
193
  unset( $cols['component'] );
194
- if ( is_null( $row['result'] ) )
195
  unset( $cols['result'] );
196
- if ( is_null( $row['stack'] ) )
197
  unset( $cols['stack'] );
198
 
199
  $row_attr = array();
@@ -201,7 +233,7 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
201
  $ltime = number_format_i18n( $row['ltime'], 10 );
202
  $td = $this->collector->is_expensive( $row ) ? ' qm-expensive' : '';
203
 
204
- $sql = QM_Util::format_sql( $row['sql'] );
205
 
206
  if ( 'SELECT' != $row['type'] )
207
  $sql = "<span class='qm-nonselectsql'>{$sql}</span>";
@@ -225,7 +257,6 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
225
  $row_attr['data-qm-time'] = $row['ltime'];
226
  }
227
 
228
- $stack = esc_attr( $row['stack'] );
229
  $attr = '';
230
 
231
  foreach ( $row_attr as $a => $v )
@@ -238,9 +269,18 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
238
 
239
  if ( isset( $cols['caller'] ) ) {
240
  echo "<td valign='top' class='qm-row-caller qm-ltr qm-has-toggle'>";
241
- echo $row['caller'];
 
 
 
 
 
 
 
 
242
 
243
  # This isn't optimal...
 
244
  $stack = explode( ', ', $row['stack'] );
245
  $stack = array_reverse( $stack );
246
  array_shift( $stack );
@@ -323,7 +363,7 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
323
  ) );
324
  }
325
 
326
- if ( count( $data['dbs'] ) > 1 ) {
327
  foreach ( $data['dbs'] as $name => $db ) {
328
  $menu[] = $this->menu( array(
329
  'title' => sprintf( __( 'Queries (%s)', 'query-monitor' ), esc_html( $name ) ),
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
28
 
29
  $data = $this->collector->get_data();
30
 
31
+ if ( empty( $data['dbs'] ) ) {
32
+ $this->output_empty_queries();
33
  return;
34
+ }
35
 
36
  if ( !empty( $data['errors'] ) ) {
37
+ $this->output_error_queries( $data['errors'] );
38
+ }
39
 
40
+ if ( !empty( $data['expensive'] ) ) {
41
+ $this->output_expensive_queries( $data['expensive'] );
42
+ }
 
 
 
 
 
 
 
 
 
 
 
43
 
44
+ foreach ( $data['dbs'] as $name => $db ) {
45
+ $this->output_queries( $name, $db, $data );
46
+ }
47
 
48
+ }
 
 
49
 
50
+ protected function output_empty_queries() {
51
 
52
+ echo '<div class="qm qm-queries" id="' . $this->collector->id() . '-wpdb">';
53
+ echo '<table cellspacing="0">';
54
+ echo '<thead>';
55
+ echo '<tr>';
56
+ echo '<th>' . __( 'Database Queries', 'query-monitor' ) . '</th>';
57
+ echo '</tr>';
58
+ echo '</thead>';
59
+ echo '<tbody>';
60
+ echo '<tr>';
61
+ echo '<td class="qm-warn">';
62
+ _e( 'No database queries were logged because <code>SAVEQUERIES</code> is set to <code>false</code>', 'query-monitor' );
63
+ echo '</td>';
64
+ echo '</tr>';
65
+ echo '</tbody>';
66
+ echo '</table>';
67
+ echo '</div>';
68
 
69
+ }
70
 
71
+ protected function output_error_queries( array $errors ) {
 
 
 
 
 
 
 
 
72
 
73
+ echo '<div class="qm qm-queries" id="qm-query-errors">';
74
+ echo '<table cellspacing="0">';
75
+ echo '<thead>';
76
+ echo '<tr>';
77
+ echo '<th colspan="4">' . __( 'Database Errors', 'query-monitor' ) . '</th>';
78
+ echo '</tr>';
79
+ echo '<tr>';
80
+ echo '<th>' . __( 'Query', 'query-monitor' ) . '</th>';
81
+ echo '<th>' . __( 'Call Stack', 'query-monitor' ) . '</th>';
82
+ echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
83
+ echo '<th>' . __( 'Error', 'query-monitor' ) . '</th>';
84
+ echo '</tr>';
85
+ echo '</thead>';
86
+ echo '<tbody>';
87
 
88
+ foreach ( $errors as $row )
89
+ $this->output_query_row( $row, array( 'sql', 'stack', 'component', 'result' ) );
90
 
91
+ echo '</tbody>';
92
+ echo '</table>';
93
+ echo '</div>';
 
94
 
95
+ }
 
96
 
97
+ protected function output_expensive_queries( array $expensive ) {
 
 
98
 
99
+ $dp = strlen( substr( strrchr( QM_DB_EXPENSIVE, '.' ), 1 ) );
100
 
101
+ echo '<div class="qm qm-queries" id="qm-query-expensive">';
102
+ echo '<table cellspacing="0">';
103
+ echo '<thead>';
104
+ echo '<tr>';
105
+ echo '<th colspan="5" class="qm-expensive">' . sprintf( __( 'Slow Database Queries (above %ss)', 'query-monitor' ), '<span class="qm-expensive">' . number_format_i18n( QM_DB_EXPENSIVE, $dp ) . '</span>' ) . '</th>';
106
+ echo '</tr>';
107
+ echo '<tr>';
108
+ echo '<th scope="col">' . __( 'Query', 'query-monitor' ) . '</th>';
109
+ echo '<th scope="col">' . __( 'Caller', 'query-monitor' ) . '</th>';
110
+
111
+ if ( isset( $expensive[0]['component'] ) )
112
+ echo '<th scope="col">' . __( 'Component', 'query-monitor' ) . '</th>';
113
+
114
+ if ( isset( $expensive[0]['result'] ) )
115
+ echo '<th scope="col">' . __( 'Affected Rows', 'query-monitor' ) . '</th>';
116
+
117
+ echo '<th>' . __( 'Time', 'query-monitor' ) . '</th>';
118
+ echo '</tr>';
119
+ echo '</thead>';
120
+ echo '<tbody>';
121
+
122
+ foreach ( $expensive as $row )
123
+ $this->output_query_row( $row, array( 'sql', 'caller', 'component', 'result', 'time' ) );
124
+
125
+ echo '</tbody>';
126
+ echo '</table>';
127
+ echo '</div>';
128
 
129
  }
130
 
148
 
149
  if ( ! $db->has_component ) {
150
  echo '<tr>';
151
+ echo '<td colspan="' . $span . '" class="qm-warn">' . sprintf( __( 'Extended query information such as the component and affected rows is not available. Query Monitor was unable to symlink its <code>db.php</code> file into place. <a href="%s" target="_blank">See this wiki page for more information.</a>', 'query-monitor' ),
152
  'https://github.com/johnbillion/query-monitor/wiki/db.php-Symlink'
153
  ) . '</td>';
154
  echo '</tr>';
221
 
222
  $cols = array_flip( $cols );
223
 
224
+ if ( !isset( $row['component'] ) )
225
  unset( $cols['component'] );
226
+ if ( !isset( $row['result'] ) )
227
  unset( $cols['result'] );
228
+ if ( !isset( $row['stack'] ) )
229
  unset( $cols['stack'] );
230
 
231
  $row_attr = array();
233
  $ltime = number_format_i18n( $row['ltime'], 10 );
234
  $td = $this->collector->is_expensive( $row ) ? ' qm-expensive' : '';
235
 
236
+ $sql = self::format_sql( $row['sql'] );
237
 
238
  if ( 'SELECT' != $row['type'] )
239
  $sql = "<span class='qm-nonselectsql'>{$sql}</span>";
257
  $row_attr['data-qm-time'] = $row['ltime'];
258
  }
259
 
 
260
  $attr = '';
261
 
262
  foreach ( $row_attr as $a => $v )
269
 
270
  if ( isset( $cols['caller'] ) ) {
271
  echo "<td valign='top' class='qm-row-caller qm-ltr qm-has-toggle'>";
272
+
273
+ $caller_name = $row['caller'];
274
+
275
+ if ( isset( $row['trace'] ) ) {
276
+ $caller = $row['trace']->get_caller();
277
+ $caller_name = self::output_filename( $row['caller'], $caller['calling_file'], $caller['calling_line'] );
278
+ }
279
+
280
+ echo $caller_name;
281
 
282
  # This isn't optimal...
283
+ # @TODO convert this to use our new filtered trace array when present
284
  $stack = explode( ', ', $row['stack'] );
285
  $stack = array_reverse( $stack );
286
  array_shift( $stack );
363
  ) );
364
  }
365
 
366
+ if ( isset( $data['dbs'] ) and count( $data['dbs'] ) > 1 ) {
367
  foreach ( $data['dbs'] as $name => $db ) {
368
  $menu[] = $this->menu( array(
369
  'title' => sprintf( __( 'Queries (%s)', 'query-monitor' ), esc_html( $name ) ),
output/html/environment.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
output/html/hooks.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
@@ -91,7 +91,13 @@ class QM_Output_Html_Hooks extends QM_Output_Html {
91
 
92
  echo '<td valign="top" class="qm-priority">' . $action['priority'] . '</td>';
93
  echo '<td valign="top" class="qm-ltr">';
94
- echo esc_html( $action['callback']['name'] );
 
 
 
 
 
 
95
  if ( isset( $action['callback']['error'] ) ) {
96
  echo '<br><span class="qm-warn">';
97
  printf( __( 'Error: %s', 'query-monitor' ),
@@ -99,6 +105,7 @@ class QM_Output_Html_Hooks extends QM_Output_Html {
99
  );
100
  echo '<span>';
101
  }
 
102
  echo '</td>';
103
  echo '<td valign="top">';
104
  echo esc_html( $component );
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
91
 
92
  echo '<td valign="top" class="qm-priority">' . $action['priority'] . '</td>';
93
  echo '<td valign="top" class="qm-ltr">';
94
+
95
+ if ( isset( $action['callback']['file'] ) ) {
96
+ echo self::output_filename( esc_html( $action['callback']['name'] ), $action['callback']['file'], $action['callback']['line'] );
97
+ } else {
98
+ echo esc_html( $action['callback']['name'] );
99
+ }
100
+
101
  if ( isset( $action['callback']['error'] ) ) {
102
  echo '<br><span class="qm-warn">';
103
  printf( __( 'Error: %s', 'query-monitor' ),
105
  );
106
  echo '<span>';
107
  }
108
+
109
  echo '</td>';
110
  echo '<td valign="top">';
111
  echo esc_html( $component );
output/html/http.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
@@ -50,7 +50,7 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
50
  foreach ( $data['http'] as $key => $row ) {
51
  $funcs = array();
52
 
53
- $ltime = ( $row['end'] - $row['start'] );
54
  $total_time += $ltime;
55
 
56
  if ( empty( $ltime ) )
@@ -58,8 +58,6 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
58
  else
59
  $stime = number_format_i18n( $ltime, 4 );
60
 
61
- $ltime = number_format_i18n( $ltime, 10 );
62
-
63
  if ( is_wp_error( $row['response'] ) ) {
64
  $response = $row['response']->get_error_message();
65
  $css = 'qm-warn';
@@ -81,7 +79,7 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
81
  $method = $row['args']['method'];
82
  if ( !$row['args']['blocking'] )
83
  $method .= '&nbsp;' . _x( '(non-blocking)', 'non-blocking HTTP transport', 'query-monitor' );
84
- $url = QM_Util::format_url( $row['url'] );
85
 
86
  if ( isset( $row['transport'] ) )
87
  $transport = $row['transport'];
@@ -110,7 +108,7 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
110
  <td valign='top' class='qm-ltr'>{$stack}</td>\n
111
  <td valign='top'>{$component->name}</td>\n
112
  <td valign='top'>{$row['args']['timeout']}</td>\n
113
- <td valign='top' title='{$ltime}'>{$stime}</td>\n
114
  </tr>\n
115
  ";
116
  }
@@ -121,8 +119,18 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
121
  $total_stime = number_format_i18n( $total_time, 4 );
122
  $total_ltime = number_format_i18n( $total_time, 10 );
123
 
 
 
 
 
 
 
 
 
 
 
124
  echo '<tr>';
125
- echo '<td colspan="6">&nbsp;</td>';
126
  echo "<td title='{$total_ltime}'>{$total_stime}</td>";
127
  echo '</tr>';
128
  echo '</tfoot>';
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
50
  foreach ( $data['http'] as $key => $row ) {
51
  $funcs = array();
52
 
53
+ $ltime = $row['ltime'];
54
  $total_time += $ltime;
55
 
56
  if ( empty( $ltime ) )
58
  else
59
  $stime = number_format_i18n( $ltime, 4 );
60
 
 
 
61
  if ( is_wp_error( $row['response'] ) ) {
62
  $response = $row['response']->get_error_message();
63
  $css = 'qm-warn';
79
  $method = $row['args']['method'];
80
  if ( !$row['args']['blocking'] )
81
  $method .= '&nbsp;' . _x( '(non-blocking)', 'non-blocking HTTP transport', 'query-monitor' );
82
+ $url = self::format_url( $row['url'] );
83
 
84
  if ( isset( $row['transport'] ) )
85
  $transport = $row['transport'];
108
  <td valign='top' class='qm-ltr'>{$stack}</td>\n
109
  <td valign='top'>{$component->name}</td>\n
110
  <td valign='top'>{$row['args']['timeout']}</td>\n
111
+ <td valign='top'>{$stime}</td>\n
112
  </tr>\n
113
  ";
114
  }
119
  $total_stime = number_format_i18n( $total_time, 4 );
120
  $total_ltime = number_format_i18n( $total_time, 10 );
121
 
122
+ $vars = '&nbsp;';
123
+
124
+ if ( isset( $data['vars'] ) ) {
125
+ $vars = array();
126
+ foreach ( $data['vars'] as $key => $value ) {
127
+ $vars[] = $key . ': ' . $value;
128
+ }
129
+ $vars = implode( ', ', $vars );
130
+ }
131
+
132
  echo '<tr>';
133
+ echo '<td colspan="6">' . $vars . '</td>';
134
  echo "<td title='{$total_ltime}'>{$total_stime}</td>";
135
  echo '</tr>';
136
  echo '</tfoot>';
output/html/overview.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
output/html/php_errors.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
@@ -35,8 +35,8 @@ class QM_Output_Html_PHP_Errors extends QM_Output_Html {
35
  echo '<thead>';
36
  echo '<tr>';
37
  echo '<th colspan="2">' . __( 'PHP Error', 'query-monitor' ) . '</th>';
38
- echo '<th>' . __( 'File', 'query-monitor' ) . '</th>';
39
- echo '<th>' . __( 'Line', 'query-monitor' ) . '</th>';
40
  echo '<th>' . __( 'Call Stack', 'query-monitor' ) . '</th>';
41
  echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
42
  echo '</tr>';
@@ -55,10 +55,7 @@ class QM_Output_Html_PHP_Errors extends QM_Output_Html {
55
  if ( isset( $data['errors'][$type] ) ) {
56
 
57
  echo '<tr>';
58
- if ( count( $data['errors'][$type] ) > 1 )
59
- echo '<td rowspan="' . count( $data['errors'][$type] ) . '">' . $title . '</td>';
60
- else
61
- echo '<td>' . $title . '</td>';
62
  $first = true;
63
 
64
  foreach ( $data['errors'][$type] as $error ) {
@@ -66,19 +63,18 @@ class QM_Output_Html_PHP_Errors extends QM_Output_Html {
66
  if ( !$first )
67
  echo '<tr>';
68
 
69
- $stack = $error->trace->get_stack();
70
  $component = $error->trace->get_component();
 
 
71
 
72
- if ( empty( $stack ) )
73
- $stack = '<em>' . __( 'none', 'query-monitor' ) . '</em>';
74
- else
75
- $stack = implode( '<br>', $stack );
76
-
77
- $message = str_replace( "href='function.", "target='_blank' href='http://php.net/function.", $error->message );
78
 
79
  echo '<td>' . $message . '</td>';
80
- echo '<td title="' . esc_attr( $error->file ) . '">' . esc_html( $error->filename ) . '</td>';
81
- echo '<td>' . esc_html( $error->line ) . '</td>';
 
 
82
  echo '<td class="qm-ltr">' . $stack . '</td>';
83
  echo '<td>' . $component->name . '</td>';
84
  echo '</tr>';
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
35
  echo '<thead>';
36
  echo '<tr>';
37
  echo '<th colspan="2">' . __( 'PHP Error', 'query-monitor' ) . '</th>';
38
+ echo '<th>' . __( 'Count', 'query-monitor' ) . '</th>';
39
+ echo '<th>' . __( 'Location', 'query-monitor' ) . '</th>';
40
  echo '<th>' . __( 'Call Stack', 'query-monitor' ) . '</th>';
41
  echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
42
  echo '</tr>';
55
  if ( isset( $data['errors'][$type] ) ) {
56
 
57
  echo '<tr>';
58
+ echo '<td rowspan="' . count( $data['errors'][$type] ) . '">' . $title . '</td>';
 
 
 
59
  $first = true;
60
 
61
  foreach ( $data['errors'][$type] as $error ) {
63
  if ( !$first )
64
  echo '<tr>';
65
 
66
+ $stack = $error->trace->get_stack();
67
  $component = $error->trace->get_component();
68
+ $stack = implode( '<br>', $stack );
69
+ $message = str_replace( "href='function.", "target='_blank' href='http://php.net/function.", $error->message );
70
 
71
+ $output = esc_html( $error->filename ) . ':' . $error->line;
 
 
 
 
 
72
 
73
  echo '<td>' . $message . '</td>';
74
+ echo '<td>' . number_format_i18n( $error->calls ) . '</td>';
75
+ echo '<td title="' . esc_attr( $error->file ) . '">';
76
+ echo self::output_filename( $output, $error->file, $error->line );
77
+ echo '</td>';
78
  echo '<td class="qm-ltr">' . $stack . '</td>';
79
  echo '<td>' . $component->name . '</td>';
80
  echo '</tr>';
output/html/request.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
@@ -88,7 +88,7 @@ class QM_Output_Html_Request extends QM_Output_Html {
88
 
89
  if ( ! empty( $data['request'][$item] ) ) {
90
  if ( in_array( $item, array( 'request', 'matched_query', 'query_string' ) ) ) {
91
- $value = QM_Util::format_url( $data['request'][$item] );
92
  } else {
93
  $value = esc_html( $data['request'][$item] );
94
  }
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
88
 
89
  if ( ! empty( $data['request'][$item] ) ) {
90
  if ( in_array( $item, array( 'request', 'matched_query', 'query_string' ) ) ) {
91
+ $value = self::format_url( $data['request'][$item] );
92
  } else {
93
  $value = esc_html( $data['request'][$item] );
94
  }
output/html/theme.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
@@ -40,7 +40,7 @@ class QM_Output_Html_Theme extends QM_Output_Html {
40
  echo '<tbody>';
41
  echo '<tr>';
42
  echo '<td>' . __( 'Template', 'query-monitor' ) . '</td>';
43
- echo "<td>{$data['template_file']}</td>";
44
  echo '</tr>';
45
 
46
  if ( !empty( $data['body_class'] ) ) {
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
40
  echo '<tbody>';
41
  echo '<tr>';
42
  echo '<td>' . __( 'Template', 'query-monitor' ) . '</td>';
43
+ echo '<td>' . self::output_filename( $data['template_file'], $data['template_path'] ) . '</td>';
44
  echo '</tr>';
45
 
46
  if ( !empty( $data['body_class'] ) ) {
output/html/transients.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
 
4
- Copyright 2013 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ class QM_Output_Html_Transients extends QM_Output_Html {
33
  echo '<th>' . __( 'Transient Set', 'query-monitor' ) . '</th>';
34
  if ( is_multisite() )
35
  echo '<th>' . __( 'Type', 'query-monitor' ) . '</th>';
36
- if ( !empty( $data['trans'] ) and !is_null( $data['trans'][0]['expiration'] ) )
37
  echo '<th>' . __( 'Expiration', 'query-monitor' ) . '</th>';
38
  echo '<th>' . __( 'Call Stack', 'query-monitor' ) . '</th>';
39
  echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
@@ -53,7 +53,7 @@ class QM_Output_Html_Transients extends QM_Output_Html {
53
  $type = ( is_multisite() ) ? "<td valign='top'>{$row['type']}</td>\n" : '';
54
  if ( 0 === $row['expiration'] )
55
  $row['expiration'] = '<em>' . __( 'none', 'query-monitor' ) . '</em>';
56
- $expiration = ( !is_null( $row['expiration'] ) ) ? "<td valign='top'>{$row['expiration']}</td>\n" : '';
57
 
58
  foreach ( $stack as & $trace ) {
59
  foreach ( array( 'set_transient', 'set_site_transient' ) as $skip ) {
1
  <?php
2
  /*
3
 
4
+ Copyright 2014 John Blackbourn
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
33
  echo '<th>' . __( 'Transient Set', 'query-monitor' ) . '</th>';
34
  if ( is_multisite() )
35
  echo '<th>' . __( 'Type', 'query-monitor' ) . '</th>';
36
+ if ( !empty( $data['trans'] ) and isset( $data['trans'][0]['expiration'] ) )
37
  echo '<th>' . __( 'Expiration', 'query-monitor' ) . '</th>';
38
  echo '<th>' . __( 'Call Stack', 'query-monitor' ) . '</th>';
39
  echo '<th>' . __( 'Component', 'query-monitor' ) . '</th>';
53
  $type = ( is_multisite() ) ? "<td valign='top'>{$row['type']}</td>\n" : '';
54
  if ( 0 === $row['expiration'] )
55
  $row['expiration'] = '<em>' . __( 'none', 'query-monitor' ) . '</em>';
56
+ $expiration = ( isset( $row['expiration'] ) ) ? "<td valign='top'>{$row['expiration']}</td>\n" : '';
57
 
58
  foreach ( $stack as & $trace ) {
59
  foreach ( array( 'set_transient', 'set_site_transient' ) as $skip ) {
query-monitor.php CHANGED
@@ -2,7 +2,7 @@
2
  /*
3
  Plugin Name: Query Monitor
4
  Description: Monitoring of database queries, hooks, conditionals and more.
5
- Version: 2.6.2
6
  Plugin URI: https://github.com/johnbillion/query-monitor
7
  Author: John Blackbourn
8
  Author URI: https://johnblackbourn.com/
@@ -10,7 +10,7 @@ Text Domain: query-monitor
10
  Domain Path: /languages/
11
  License: GPL v2 or later
12
 
13
- Copyright 2013 John Blackbourn
14
 
15
  This program is free software; you can redistribute it and/or modify
16
  it under the terms of the GNU General Public License as published by
@@ -26,24 +26,24 @@ GNU General Public License for more details.
26
 
27
  defined( 'ABSPATH' ) or die();
28
 
 
 
 
29
  # No autoloaders for us. See https://github.com/johnbillion/QueryMonitor/issues/7
30
- foreach ( array( 'Backtrace', 'Collector', 'Plugin', 'Util', 'Dispatcher', 'Output' ) as $f )
31
- require_once dirname( __FILE__ ) . "/{$f}.php";
 
32
 
33
  class QueryMonitor extends QM_Plugin {
34
 
35
  protected $collectors = array();
36
  protected $dispatchers = array();
37
- protected $did_footer = false;
38
 
39
  protected function __construct( $file ) {
40
 
41
  # Actions
42
- add_action( 'init', array( $this, 'action_init' ) );
43
- add_action( 'admin_footer', array( $this, 'action_footer' ) );
44
- add_action( 'wp_footer', array( $this, 'action_footer' ) );
45
- add_action( 'login_footer', array( $this, 'action_footer' ) );
46
- add_action( 'shutdown', array( $this, 'action_shutdown' ), 9999 );
47
 
48
  # Filters
49
  add_filter( 'pre_update_option_active_plugins', array( $this, 'filter_active_plugins' ) );
@@ -56,12 +56,14 @@ class QueryMonitor extends QM_Plugin {
56
  # Parent setup:
57
  parent::__construct( $file );
58
 
 
59
  foreach ( glob( $this->plugin_path( 'collectors/*.php' ) ) as $collector )
60
  include $collector;
61
 
62
  foreach ( apply_filters( 'query_monitor_collectors', array() ) as $collector )
63
  $this->add_collector( $collector );
64
 
 
65
  foreach ( glob( $this->plugin_path( 'dispatchers/*.php' ) ) as $dispatcher )
66
  include $dispatcher;
67
 
@@ -93,16 +95,12 @@ class QueryMonitor extends QM_Plugin {
93
  return $this->dispatchers;
94
  }
95
 
96
- public function did_footer() {
97
- return $this->did_footer;
98
- }
99
-
100
  public function activate( $sitewide = false ) {
101
 
102
  if ( $admins = QM_Util::get_admins() )
103
  $admins->add_cap( 'view_query_monitor' );
104
 
105
- if ( ! file_exists( $db = WP_CONTENT_DIR . '/db.php' ) )
106
  @symlink( $this->plugin_path( 'wp-content/db.php' ), $db );
107
 
108
  if ( $sitewide )
@@ -123,41 +121,75 @@ class QueryMonitor extends QM_Plugin {
123
 
124
  }
125
 
126
- public function show_query_monitor() {
127
 
128
  if ( !did_action( 'plugins_loaded' ) )
129
  return false;
130
 
131
- if ( isset( $this->show_query_monitor ) )
132
- return $this->show_query_monitor;
133
-
134
- if ( isset( $_REQUEST['wp_customize'] ) and 'on' == $_REQUEST['wp_customize'] )
135
- return $this->show_query_monitor = false;
136
-
137
  if ( is_multisite() ) {
138
  if ( current_user_can( 'manage_network_options' ) )
139
- return $this->show_query_monitor = true;
140
  } else if ( current_user_can( 'view_query_monitor' ) ) {
141
- return $this->show_query_monitor = true;
142
  }
143
 
144
  if ( $auth = self::get_collector( 'authentication' ) )
145
- return $this->show_query_monitor = $auth->show_query_monitor();
146
 
147
- return $this->show_query_monitor = false;
148
 
149
  }
150
 
151
- public function action_footer() {
 
 
 
 
 
 
 
 
 
 
152
 
153
- $this->did_footer = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
  }
156
 
157
  public function action_shutdown() {
158
 
159
- # @TODO introduce a method on dispatchers which defaults to not processing
160
- # qm and then a persistent outputter can switch it on
 
 
161
  foreach ( $this->get_collectors() as $collector ) {
162
  $collector->process();
163
  }
@@ -184,9 +216,6 @@ class QueryMonitor extends QM_Plugin {
184
 
185
  load_plugin_textdomain( 'query-monitor', false, dirname( $this->plugin_base() ) . '/languages' );
186
 
187
- if ( !$this->show_query_monitor() )
188
- return;
189
-
190
  foreach ( $this->get_dispatchers() as $dispatcher ) {
191
  $dispatcher->init();
192
  }
2
  /*
3
  Plugin Name: Query Monitor
4
  Description: Monitoring of database queries, hooks, conditionals and more.
5
+ Version: 2.6.3
6
  Plugin URI: https://github.com/johnbillion/query-monitor
7
  Author: John Blackbourn
8
  Author URI: https://johnblackbourn.com/
10
  Domain Path: /languages/
11
  License: GPL v2 or later
12
 
13
+ Copyright 2014 John Blackbourn
14
 
15
  This program is free software; you can redistribute it and/or modify
16
  it under the terms of the GNU General Public License as published by
26
 
27
  defined( 'ABSPATH' ) or die();
28
 
29
+ if ( defined( 'QM_DISABLED' ) and QM_DISABLED )
30
+ return;
31
+
32
  # No autoloaders for us. See https://github.com/johnbillion/QueryMonitor/issues/7
33
+ $qm_dir = dirname( __FILE__ );
34
+ foreach ( array( 'Backtrace', 'Collector', 'Plugin', 'Util', 'Dispatcher', 'Output' ) as $qm_class )
35
+ require_once "{$qm_dir}/{$qm_class}.php";
36
 
37
  class QueryMonitor extends QM_Plugin {
38
 
39
  protected $collectors = array();
40
  protected $dispatchers = array();
 
41
 
42
  protected function __construct( $file ) {
43
 
44
  # Actions
45
+ add_action( 'init', array( $this, 'action_init' ) );
46
+ add_action( 'shutdown', array( $this, 'action_shutdown' ), 0 );
 
 
 
47
 
48
  # Filters
49
  add_filter( 'pre_update_option_active_plugins', array( $this, 'filter_active_plugins' ) );
56
  # Parent setup:
57
  parent::__construct( $file );
58
 
59
+ # Collectors:
60
  foreach ( glob( $this->plugin_path( 'collectors/*.php' ) ) as $collector )
61
  include $collector;
62
 
63
  foreach ( apply_filters( 'query_monitor_collectors', array() ) as $collector )
64
  $this->add_collector( $collector );
65
 
66
+ # Dispatchers:
67
  foreach ( glob( $this->plugin_path( 'dispatchers/*.php' ) ) as $dispatcher )
68
  include $dispatcher;
69
 
95
  return $this->dispatchers;
96
  }
97
 
 
 
 
 
98
  public function activate( $sitewide = false ) {
99
 
100
  if ( $admins = QM_Util::get_admins() )
101
  $admins->add_cap( 'view_query_monitor' );
102
 
103
+ if ( ! file_exists( $db = WP_CONTENT_DIR . '/db.php' ) and function_exists( 'symlink' ) )
104
  @symlink( $this->plugin_path( 'wp-content/db.php' ), $db );
105
 
106
  if ( $sitewide )
121
 
122
  }
123
 
124
+ public function user_can_view() {
125
 
126
  if ( !did_action( 'plugins_loaded' ) )
127
  return false;
128
 
 
 
 
 
 
 
129
  if ( is_multisite() ) {
130
  if ( current_user_can( 'manage_network_options' ) )
131
+ return true;
132
  } else if ( current_user_can( 'view_query_monitor' ) ) {
133
+ return true;
134
  }
135
 
136
  if ( $auth = self::get_collector( 'authentication' ) )
137
+ return $auth->user_can_view();
138
 
139
+ return false;
140
 
141
  }
142
 
143
+ public function should_process() {
144
+
145
+ # Don't process if the minimum required actions haven't fired:
146
+
147
+ if ( QM_Util::is_ajax() ) {
148
+
149
+ if ( ! did_action( 'init' ) ) {
150
+ return false;
151
+ }
152
+
153
+ } else if ( is_admin() ) {
154
 
155
+ if ( ! did_action( 'admin_init' ) ) {
156
+ return false;
157
+ }
158
+
159
+ } else {
160
+
161
+ if ( ! did_action( 'wp' ) ) {
162
+ return false;
163
+ }
164
+
165
+ }
166
+
167
+ $e = error_get_last();
168
+
169
+ # Don't process if a fatal has occurred:
170
+ if ( ! empty( $e ) and ( 1 === $e['type'] ) ) {
171
+ return false;
172
+ }
173
+
174
+ foreach ( $this->get_dispatchers() as $dispatcher ) {
175
+
176
+ # At least one dispatcher is active, so we need to process:
177
+ if ( $dispatcher->active() ) {
178
+ return true;
179
+ }
180
+
181
+ }
182
+
183
+ return false;
184
 
185
  }
186
 
187
  public function action_shutdown() {
188
 
189
+ if ( ! $this->should_process() ) {
190
+ return;
191
+ }
192
+
193
  foreach ( $this->get_collectors() as $collector ) {
194
  $collector->process();
195
  }
216
 
217
  load_plugin_textdomain( 'query-monitor', false, dirname( $this->plugin_base() ) . '/languages' );
218
 
 
 
 
219
  foreach ( $this->get_dispatchers() as $dispatcher ) {
220
  $dispatcher->init();
221
  }
readme.txt CHANGED
@@ -2,15 +2,15 @@
2
  Contributors: johnbillion
3
  Tags: debug, debugging, development, developer, performance, profiler, profiling, queries
4
  Requires at least: 3.5
5
- Tested up to: 3.8
6
- Stable tag: 2.6.2
7
  License: GPLv2 or later
8
 
9
  View debugging and performance information on database queries, hooks, conditionals, HTTP requests, redirects and more.
10
 
11
  == Description ==
12
 
13
- Query Monitor is a debugging plugin for anyone developing with WordPress. It has some unique features not yet seen in other debugging plugins, including automatic AJAX debugging and the ability to narrow down things by plugin or theme.
14
 
15
  For complete information, please see [Query Monitor's GitHub repo](https://github.com/johnbillion/QueryMonitor).
16
 
@@ -27,7 +27,7 @@ Here's an overview of what's shown:
27
  * View **aggregate query information** grouped by component, calling function, and type
28
  * Super advanced: Supports **multiple instances of wpdb** on one page
29
 
30
- Filtering queries by component or calling function makes it easy to see which plugins, themes, or functions on your site are making the most (or the slowest) database queries. Query Monitor can easily tell you if your "premium" theme is doing a premium number of database queries.
31
 
32
  = Hooks =
33
 
@@ -39,13 +39,12 @@ Filtering queries by component or calling function makes it easy to see which pl
39
 
40
  * Shows the **template filename** for the current page
41
  * Shows the available **body classes** for the current page
42
- * Shows the active theme name
43
 
44
  = PHP Errors =
45
 
46
- * PHP errors (warnings, notices and stricts) are presented nicely along with their component and call stack
47
  * Shows an easily visible warning in the admin toolbar
48
- * Plays nicely with Xdebug
49
 
50
  = Request =
51
 
@@ -66,13 +65,13 @@ Filtering queries by component or calling function makes it easy to see which pl
66
 
67
  The response from any jQuery AJAX request on the page will contain various debugging information in its header that gets output to the developer console. **No hooking required**.
68
 
69
- AJAX debugging is in its early stages. Currently it only includes PHP errors (warnings, notices and stricts), but this will be built upon in future versions.
70
 
71
  = Admin Screen =
72
 
73
- Hands up who can remember the correct names for the filters and hooks for custom admin screen columns?
74
 
75
- * Shows the correct names for **custom column hooks and filters** on all admin screens that have a listing table
76
  * Shows the state of `get_current_screen()` and a few variables
77
 
78
  = Environment Information =
@@ -82,14 +81,19 @@ Hands up who can remember the correct names for the filters and hooks for custom
82
  * Shows **various MySQL information**, including caching and performance related configuration
83
  * Highlights the fact when any performance related configurations are not optimal
84
  * Shows various details about **WordPress** and the **web server**
85
- * Shows version numbers for everything
86
 
87
  = Everything Else =
88
 
89
  * Shows any **transients that were set**, along with their timeout, component, and call stack
90
  * Shows all **WordPress conditionals** on the current page, highlighted nicely
91
- * Shows an overview at the top, including page generation time and memory limit as absolute values and as % of their respective limits
92
- * You can set an authentication cookie which allows you to view Query Monitor output when you're not logged in (or if you're logged in as a non-administrator). See the bottom of Query Monitor's output for details
 
 
 
 
 
93
 
94
  == Installation ==
95
 
@@ -114,12 +118,42 @@ Alternatively, see the guide to [Manually Installing Plugins](http://codex.wordp
114
 
115
  == Frequently Asked Questions ==
116
 
117
- = There's nothing here =
 
 
 
 
 
 
 
 
118
 
119
- I know!
 
 
 
 
 
 
 
 
 
 
120
 
121
  == Changelog ==
122
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  = 2.6.2 =
124
  * Fix two fundamental stability and compatibility issues (great news)
125
  * Various visual tweaks
2
  Contributors: johnbillion
3
  Tags: debug, debugging, development, developer, performance, profiler, profiling, queries
4
  Requires at least: 3.5
5
+ Tested up to: 3.9
6
+ Stable tag: 2.6.3
7
  License: GPLv2 or later
8
 
9
  View debugging and performance information on database queries, hooks, conditionals, HTTP requests, redirects and more.
10
 
11
  == Description ==
12
 
13
+ Query Monitor is a debugging plugin for anyone developing with WordPress. It has some advanced features not available in other debugging plugins, including automatic AJAX debugging and the ability to narrow down things by plugin or theme.
14
 
15
  For complete information, please see [Query Monitor's GitHub repo](https://github.com/johnbillion/QueryMonitor).
16
 
27
  * View **aggregate query information** grouped by component, calling function, and type
28
  * Super advanced: Supports **multiple instances of wpdb** on one page
29
 
30
+ Filtering queries by component or calling function makes it easy to see which plugins, themes, or functions on your site are making the most (or the slowest) database queries.
31
 
32
  = Hooks =
33
 
39
 
40
  * Shows the **template filename** for the current page
41
  * Shows the available **body classes** for the current page
42
+ * Shows the active parent and child theme name
43
 
44
  = PHP Errors =
45
 
46
+ * PHP errors (warnings, notices, stricts, and deprecated) are presented nicely along with their component and call stack
47
  * Shows an easily visible warning in the admin toolbar
 
48
 
49
  = Request =
50
 
65
 
66
  The response from any jQuery AJAX request on the page will contain various debugging information in its header that gets output to the developer console. **No hooking required**.
67
 
68
+ AJAX debugging is in its early stages. Currently it only includes PHP errors, but this will be built upon in future versions.
69
 
70
  = Admin Screen =
71
 
72
+ Hands up who can remember the correct names for the filters and actions for custom admin screen columns?
73
 
74
+ * Shows the correct names for **custom column filters and actions** on all admin screens that have a listing table
75
  * Shows the state of `get_current_screen()` and a few variables
76
 
77
  = Environment Information =
81
  * Shows **various MySQL information**, including caching and performance related configuration
82
  * Highlights the fact when any performance related configurations are not optimal
83
  * Shows various details about **WordPress** and the **web server**
84
+ * Shows version numbers for all the things
85
 
86
  = Everything Else =
87
 
88
  * Shows any **transients that were set**, along with their timeout, component, and call stack
89
  * Shows all **WordPress conditionals** on the current page, highlighted nicely
90
+ * Shows an overview including page generation time and memory limit as absolute values and as % of their respective limits
91
+
92
+ = Authentication =
93
+
94
+ By default, Query Monitor's output is only shown to Administrators on single-site installs, and Super Admins on Multisite installs.
95
+
96
+ In addition to this, you can set an authentication cookie which allows you to view Query Monitor output when you're not logged in (or if you're logged in as a non-administrator). See the bottom of Query Monitor's output for details.
97
 
98
  == Installation ==
99
 
118
 
119
  == Frequently Asked Questions ==
120
 
121
+ = Who can see Query Monitor's output? =
122
+
123
+ By default, Query Monitor's output is only shown to Administrators on single-site installs, and Super Admins on Multisite installs.
124
+
125
+ In addition to this, you can set an authentication cookie which allows you to view Query Monitor output when you're not logged in (or if you're logged in as a non-administrator). See the bottom of Query Monitor's output for details.
126
+
127
+ = Does Query Monitor itself impact the page generation time or memory usage? =
128
+
129
+ Short answer: Yes, but only a little.
130
 
131
+ Long answer: Query Monitor has a small impact on page generation time because it hooks into a few places in WordPress in the same way that other plugins do. The impact is negligable.
132
+
133
+ On pages that have an especially high number of database queries (in the hundreds), Query Monitor currently uses more memory than I would like it to. This is due to the amount of data that is captured in the stack trace for each query. I have been and will be working to continually reduce this.
134
+
135
+ = Where can I suggest a new feature or report a bug? =
136
+
137
+ Please use [the issue tracker on Query Monitor's GitHub repo](https://github.com/johnbillion/QueryMonitor/issues) as it's easier to keep track of issues there, rather than on the wordpress.org support forums.
138
+
139
+ = Do you accept donations? =
140
+
141
+ No, I do not accept donations. If you like the plugin, I'd love for you to [leave a review](http://wordpress.org/support/view/plugin-reviews/query-monitor). Tell all your friends about the plugin too!
142
 
143
  == Changelog ==
144
 
145
+ = 2.6.3 =
146
+ * Clickable stack traces and file names if you've configured Xdebug's `file_link_format` setting
147
+ * Show the number of times each PHP error has been triggered
148
+ * Visual bugfixes when using Firefox
149
+ * Fix a bug which was preventing AJAX debugging from being output
150
+ * Fix a fatal error when using PHP 5.2 on Windows
151
+ * Display HTTP proxy information when appropriate
152
+ * Introduce the `QM_DISABLE` constant for unconditionally disabling Query Monitor
153
+ * Always return true from our PHP error handler to suppress unwanted PHP error output (eg. from Xdebug)
154
+ * Internals: Much more robust logic and even more separation of data collection and output
155
+ * Internals: Many performance improvements
156
+
157
  = 2.6.2 =
158
  * Fix two fundamental stability and compatibility issues (great news)
159
  * Various visual tweaks
wp-content/db.php CHANGED
@@ -9,7 +9,7 @@ additional database query information in Query Monitor's output.
9
 
10
  *********************************************************************
11
 
12
- Copyright 2013 John Blackbourn
13
 
14
  This program is free software; you can redistribute it and/or modify
15
  it under the terms of the GNU General Public License as published by
@@ -25,11 +25,15 @@ GNU General Public License for more details.
25
 
26
  defined( 'ABSPATH' ) or die();
27
 
 
 
 
28
  # No autoloaders for us. See https://github.com/johnbillion/QueryMonitor/issues/7
29
- foreach ( array( 'Backtrace', 'Collector', 'Plugin', 'Util' ) as $f ) {
30
- if ( ! is_readable( $file = dirname( __FILE__ ) . "/../{$f}.php" ) )
 
31
  return;
32
- require_once $file;
33
  }
34
 
35
  if ( !defined( 'SAVEQUERIES' ) )
@@ -87,17 +91,18 @@ class QueryMonitorDB extends wpdb {
87
  // Keep track of the last query for debug..
88
  $this->last_query = $query;
89
 
90
- if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES )
91
  $this->timer_start();
92
 
93
  $this->result = @mysql_query( $query, $this->dbh );
94
  $this->num_queries++;
95
 
96
- if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
 
97
  $trace = new QM_Backtrace;
98
  $q = array(
99
  'sql' => $query,
100
- 'ltime' => $this->timer_stop(),
101
  'stack' => implode( ', ', array_reverse( $trace->get_stack() ) ),
102
  'trace' => $trace,
103
  'result' => null,
@@ -111,7 +116,7 @@ class QueryMonitorDB extends wpdb {
111
 
112
  // If there is an error then take note of it..
113
  if ( $this->last_error = mysql_error( $this->dbh ) ) {
114
- if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES )
115
  $this->queries[$this->num_queries]['result'] = new WP_Error( 'qmdb', $this->last_error );
116
  // Clear insert_id on a subsequent failed insert.
117
  if ( $this->insert_id && preg_match( '/^\s*(insert|replace)\s/i', $query ) )
@@ -144,7 +149,7 @@ class QueryMonitorDB extends wpdb {
144
  $return_val = $num_rows;
145
  }
146
 
147
- if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES )
148
  $this->queries[$this->num_queries]['result'] = $return_val;
149
 
150
  return $return_val;
9
 
10
  *********************************************************************
11
 
12
+ Copyright 2014 John Blackbourn
13
 
14
  This program is free software; you can redistribute it and/or modify
15
  it under the terms of the GNU General Public License as published by
25
 
26
  defined( 'ABSPATH' ) or die();
27
 
28
+ if ( defined( 'QM_DISABLED' ) and QM_DISABLED )
29
+ return;
30
+
31
  # No autoloaders for us. See https://github.com/johnbillion/QueryMonitor/issues/7
32
+ $qm_dir = dirname( dirname( __FILE__ ) );
33
+ foreach ( array( 'Backtrace', 'Collector', 'Plugin', 'Util' ) as $qm_class ) {
34
+ if ( ! is_readable( $qm_file = "{$qm_dir}/{$qm_class}.php" ) )
35
  return;
36
+ require_once $qm_file;
37
  }
38
 
39
  if ( !defined( 'SAVEQUERIES' ) )
91
  // Keep track of the last query for debug..
92
  $this->last_query = $query;
93
 
94
+ if ( SAVEQUERIES )
95
  $this->timer_start();
96
 
97
  $this->result = @mysql_query( $query, $this->dbh );
98
  $this->num_queries++;
99
 
100
+ if ( SAVEQUERIES ) {
101
+ $ltime = $this->timer_stop();
102
  $trace = new QM_Backtrace;
103
  $q = array(
104
  'sql' => $query,
105
+ 'ltime' => $ltime,
106
  'stack' => implode( ', ', array_reverse( $trace->get_stack() ) ),
107
  'trace' => $trace,
108
  'result' => null,
116
 
117
  // If there is an error then take note of it..
118
  if ( $this->last_error = mysql_error( $this->dbh ) ) {
119
+ if ( SAVEQUERIES )
120
  $this->queries[$this->num_queries]['result'] = new WP_Error( 'qmdb', $this->last_error );
121
  // Clear insert_id on a subsequent failed insert.
122
  if ( $this->insert_id && preg_match( '/^\s*(insert|replace)\s/i', $query ) )
149
  $return_val = $num_rows;
150
  }
151
 
152
+ if ( SAVEQUERIES )
153
  $this->queries[$this->num_queries]['result'] = $return_val;
154
 
155
  return $return_val;