P3 (Plugin Performance Profiler) - Version 1.2.0

Version Description

Many compatibility fixes based on user feedback. Upgrading is recommended.

Download this release

Release Info

Developer StarfieldTech
Plugin Icon wp plugin P3 (Plugin Performance Profiler)
Version 1.2.0
Comparing to
See all releases

Code changes from version 1.1.3 to 1.2.0

.profiling_enabled DELETED
@@ -1 +0,0 @@
1
- []
 
class.p3-profile-reader.php CHANGED
@@ -188,7 +188,7 @@ if ( !defined('P3_PATH') )
188
 
189
  // Check for empty data
190
  if ( empty( $this->_data ) ) {
191
- throw new P3_Profile_No_Data_Exception('No visits in this profile. Check the IP address you\'re scanning from.');
192
  }
193
 
194
  foreach ( $this->_data as $o ) {
@@ -257,7 +257,7 @@ if ( !defined('P3_PATH') )
257
  }
258
  $this->averages = array(
259
  'total' => $this->total_time / $this->visits,
260
- 'site' => ( $this->total_time - $this->profile_time) / $this->visits,
261
  'core' => $this->core_time / $this->visits,
262
  'plugins' => $this->plugin_time / $this->visits,
263
  'profile' => $this->profile_time / $this->visits,
188
 
189
  // Check for empty data
190
  if ( empty( $this->_data ) ) {
191
+ throw new P3_Profile_No_Data_Exception('No visits recorded during this profiling session.');
192
  }
193
 
194
  foreach ( $this->_data as $o ) {
257
  }
258
  $this->averages = array(
259
  'total' => $this->total_time / $this->visits,
260
+ 'site' => ( $this->total_time - $this->profile_time ) / $this->visits,
261
  'core' => $this->core_time / $this->visits,
262
  'plugins' => $this->plugin_time / $this->visits,
263
  'profile' => $this->profile_time / $this->visits,
class.p3-profiler.php CHANGED
@@ -88,10 +88,10 @@ class P3_Profiler {
88
  private $_P3_PATH = ''; // Cannot rely on P3_PATH, may be instantiated before the plugin
89
 
90
  /**
91
- * Path to the ".profiling_enabled" flag file
92
- * @var string
93
  */
94
- private $_P3_FLAG_FILE = '';
95
 
96
  /**
97
  * Last stack should be marked as plugin time
@@ -121,30 +121,53 @@ class P3_Profiler {
121
 
122
  // Set up paths
123
  $this->_P3_PATH = realpath( dirname( __FILE__ ) );
124
- $this->_P3_FLAG_FILE = $this->_P3_PATH . DIRECTORY_SEPARATOR . '.profiling_enabled';
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
  // Check to see if we should profile
127
- $p3_json = ( file_exists( $this->_P3_FLAG_FILE ) ? json_decode( file_get_contents( $this->_P3_FLAG_FILE ) ) : null );
128
- if ( empty( $p3_json ) ) {
129
- return $this;
130
- }
131
- $found = false;
132
- foreach ( (array) $p3_json as $v ) {
133
- if ( 0 === strpos( $_SERVER['REQUEST_URI'], $v->site_url ) && preg_match( '/' . $v->ip . '/', $this->get_ip() ) ) {
134
- $found = true;
135
- break;
 
136
  }
137
  }
138
- if ( !$found ) {
139
- return $this;
 
 
140
  }
141
 
 
 
 
 
 
 
 
 
142
  // Kludge memory limit / time limit
143
  @ini_set( 'memory_limit', '128M' );
144
  @set_time_limit( 90 );
145
 
146
  // Set the profile file
147
- $this->_profile_filename = $v->name . '.json';
148
 
149
  // Start timing
150
  $this->_start_time = microtime( true );
@@ -159,35 +182,42 @@ class P3_Profiler {
159
  $this->_last_call_category = self::CATEGORY_CORE;
160
  $this->_last_stack = array();
161
 
162
- // Add a global flag to let everyone know we're profiling
163
- define( 'WPP_PROFILING_STARTED', true );
164
-
165
  // Add some startup information
166
  $this->_profile = array(
167
  'url' => $this->_get_url(),
168
- 'ip' => ( array_key_exists( 'HTTP_X_FORWARDED_FOR', $_SERVER ) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'] ),
169
  'pid' => getmypid(),
170
  'date' => @date( 'c' ),
171
  'stack' => array()
172
  );
173
 
174
- // Clear any opcode caches, the optimization / caching from these can
175
- // hide calls from the tick handler and backtraces
176
- if ( $v->disable_opcode_cache ) {
177
- if ( extension_loaded( 'xcache' ) && function_exists( 'xcache_clear_cache' ) && !ini_get( 'xcache.admin.enable_auth' ) ) {
178
- for ( $i = 0 ; $i < xcache_count( XC_TYPE_PHP ); $i++ ) {
179
- xcache_clear_cache( XC_TYPE_PHP, 0 );
180
- }
181
- } elseif ( extension_loaded( 'apc' ) && function_exists( 'apc_clear_cache' ) ) {
182
  apc_clear_cache();
183
- } elseif ( extension_loaded( 'eaccelerator' ) && function_exists( 'eaccelerator_clean' ) ) {
184
- @eaccelerator_clean();
 
 
 
 
 
 
185
  }
 
 
 
186
  }
187
 
188
  // Monitor all function-calls
189
  declare( ticks = 1 );
190
  register_tick_function( array( $this, 'tick_handler' ) );
 
191
  }
192
 
193
  /**
@@ -196,21 +226,12 @@ class P3_Profiler {
196
  * @return void
197
  */
198
  public function tick_handler() {
199
- static $theme_files_cache = array(); // Cache for theme files
200
- static $actions_hooked = false;
201
- static $themes_folder = 'themes';
202
- static $content_folder = 'wp-content'; // Guess, if it's not defined
203
- static $folder_flag = false;
204
- static $in_wp = false;
205
-
206
- // See if we're in WP
207
- $in_wp = ($in_wp || defined( 'WP_USE_THEMES' ) || defined( 'DOING_CRON' ) || defined( 'WP_ADMIN' ));
208
-
209
- // Set the content folder
210
- if ( !$folder_flag && defined( 'WP_CONTENT_DIR' ) ) {
211
  $content_folder = basename( WP_CONTENT_DIR );
212
- $folder_flag = true;
213
  }
 
214
 
215
  // Start timing time spent in the profiler
216
  $start = microtime( true );
@@ -218,23 +239,6 @@ class P3_Profiler {
218
  // Calculate the last call time
219
  $this->_last_call_time = ( $start - $this->_last_call_start );
220
 
221
- // Don't profile in non-WP scripts
222
- if ( !$in_wp && !$this->_is_a_plugin_file( $_SERVER['SCRIPT_FILENAME'] ) ) {
223
- $tmp = microtime( true );
224
- $this->_runtime += ( $tmp - $start );
225
- $this->_last_call_start = $tmp;
226
- return;
227
- }
228
-
229
- // Hook actions
230
- if ( !$actions_hooked && function_exists( 'add_action' ) ) {
231
- // Hook the shutdown action to save the profile when we're done
232
- add_action( 'shutdown', array( $this, 'shutdown_handler' ) );
233
-
234
- // Don't re-hook again
235
- $actions_hooked = true;
236
- }
237
-
238
  // If we had a stack in the queue, track the runtime, and write it to the log
239
  // array() !== $this->_last_stack is slightly faster than !empty( $this->_last_stack )
240
  // which is important since this is called on every tick
@@ -258,10 +262,12 @@ class P3_Profiler {
258
 
259
  // Examine the current stack, see if we should track it. It should be
260
  // related to a plugin file if we're going to track it
261
- if ( defined( 'DEBUG_BACKTRACE_IGNORE_ARGS' ) ) {
 
 
262
  $bt = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT );
263
  } else {
264
- $bt = debug_backtrace( true );
265
  }
266
 
267
  // Find our function
@@ -269,6 +275,10 @@ class P3_Profiler {
269
  if ( count( $bt ) >= 2 ) {
270
  $frame = $bt[1];
271
  }
 
 
 
 
272
 
273
  // Include/require
274
  if ( in_array( strtolower( $frame['function'] ), array( 'include', 'require', 'include_once', 'require_once' ) ) ) {
@@ -300,7 +310,7 @@ class P3_Profiler {
300
 
301
  // Lambdas / closures
302
  } elseif ( '__lambda_func' == $frame['function'] || '{closure}' == $frame['function'] ) {
303
- $file = preg_replace( '/\(\d+\)\s+:\s+runtime-created function/', '', $bt[0]['file'] );
304
 
305
  // Files, no other hints
306
  } elseif ( isset( $frame['file'] ) ) {
@@ -316,8 +326,6 @@ class P3_Profiler {
316
  list($file, $junk) = explode(': eval(', $str, 2);
317
  $file = preg_replace('/\(\d*\)$/', '', $file);
318
  }
319
-
320
- unset( $bt );
321
 
322
  // Is it a plugin?
323
  $plugin = $this->_is_a_plugin_file( $file );
@@ -383,7 +391,7 @@ class P3_Profiler {
383
  static $folder_flag = false;
384
 
385
  // Set the plugins folder
386
- if ( !$folder_flag && defined( 'WPMU_PLUGIN_DIR' ) ) {
387
  $plugins_folder = basename( WP_PLUGIN_DIR );
388
  $muplugins_folder = basename( WPMU_PLUGIN_DIR );
389
  $content_folder = basename( WP_CONTENT_DIR );
@@ -418,7 +426,7 @@ class P3_Profiler {
418
  static $folder_flag = false;
419
 
420
  // Set the plugins folder
421
- if ( !$folder_flag && defined( 'WP_PLUGIN_DIR' ) ) {
422
  $plugins_folder = basename( WP_PLUGIN_DIR );
423
  $muplugins_folder = basename( WPMU_PLUGIN_DIR );
424
  $content_folder = basename( WP_CONTENT_DIR );
@@ -477,6 +485,11 @@ class P3_Profiler {
477
  */
478
  public function shutdown_handler() {
479
 
 
 
 
 
 
480
  // Make sure we've actually started ( wp-cron??)
481
  if ( !defined( 'WPP_PROFILING_STARTED' ) || !WPP_PROFILING_STARTED ) {
482
  return;
@@ -576,23 +589,7 @@ class P3_Profiler {
576
  // previous profiles
577
  $uploads_dir = wp_upload_dir();
578
  $path = $uploads_dir['basedir'] . DIRECTORY_SEPARATOR . 'profiles' . DIRECTORY_SEPARATOR . $this->_profile_filename;
579
- $fp = fopen( $path, 'a+' );
580
- $wait = 30; // Wait 30 iterations ( 3 seconds )
581
- while ( !flock( $fp, LOCK_EX ) && $wait-- ) {
582
- usleep( 100 * 1000 );
583
- }
584
-
585
- // If we've waited too long, bail, don't add this profile, there's too
586
- // much traffic
587
- if ( $wait <= 0 ) {
588
- return;
589
- }
590
-
591
- fwrite( $fp, json_encode( $this->_profile ) . PHP_EOL );
592
-
593
- // Release the lock and close the file
594
- flock( $fp, LOCK_UN );
595
- fclose( $fp );
596
  }
597
 
598
  /**
@@ -600,6 +597,10 @@ class P3_Profiler {
600
  * @return string
601
  */
602
  private function _get_url() {
 
 
 
 
603
  $protocol = 'http://';
604
  if ( ( !empty( $_SERVER['HTTPS'] ) && 'on' == strtolower( $_SERVER['HTTPS'] ) ) || 443 == $_SERVER['SERVER_PORT'] ) {
605
  $protocol = 'https://';
@@ -625,7 +626,8 @@ class P3_Profiler {
625
  $query_string = '?' . preg_replace( '/[?&]P3_NOCACHE=[a-zA-Z0-9]+/', '', $_SERVER['QUERY_STRING'] );
626
  }
627
  }
628
- return $protocol.$domain.$file.$path.$query_string;
 
629
  }
630
 
631
  /**
@@ -638,11 +640,35 @@ class P3_Profiler {
638
  return $ip;
639
  } else {
640
  if ( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
641
- $ip = filter_var( $_SERVER['HTTP_X_FORWARDED_FOR'], FILTER_SANITIZE_STRING );
 
 
642
  } else {
643
- $ip = filter_var( $_SERVER['REMOTE_ADDR'], FILTER_SANITIZE_STRING );
644
  }
645
  return $ip;
646
  }
647
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
648
  }
88
  private $_P3_PATH = ''; // Cannot rely on P3_PATH, may be instantiated before the plugin
89
 
90
  /**
91
+ * Debug log entry
92
+ * @var array
93
  */
94
+ private $_debug_entry = array();
95
 
96
  /**
97
  * Last stack should be marked as plugin time
121
 
122
  // Set up paths
123
  $this->_P3_PATH = realpath( dirname( __FILE__ ) );
124
+
125
+ // Debug mode
126
+ $this->_debug_entry = array(
127
+ 'profiling_enabled' => false,
128
+ 'recording_ip' => '',
129
+ 'scan_name' => '',
130
+ 'recording' => false,
131
+ 'disable_optimizers' => false,
132
+ 'url' => $this->_get_url(),
133
+ 'visitor_ip' => $this->get_ip(),
134
+ 'time' => time(),
135
+ 'pid' => getmypid()
136
+ );
137
 
138
  // Check to see if we should profile
139
+ $opts = array();
140
+ if ( function_exists( 'get_option') ) {
141
+ $opts = get_option('p3-profiler_profiling_enabled');
142
+ if ( !empty( $opts ) ) {
143
+ if ( isset( $this->_debug_entry ) ) {
144
+ $this->_debug_entry['profiling_enabled'] = true;
145
+ $this->_debug_entry['scan_name'] = $opts['name'];
146
+ $this->_debug_entry['recording_ip'] = $opts['ip'];
147
+ $this->_debug_entry['disable_optimizers'] = $opts['disable_opcode_cache'];
148
+ }
149
  }
150
  }
151
+
152
+ // Add a global flag to let everyone know we're profiling
153
+ if ( !empty( $opts ) && preg_match( '/' . $opts['ip'] . '/', $this->get_ip() ) ) {
154
+ define( 'WPP_PROFILING_STARTED', true );
155
  }
156
 
157
+ // Save the debug info
158
+ $this->_debug_entry['recording'] = defined( 'WPP_PROFILING_STARTED' );
159
+
160
+ // Check the profiling flag
161
+ if ( !defined( 'WPP_PROFILING_STARTED' ) ) {
162
+ return $this;
163
+ }
164
+
165
  // Kludge memory limit / time limit
166
  @ini_set( 'memory_limit', '128M' );
167
  @set_time_limit( 90 );
168
 
169
  // Set the profile file
170
+ $this->_profile_filename = $opts['name'] . '.json';
171
 
172
  // Start timing
173
  $this->_start_time = microtime( true );
182
  $this->_last_call_category = self::CATEGORY_CORE;
183
  $this->_last_stack = array();
184
 
 
 
 
185
  // Add some startup information
186
  $this->_profile = array(
187
  'url' => $this->_get_url(),
188
+ 'ip' => $this->get_ip(),
189
  'pid' => getmypid(),
190
  'date' => @date( 'c' ),
191
  'stack' => array()
192
  );
193
 
194
+ // Disable opcode optimizers. These "optimize" calls out of the stack
195
+ // and hide calls from the tick handler and backtraces
196
+ if ( $opts['disable_opcode_cache'] ) {
197
+ if ( extension_loaded( 'xcache' ) ) {
198
+ @ini_set( 'xcache.optimizer', false ); // Will be implemented in 2.0, here for future proofing
199
+ // XCache seems to do some optimizing, anyway. The recorded stack size is smaller with xcache.cacher enabled than without.
200
+ } elseif ( extension_loaded( 'apc' ) ) {
201
+ @ini_set( 'apc.optimization', 0 ); // Removed in APC 3.0.13 (2007-02-24)
202
  apc_clear_cache();
203
+ } elseif ( extension_loaded( 'eaccelerator' ) ) {
204
+ @ini_set( 'eaccelerator.optimizer', 0 );
205
+ if ( function_exists( 'eaccelerator_optimizer' ) ) {
206
+ @eaccelerator_optimizer( false );
207
+ }
208
+ // If you're reading this, try setting eaccelerator.optimizer = 0 in a .user.ini or .htaccess file
209
+ } elseif (extension_loaded( 'Zend Optimizer+' ) ) {
210
+ @ini_set('zend_optimizerplus.optimization_level', 0);
211
  }
212
+ // Tested with wincache
213
+ // Tested with ioncube
214
+ // Tested with zend guard loader
215
  }
216
 
217
  // Monitor all function-calls
218
  declare( ticks = 1 );
219
  register_tick_function( array( $this, 'tick_handler' ) );
220
+ add_action( 'shutdown', array( $this, 'shutdown_handler' ) );
221
  }
222
 
223
  /**
226
  * @return void
227
  */
228
  public function tick_handler() {
229
+ static $theme_files_cache = array(); // Cache for theme files
230
+ static $content_folder = '';
231
+ if ( empty( $content_folder ) ) {
 
 
 
 
 
 
 
 
 
232
  $content_folder = basename( WP_CONTENT_DIR );
 
233
  }
234
+ $themes_folder = 'themes';
235
 
236
  // Start timing time spent in the profiler
237
  $start = microtime( true );
239
  // Calculate the last call time
240
  $this->_last_call_time = ( $start - $this->_last_call_start );
241
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  // If we had a stack in the queue, track the runtime, and write it to the log
243
  // array() !== $this->_last_stack is slightly faster than !empty( $this->_last_stack )
244
  // which is important since this is called on every tick
262
 
263
  // Examine the current stack, see if we should track it. It should be
264
  // related to a plugin file if we're going to track it
265
+ if ( version_compare( PHP_VERSION, '5.3.6' ) < 0 ) {
266
+ $bt = debug_backtrace( true );
267
+ } elseif ( version_compare( PHP_VERSION, '5.4.0' ) < 0 ) {
268
  $bt = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT );
269
  } else {
270
+ $bt = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT, 2 ); // Examine the last 2 frames
271
  }
272
 
273
  // Find our function
275
  if ( count( $bt ) >= 2 ) {
276
  $frame = $bt[1];
277
  }
278
+ $lambda_file = @$bt[0]['file'];
279
+
280
+ // Free up memory
281
+ unset( $bt );
282
 
283
  // Include/require
284
  if ( in_array( strtolower( $frame['function'] ), array( 'include', 'require', 'include_once', 'require_once' ) ) ) {
310
 
311
  // Lambdas / closures
312
  } elseif ( '__lambda_func' == $frame['function'] || '{closure}' == $frame['function'] ) {
313
+ $file = preg_replace( '/\(\d+\)\s+:\s+runtime-created function/', '', $lambda_file );
314
 
315
  // Files, no other hints
316
  } elseif ( isset( $frame['file'] ) ) {
326
  list($file, $junk) = explode(': eval(', $str, 2);
327
  $file = preg_replace('/\(\d*\)$/', '', $file);
328
  }
 
 
329
 
330
  // Is it a plugin?
331
  $plugin = $this->_is_a_plugin_file( $file );
391
  static $folder_flag = false;
392
 
393
  // Set the plugins folder
394
+ if ( !$folder_flag ) {
395
  $plugins_folder = basename( WP_PLUGIN_DIR );
396
  $muplugins_folder = basename( WPMU_PLUGIN_DIR );
397
  $content_folder = basename( WP_CONTENT_DIR );
426
  static $folder_flag = false;
427
 
428
  // Set the plugins folder
429
+ if ( !$folder_flag ) {
430
  $plugins_folder = basename( WP_PLUGIN_DIR );
431
  $muplugins_folder = basename( WPMU_PLUGIN_DIR );
432
  $content_folder = basename( WP_CONTENT_DIR );
485
  */
486
  public function shutdown_handler() {
487
 
488
+ // Write debug log
489
+ if ( get_option( 'p3-profiler_debug' ) ) {
490
+ $this->_write_debug_log();
491
+ }
492
+
493
  // Make sure we've actually started ( wp-cron??)
494
  if ( !defined( 'WPP_PROFILING_STARTED' ) || !WPP_PROFILING_STARTED ) {
495
  return;
589
  // previous profiles
590
  $uploads_dir = wp_upload_dir();
591
  $path = $uploads_dir['basedir'] . DIRECTORY_SEPARATOR . 'profiles' . DIRECTORY_SEPARATOR . $this->_profile_filename;
592
+ file_put_contents( $path, json_encode( $this->_profile ) . PHP_EOL, FILE_APPEND );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
593
  }
594
 
595
  /**
597
  * @return string
598
  */
599
  private function _get_url() {
600
+ static $url = '';
601
+ if ( !empty( $url ) ) {
602
+ return $url;
603
+ }
604
  $protocol = 'http://';
605
  if ( ( !empty( $_SERVER['HTTPS'] ) && 'on' == strtolower( $_SERVER['HTTPS'] ) ) || 443 == $_SERVER['SERVER_PORT'] ) {
606
  $protocol = 'https://';
626
  $query_string = '?' . preg_replace( '/[?&]P3_NOCACHE=[a-zA-Z0-9]+/', '', $_SERVER['QUERY_STRING'] );
627
  }
628
  }
629
+ $url = $protocol.$domain.$file.$path.$query_string;
630
+ return $url;
631
  }
632
 
633
  /**
640
  return $ip;
641
  } else {
642
  if ( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
643
+ $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
644
+ } elseif ( !empty ( $_SERVER['HTTP_X_REAL_IP'] ) ) {
645
+ $ip = $_SERVER['HTTP_X_REAL_IP'];
646
  } else {
647
+ $ip = $_SERVER['REMOTE_ADDR'];
648
  }
649
  return $ip;
650
  }
651
  }
652
+
653
+ /**
654
+ * Disable debug mode
655
+ */
656
+ private function _write_debug_log() {
657
+
658
+ // Get the existing log
659
+ $debug_log = get_option( 'p3-profiler_debug_log' );
660
+ if ( empty( $debug_log) ) {
661
+ $debug_log = array();
662
+ }
663
+
664
+ // Prepend this entry
665
+ array_unshift( $debug_log, $this->_debug_entry );
666
+ if ( count( $debug_log ) >= 100 ) {
667
+ $debug_log = array_slice( $debug_log, 0, 100 );
668
+ update_option( 'p3-profiler_debug', false );
669
+ }
670
+
671
+ // Write the log
672
+ update_option( 'p3-profiler_debug_log', $debug_log );
673
+ }
674
  }
p3-profiler.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: P3 (Plugin Performance Profiler)
4
  Plugin URI: http://support.godaddy.com/godaddy/wordpress-p3-plugin/
5
  Description: See which plugins are slowing down your site. Create a profile of your WordPress site's plugins' performance by measuring their impact on your site's load time.
6
  Author: GoDaddy.com
7
- Version: 1.1.3
8
  Author URI: http://www.godaddy.com/
9
  */
10
 
@@ -19,9 +19,6 @@ if ( !defined( 'ABSPATH') )
19
  // Shortcut for knowing our path
20
  define( 'P3_PATH', realpath( dirname( __FILE__ ) ) );
21
 
22
- // Flag file for enabling profile mode
23
- define( 'P3_FLAG_FILE', P3_PATH . DIRECTORY_SEPARATOR . '.profiling_enabled' );
24
-
25
  // Directory for profiles
26
  $uploads_dir = wp_upload_dir();
27
  define( 'P3_PROFILES_PATH', $uploads_dir['basedir'] . DIRECTORY_SEPARATOR . 'profiles' );
@@ -50,6 +47,9 @@ if ( is_admin() ) {
50
  // Upgrade routine
51
  add_action( 'admin_init', array( $p3_profiler_plugin, 'upgrade' ) );
52
 
 
 
 
53
  // Ajax actions
54
  add_action( 'wp_ajax_p3_start_scan', array( $p3_profiler_plugin, 'ajax_start_scan' ) );
55
  add_action( 'wp_ajax_p3_stop_scan', array( $p3_profiler_plugin, 'ajax_stop_scan' ) );
@@ -117,7 +117,7 @@ class P3_Profiler_Plugin {
117
  */
118
  public function remove_admin_bar() {
119
  if ( !is_admin() && is_user_logged_in() ) {
120
- remove_action( 'wp_footer', 'wp_admin_bar_render', 1000 );
121
  if ( true === force_ssl_admin() ) {
122
  add_filter( 'site_url', array( $this, '_fix_url' ) );
123
  add_filter( 'admin_url', array( $this, '_fix_url' ) );
@@ -212,15 +212,11 @@ class P3_Profiler_Plugin {
212
  wp_enqueue_style( 'p3_qtip_css', plugins_url() . '/p3-profiler/css/jquery.qtip.min.css' );
213
  wp_enqueue_style( 'p3_css', plugins_url() . '/p3-profiler/css/p3.css' );
214
  }
215
-
216
  /**
217
- * Load the necessary resources
218
- * @uses wp_enqueue_script
219
- * @uses jquery, jquery-ui, jquery.corners
220
- * @uses flot, flot.pie
221
- * @return void
222
  */
223
- public function early_init() {
224
 
225
  // Only for our page
226
  if ( isset( $_REQUEST['page'] ) && basename( __FILE__ ) == $_REQUEST['page'] ) {
@@ -242,13 +238,36 @@ class P3_Profiler_Plugin {
242
  }
243
  $this->scan = P3_PROFILES_PATH . "/{$this->scan}";
244
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
 
246
  // If there's a scan, create a viewer object
247
  if ( !empty( $this->scan ) ) {
248
  try {
249
  $this->profile = new P3_Profile_Reader( $this->scan );
250
  } catch ( P3_Profile_No_Data_Exception $e ) {
251
- echo '<div class="error"><p>' . $e->getMessage() . '</p></div>';
 
 
252
  $this->scan = null;
253
  $this->profile = null;
254
  $this->action = 'list-scans';
@@ -289,9 +308,6 @@ class P3_Profiler_Plugin {
289
  case 'start-scan' :
290
  $this->start_scan();
291
  break;
292
- case 'fix-flag-file' :
293
- $this->fix_flag_file();
294
- break;
295
  case 'help' :
296
  $this->show_help();
297
  break;
@@ -301,62 +317,11 @@ class P3_Profiler_Plugin {
301
  }
302
 
303
  /**
304
- * Explain why P3 is asking for FTP credentials
305
  * @return string
306
  */
307
- public function fix_flag_file_help() {
308
- ?>
309
- <div class="wrap">
310
- <strong>Why am I being asked for this information?</strong>
311
- <blockquote>
312
- P3 cannot write to this file:<br />
313
- <code><?php echo P3_FLAG_FILE; ?></code>
314
- <br />
315
- P3 needs to write to this file to toggle profiling for your site.
316
- If you want to fix this manually, please ensure the file is readable
317
- and writable by the web server.
318
- </blockquote>
319
- <div class="updated">
320
- <p>P3 does <strong>not</strong> store or re-transmit this information.</p>
321
- </div>
322
- </div>
323
- <?php
324
- }
325
-
326
- /**
327
- * Write .profiling_enabled file, uses request_filesystem_credentials, if
328
- * necessary, to create the file and make it writable
329
- * @return void
330
- */
331
- public function fix_flag_file() {
332
-
333
- // Don't force a specific file system method
334
- $method = '';
335
-
336
- // Define any extra pass-thru fields (none)
337
- $form_fields = array();
338
-
339
- // Define the URL to post back to (this one)
340
- $url = wp_nonce_url( add_query_arg( array( 'p3_action' => 'fix-flag-file' ) ), 'p3-fix-flag-file' );
341
-
342
- // Ask for credentials, if necessary
343
- if ( false === ( $creds = request_filesystem_credentials( $url, $method, false, false, $form_fields ) ) ) {
344
- $this->fix_flag_file_help();
345
- return true;
346
- } elseif ( ! WP_Filesystem($creds) ) {
347
- // The credentials are bad, ask again
348
- request_filesystem_credentials( $url, $method, true, false, $form_fields );
349
- $this->fix_flag_file_help();
350
- return true;
351
- } else {
352
- // Once we get here, we should have credentials, do the file system operations
353
- global $wp_filesystem;
354
- if ( $wp_filesystem->put_contents( $wp_filesystem->wp_plugins_dir() . '/p3-profiler/.profiling_enabled' , '[]', FS_CHMOD_FILE | 0222) ) {
355
- include_once P3_PATH . '/templates/template.php';
356
- } else {
357
- wp_die( 'Error saving file!' );
358
- }
359
- }
360
  }
361
 
362
  /**
@@ -368,14 +333,26 @@ class P3_Profiler_Plugin {
368
  // Start off the scan with the home page
369
  $pages = array( get_home_url() ); // Home page
370
 
371
- // Get the default RSS feed
372
- $pages[] = get_feed_link();
 
373
 
374
- // Search for 'e'
375
- $pages[] = home_url( '?s=e' );
 
 
 
 
376
 
377
- // Get the latest 10 posts
378
- $tmp = preg_split( '/\s+/', wp_get_archives( 'type=postbypost&limit=10&echo=0' ) );
 
 
 
 
 
 
 
379
  if ( !empty( $tmp ) ) {
380
  foreach ( $tmp as $page ) {
381
  if ( preg_match( "/href='([^']+)'/", $page, $matches ) ) {
@@ -413,38 +390,24 @@ class P3_Profiler_Plugin {
413
  // Sanitize the file name
414
  $filename = sanitize_file_name( basename( $_POST['p3_scan_name'] ) );
415
 
416
- // Create flag file
417
- if ( file_exists( P3_FLAG_FILE ) ) {
418
- $json = json_decode( file_get_contents( P3_FLAG_FILE ) );
419
- } else {
420
- $json = array();
421
- }
422
-
423
- // Site url
424
- $site_url = parse_url( get_home_url(), PHP_URL_PATH );
425
- if ( null === $site_url ) {
426
- $site_url = '/';
427
- }
428
-
429
  // Add the entry ( multisite installs can run more than one concurrent profile )
430
- $json[] = array(
431
  'ip' => stripslashes( $_POST['p3_ip'] ),
432
  'disable_opcode_cache' => ( 'true' == $_POST['p3_disable_opcode_cache'] ),
433
- 'site_url' => $site_url,
434
  'name' => $filename,
435
  );
436
 
437
- $flag1 = file_put_contents( P3_FLAG_FILE, json_encode( $json ) );
438
-
439
  // Kick start the profile file
440
  if ( !file_exists( P3_PROFILES_PATH . "/$filename.json" ) ) {
441
- $flag2 = file_put_contents( P3_PROFILES_PATH . "/$filename.json", '' );
442
  } else {
443
- $flag2 = true;
444
  }
445
 
446
  // Check if either operation failed
447
- if ( false === $flag1 & $flag2 ) {
448
  wp_die( 0 );
449
  } else {
450
  echo 1;
@@ -463,37 +426,16 @@ class P3_Profiler_Plugin {
463
  wp_die( 'Invalid nonce' );
464
  }
465
 
466
- // If there's no file, return an error
467
- if ( !file_exists( P3_FLAG_FILE ) ) {
468
- wp_die( 0 );
469
- }
470
-
471
- // Get the file
472
- $json = json_decode( file_get_contents( P3_FLAG_FILE ) );
473
-
474
- // Stop all sites who match the current site's URL
475
- $site_url = parse_url( get_home_url(), PHP_URL_PATH );
476
- if ( null === $site_url ) {
477
- $site_url = '/';
478
- }
479
- foreach ( (array) $json as $k => $v ) {
480
- if ( $site_url == $v->site_url ) {
481
- unset( $json[$k] );
482
- }
483
- }
484
-
485
- // Rewrite the file
486
- $flag = file_put_contents( P3_FLAG_FILE, json_encode( $json ) );
487
- if ( !$flag ) {
488
- wp_die( 0 );
489
- }
490
 
491
  // Tell the user what happened
492
  $this->add_notice( 'Turned off performance scanning.' );
493
 
494
  // Return the last filename
495
- if ( !empty( $v ) && is_object( $v ) && property_exists( $v, 'name' ) ) {
496
- echo $v->name . '.json';
497
  die();
498
  } else {
499
  wp_die( 0 );
@@ -516,7 +458,16 @@ class P3_Profiler_Plugin {
516
  update_option( 'p3-profiler_cache_buster', 'true' == $_POST['p3_cache_buster'] );
517
  update_option( 'p3-profiler_use_current_ip', 'true' == $_POST['p3_use_current_ip'] );
518
  update_option( 'p3-profiler_ip_address', $_POST['p3_ip_address'] );
519
-
 
 
 
 
 
 
 
 
 
520
  die( '1' );
521
  }
522
 
@@ -539,9 +490,7 @@ class P3_Profiler_Plugin {
539
  // Check fields
540
  $to = sanitize_email( $_POST['p3_to'] );
541
  $from = sanitize_email( $_POST['p3_from'] );
542
- $subject = filter_var(
543
- $_POST['p3_subject'], FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_LOW
544
- );
545
  $message = strip_tags( $_POST['p3_message'] );
546
  $results = strip_tags( $_POST['p3_results'] );
547
 
@@ -590,6 +539,63 @@ class P3_Profiler_Plugin {
590
  include_once P3_PATH . '/templates/template.php';
591
  }
592
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
593
 
594
  /**************************************************************/
595
  /** HISTORY PAGE **/
@@ -679,12 +685,6 @@ class P3_Profiler_Plugin {
679
  * @return voide
680
  */
681
  public function show_notices() {
682
-
683
- // Skip notices if we're fixing the flag file
684
- if ( 'fix-flag-file' == $this->action ) {
685
- return true;
686
- }
687
-
688
  $notices = get_transient( 'p3_notices' );
689
  if ( !empty( $notices ) ) {
690
  $notices = array_unique( $notices );
@@ -696,16 +696,6 @@ class P3_Profiler_Plugin {
696
  if ( false !== $this->scan_enabled() ) {
697
  echo '<div class="updated"><p>Performance scanning is enabled.</p></div>';
698
  }
699
-
700
- // Check that we can write .profiling_enabled
701
- if ( isset( $_REQUEST['page'] ) && basename( __FILE__ ) == $_REQUEST['page'] && 'fix-flag-file' != $this->action ) {
702
- if ( !file_exists( P3_FLAG_FILE ) || !is_writable( P3_FLAG_FILE ) ) {
703
- @touch( P3_FLAG_FILE );
704
- if ( !file_exists( P3_FLAG_FILE ) || !is_writable( P3_FLAG_FILE ) ) {
705
- echo '<div class="error"><p>Cannot set profile flag file <input type="button" onclick="location.href=\'' . add_query_arg( array( 'p3_action' => 'fix-flag-file' ) ) . '\';" class="button" value="click here to fix" /></p></div>';
706
- }
707
- }
708
- }
709
  }
710
 
711
  /**
@@ -723,22 +713,8 @@ class P3_Profiler_Plugin {
723
  die( '<strong>P3</strong> requires WordPress 3.3 or later' );
724
  }
725
 
726
-
727
- $sapi = strtolower( php_sapi_name() );
728
-
729
- // .htaccess for mod_php
730
- if ( 'apache2handler' == $sapi ) {
731
- insert_with_markers(
732
- ABSPATH . '/.htaccess',
733
- 'p3-profiler',
734
- array( 'php_value auto_prepend_file "' . P3_PATH . DIRECTORY_SEPARATOR . 'start-profile.php"' )
735
- );
736
- }
737
-
738
- // Always try to create the mu-plugin loader in case either of the above methods fail
739
-
740
  // mu-plugins doesn't exist
741
- if ( !file_exists( WPMU_PLUGIN_DIR ) && is_writable( WPMU_PLUGIN_DIR . '/../' ) ) {
742
  wp_mkdir_p( WPMU_PLUGIN_DIR );
743
  }
744
  if ( file_exists( WPMU_PLUGIN_DIR ) && is_writable( WPMU_PLUGIN_DIR ) ) {
@@ -788,12 +764,12 @@ class P3_Profiler_Plugin {
788
  * @return void
789
  */
790
  public function deactivate() {
 
791
 
792
- // Remove any .htaccess modifications
793
- $file = ABSPATH . '/.htaccess';
794
- if ( file_exists( $file ) && array() !== extract_from_markers( $file, 'p3-profiler' ) ) {
795
- insert_with_markers( $file, 'p3-profiler', array( '# removed during uninstall' ) );
796
- }
797
 
798
  // Remove mu-plugin
799
  if ( file_exists( WPMU_PLUGIN_DIR . '/p3-profiler.php' ) ) {
@@ -811,6 +787,13 @@ class P3_Profiler_Plugin {
811
  * @return void
812
  */
813
  public static function uninstall() {
 
 
 
 
 
 
 
814
  // This is a static function so it needs an instance
815
  // Since I'm myself, I can call my own private methods
816
  $class = __CLASS__;
@@ -831,6 +814,9 @@ class P3_Profiler_Plugin {
831
  delete_option( 'p3-profiler_ip_address' );
832
  delete_option( 'p3-profiler_version' );
833
  delete_option( 'p3-profiler_cache_buster' );
 
 
 
834
  }
835
  restore_current_blog();
836
  } else {
@@ -842,6 +828,9 @@ class P3_Profiler_Plugin {
842
  delete_option( 'p3-profiler_ip_address' );
843
  delete_option( 'p3-profiler_version' );
844
  delete_option( 'p3-profiler_cache_buster' );
 
 
 
845
  }
846
  }
847
 
@@ -850,18 +839,9 @@ class P3_Profiler_Plugin {
850
  * @return array|false
851
  */
852
  public function scan_enabled() {
853
- if ( !file_exists( P3_FLAG_FILE ) ) {
854
- return false;
855
- }
856
- $site_url = parse_url( get_home_url(), PHP_URL_PATH );
857
- if ( null === $site_url ) {
858
- $site_url = '/';
859
- }
860
- $json = json_decode( file_get_contents( P3_FLAG_FILE ), true );
861
- foreach ( (array) $json as $v ) {
862
- if ( $site_url == $v['site_url'] ) {
863
- return $v;
864
- }
865
  }
866
  return false;
867
  }
@@ -893,6 +873,9 @@ class P3_Profiler_Plugin {
893
  delete_option( 'p3-profiler_ip_address' );
894
  delete_option( 'p3-profiler_version' );
895
  delete_option( 'p3-profiler_cache_buster' );
 
 
 
896
  }
897
 
898
  /**
@@ -902,11 +885,16 @@ class P3_Profiler_Plugin {
902
  */
903
  public function upgrade() {
904
 
 
 
 
 
 
905
  // Get the current version
906
  $version = get_option( 'p3-profiler_version' );
907
-
908
  // Upgrading from < 1.1.0
909
- if ( empty( $version ) || version_compare( $version, '1.1.0') < 0 ) {
910
  update_option( 'p3-profiler_disable_opcode_cache', true );
911
  update_option( 'p3-profiler_use_current_ip', true );
912
  update_option( 'p3-profiler_ip_address', '' );
@@ -914,11 +902,32 @@ class P3_Profiler_Plugin {
914
  }
915
 
916
  // Upgrading from < 1.1.2
917
- elseif ( version_compare( $version, '1.1.2') < 0 ) {
918
  update_option( 'p3-profiler_cache_buster', true );
919
  update_option( 'p3-profiler_version', '1.1.2' );
920
  }
921
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
922
  // Ensure the profiles folder is there
923
  $uploads_dir = wp_upload_dir();
924
  $folder = $uploads_dir['basedir'] . DIRECTORY_SEPARATOR . 'profiles';
4
  Plugin URI: http://support.godaddy.com/godaddy/wordpress-p3-plugin/
5
  Description: See which plugins are slowing down your site. Create a profile of your WordPress site's plugins' performance by measuring their impact on your site's load time.
6
  Author: GoDaddy.com
7
+ Version: 1.2.0
8
  Author URI: http://www.godaddy.com/
9
  */
10
 
19
  // Shortcut for knowing our path
20
  define( 'P3_PATH', realpath( dirname( __FILE__ ) ) );
21
 
 
 
 
22
  // Directory for profiles
23
  $uploads_dir = wp_upload_dir();
24
  define( 'P3_PROFILES_PATH', $uploads_dir['basedir'] . DIRECTORY_SEPARATOR . 'profiles' );
47
  // Upgrade routine
48
  add_action( 'admin_init', array( $p3_profiler_plugin, 'upgrade' ) );
49
 
50
+ // Figure out the action
51
+ add_action( 'admin_init', array( $p3_profiler_plugin, 'action_init' ) );
52
+
53
  // Ajax actions
54
  add_action( 'wp_ajax_p3_start_scan', array( $p3_profiler_plugin, 'ajax_start_scan' ) );
55
  add_action( 'wp_ajax_p3_stop_scan', array( $p3_profiler_plugin, 'ajax_stop_scan' ) );
117
  */
118
  public function remove_admin_bar() {
119
  if ( !is_admin() && is_user_logged_in() ) {
120
+ remove_action( 'init', '_wp_admin_bar_init' );
121
  if ( true === force_ssl_admin() ) {
122
  add_filter( 'site_url', array( $this, '_fix_url' ) );
123
  add_filter( 'admin_url', array( $this, '_fix_url' ) );
212
  wp_enqueue_style( 'p3_qtip_css', plugins_url() . '/p3-profiler/css/jquery.qtip.min.css' );
213
  wp_enqueue_style( 'p3_css', plugins_url() . '/p3-profiler/css/p3.css' );
214
  }
215
+
216
  /**
217
+ * Determine the action from the query string that guides the exection path
 
 
 
 
218
  */
219
+ public function action_init() {
220
 
221
  // Only for our page
222
  if ( isset( $_REQUEST['page'] ) && basename( __FILE__ ) == $_REQUEST['page'] ) {
238
  }
239
  $this->scan = P3_PROFILES_PATH . "/{$this->scan}";
240
  }
241
+
242
+ // Download the debug logs before output is sent
243
+ if ( 'download-debug-log' == $this->action ) {
244
+ $this->download_debug_log();
245
+ } elseif ( 'clear-debug-log' == $this->action ) {
246
+ $this->clear_debug_log();
247
+ }
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Load the necessary resources
253
+ * @uses wp_enqueue_script
254
+ * @uses jquery, jquery-ui, jquery.corners
255
+ * @uses flot, flot.pie
256
+ * @return void
257
+ */
258
+ public function early_init() {
259
+
260
+ // Only for our page
261
+ if ( isset( $_REQUEST['page'] ) && basename( __FILE__ ) == $_REQUEST['page'] ) {
262
 
263
  // If there's a scan, create a viewer object
264
  if ( !empty( $this->scan ) ) {
265
  try {
266
  $this->profile = new P3_Profile_Reader( $this->scan );
267
  } catch ( P3_Profile_No_Data_Exception $e ) {
268
+ echo '<div class="error"><p>No visits recorded during this profiling session. Check the <a href="' .
269
+ add_query_arg( array( 'p3_action' => 'help', 'current_scan' => null ) ) . '#q-circumvent-cache"' .
270
+ '>help</a> page for more information</p></div>';
271
  $this->scan = null;
272
  $this->profile = null;
273
  $this->action = 'list-scans';
308
  case 'start-scan' :
309
  $this->start_scan();
310
  break;
 
 
 
311
  case 'help' :
312
  $this->show_help();
313
  break;
317
  }
318
 
319
  /**
320
+ * Order terms randomly
321
  * @return string
322
  */
323
+ public function get_terms_orderby() {
324
+ return 'rand()';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
  }
326
 
327
  /**
333
  // Start off the scan with the home page
334
  $pages = array( get_home_url() ); // Home page
335
 
336
+ // Search for a word from the blog description
337
+ $words = array_merge( explode( ' ', get_bloginfo( 'name' ) ), explode( ' ', get_bloginfo( 'description' ) ) );
338
+ $pages[] = home_url( '?s=' . $words[ mt_rand( 0, count( $words ) - 1 ) ] );
339
 
340
+ // Get 4 random tags
341
+ add_filter( 'get_terms_orderby', array( $this, 'get_terms_orderby' ) );
342
+ $terms = get_terms( 'post_tag', 'number=4' );
343
+ foreach ( (array) $terms as $term ) {
344
+ $pages[] = get_term_link( $term );
345
+ }
346
 
347
+ // Get 4 random categories
348
+ $cats = get_terms( 'category', 'number=4');
349
+ foreach ( (array) $cats as $cat ) {
350
+ $pages[] = get_term_link( $cat );
351
+ }
352
+ remove_filter( 'get_terms_orderby', array( $this, 'get_terms_orderby' ) );
353
+
354
+ // Get the latest 4 posts
355
+ $tmp = preg_split( '/\s+/', wp_get_archives( 'type=postbypost&limit=4&echo=0' ) );
356
  if ( !empty( $tmp ) ) {
357
  foreach ( $tmp as $page ) {
358
  if ( preg_match( "/href='([^']+)'/", $page, $matches ) ) {
390
  // Sanitize the file name
391
  $filename = sanitize_file_name( basename( $_POST['p3_scan_name'] ) );
392
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  // Add the entry ( multisite installs can run more than one concurrent profile )
394
+ $opts = array(
395
  'ip' => stripslashes( $_POST['p3_ip'] ),
396
  'disable_opcode_cache' => ( 'true' == $_POST['p3_disable_opcode_cache'] ),
 
397
  'name' => $filename,
398
  );
399
 
400
+ update_option( 'p3-profiler_profiling_enabled', $opts );
401
+
402
  // Kick start the profile file
403
  if ( !file_exists( P3_PROFILES_PATH . "/$filename.json" ) ) {
404
+ $flag = file_put_contents( P3_PROFILES_PATH . "/$filename.json", '' );
405
  } else {
406
+ $flag = true;
407
  }
408
 
409
  // Check if either operation failed
410
+ if ( false === $flag ) {
411
  wp_die( 0 );
412
  } else {
413
  echo 1;
426
  wp_die( 'Invalid nonce' );
427
  }
428
 
429
+ // Turn off scanning
430
+ $opts = get_option( 'p3-profiler_profiling_enabled' );
431
+ update_option( 'p3-profiler_profiling_enabled', false );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
432
 
433
  // Tell the user what happened
434
  $this->add_notice( 'Turned off performance scanning.' );
435
 
436
  // Return the last filename
437
+ if ( !empty( $opts ) && is_array( $opts ) && array_key_exists( 'name', $opts ) ) {
438
+ echo $opts['name'] . '.json';
439
  die();
440
  } else {
441
  wp_die( 0 );
458
  update_option( 'p3-profiler_cache_buster', 'true' == $_POST['p3_cache_buster'] );
459
  update_option( 'p3-profiler_use_current_ip', 'true' == $_POST['p3_use_current_ip'] );
460
  update_option( 'p3-profiler_ip_address', $_POST['p3_ip_address'] );
461
+ update_option( 'p3-profiler_debug', 'true' == $_POST['p3_debug'] );
462
+
463
+ // Clear the debug log if it's full
464
+ if ( 'true' === $_POST['p3_debug'] ) {
465
+ $log = get_option( 'p3-profiler_debug_log' );
466
+ if ( is_array( $log ) && count( $log ) >= 100 ) {
467
+ update_option( 'p3-profiler_debug_log', array() );
468
+ }
469
+ }
470
+
471
  die( '1' );
472
  }
473
 
490
  // Check fields
491
  $to = sanitize_email( $_POST['p3_to'] );
492
  $from = sanitize_email( $_POST['p3_from'] );
493
+ $subject = trim( $_POST['p3_subject'] );
 
 
494
  $message = strip_tags( $_POST['p3_message'] );
495
  $results = strip_tags( $_POST['p3_results'] );
496
 
539
  include_once P3_PATH . '/templates/template.php';
540
  }
541
 
542
+
543
+ /**************************************************************/
544
+ /** DEBUG LOG FUNCTIONS **/
545
+ /**************************************************************/
546
+
547
+ /**
548
+ * Clear the debug log
549
+ */
550
+ public function clear_debug_log() {
551
+ if ( !check_admin_referer( 'p3-clear-debug-log' ) ) {
552
+ wp_die( 'Invalid access' );
553
+ }
554
+ update_option( 'p3-profiler_debug_log', array() );
555
+ wp_redirect( add_query_arg( array( 'p3_action' => 'help' ) ) );
556
+ }
557
+
558
+ /**
559
+ * Download the debug log
560
+ */
561
+ public function download_debug_log() {
562
+ if ( !check_admin_referer( 'p3-download-debug-log' ) ) {
563
+ wp_die( 'Invalid access' );
564
+ }
565
+ $log = get_option( 'p3-profiler_debug_log' );
566
+ if ( empty( $log ) ) {
567
+ $log = array();
568
+ }
569
+ header('Pragma: public');
570
+ header('Expires: 0');
571
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
572
+ header('Content-Type: application/force-download');
573
+ header('Content-Type: application/octet-stream');
574
+ header('Content-Type: application/download');
575
+ header('Content-Disposition: attachment; filename="p3debug.csv";');
576
+ header('Content-Transfer-Encoding: binary');
577
+
578
+ // File header
579
+ echo '"Profiling Enabled","Recording IP","Scan Name","Recording","Disable Optimizers","URL","Visitor IP","Time","PID"' . "\n";
580
+
581
+ foreach ( (array) $log as $entry ) {
582
+ printf('"%s","%s","%s","%s","%s","%s","%s","%s","%d"' . "\n",
583
+ $entry['profiling_enabled'] ? 'true' : 'false',
584
+ $entry['recording_ip'],
585
+ $entry['scan_name'],
586
+ $entry['recording'] ? 'true' : 'false',
587
+ $entry['disable_optimizers'] ? 'true' : 'false',
588
+ $entry['url'],
589
+ $entry['visitor_ip'],
590
+ date( 'Y-m-d H:i:s', $entry['time'] ),
591
+ $entry['pid']
592
+ );
593
+ }
594
+
595
+ // Done
596
+ die();
597
+ }
598
+
599
 
600
  /**************************************************************/
601
  /** HISTORY PAGE **/
685
  * @return voide
686
  */
687
  public function show_notices() {
 
 
 
 
 
 
688
  $notices = get_transient( 'p3_notices' );
689
  if ( !empty( $notices ) ) {
690
  $notices = array_unique( $notices );
696
  if ( false !== $this->scan_enabled() ) {
697
  echo '<div class="updated"><p>Performance scanning is enabled.</p></div>';
698
  }
 
 
 
 
 
 
 
 
 
 
699
  }
700
 
701
  /**
713
  die( '<strong>P3</strong> requires WordPress 3.3 or later' );
714
  }
715
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
716
  // mu-plugins doesn't exist
717
+ if ( !file_exists( WPMU_PLUGIN_DIR ) && is_writable( dirname( WPMU_PLUGIN_DIR ) ) ) {
718
  wp_mkdir_p( WPMU_PLUGIN_DIR );
719
  }
720
  if ( file_exists( WPMU_PLUGIN_DIR ) && is_writable( WPMU_PLUGIN_DIR ) ) {
764
  * @return void
765
  */
766
  public function deactivate() {
767
+ global $p3_profiler;
768
 
769
+ // Unhook the profiler
770
+ update_option( 'p3-profiler_debug', false );
771
+ update_option( 'p3-profiler_debug_log', array() );
772
+ remove_action( 'shutdown', array( $p3_profiler, 'shutdown_handler' ) );
 
773
 
774
  // Remove mu-plugin
775
  if ( file_exists( WPMU_PLUGIN_DIR . '/p3-profiler.php' ) ) {
787
  * @return void
788
  */
789
  public static function uninstall() {
790
+ global $p3_profiler;
791
+
792
+ // Unhook the profiler
793
+ update_option( 'p3-profiler_debug', false );
794
+ update_option( 'p3-profiler_debug_log', array() );
795
+ remove_action( 'shutdown', array( $p3_profiler, 'shutdown_handler' ) );
796
+
797
  // This is a static function so it needs an instance
798
  // Since I'm myself, I can call my own private methods
799
  $class = __CLASS__;
814
  delete_option( 'p3-profiler_ip_address' );
815
  delete_option( 'p3-profiler_version' );
816
  delete_option( 'p3-profiler_cache_buster' );
817
+ delete_option( 'p3-profiler_profiling_enabled' );
818
+ delete_option( 'p3-profiler_debug' );
819
+ delete_option( 'p3-profiler_debug_log' );
820
  }
821
  restore_current_blog();
822
  } else {
828
  delete_option( 'p3-profiler_ip_address' );
829
  delete_option( 'p3-profiler_version' );
830
  delete_option( 'p3-profiler_cache_buster' );
831
+ delete_option( 'p3-profiler_profiling_enabled' );
832
+ delete_option( 'p3-profiler_debug' );
833
+ delete_option( 'p3-profiler_debug_log' );
834
  }
835
  }
836
 
839
  * @return array|false
840
  */
841
  public function scan_enabled() {
842
+ $opts = get_option( 'p3-profiler_profiling_enabled' );
843
+ if ( !empty( $opts ) ) {
844
+ return $opts;
 
 
 
 
 
 
 
 
 
845
  }
846
  return false;
847
  }
873
  delete_option( 'p3-profiler_ip_address' );
874
  delete_option( 'p3-profiler_version' );
875
  delete_option( 'p3-profiler_cache_buster' );
876
+ delete_option( 'p3-profiler_profiling_enabled' );
877
+ delete_option( 'p3-profiler_debug' );
878
+ delete_option( 'p3-profiler_debug_log' );
879
  }
880
 
881
  /**
885
  */
886
  public function upgrade() {
887
 
888
+ // Only for our page
889
+ if ( !isset( $_REQUEST['page'] ) || basename( __FILE__ ) != $_REQUEST['page'] ) {
890
+ return;
891
+ }
892
+
893
  // Get the current version
894
  $version = get_option( 'p3-profiler_version' );
895
+
896
  // Upgrading from < 1.1.0
897
+ if ( empty( $version ) || version_compare( $version, '1.1.0' ) < 0 ) {
898
  update_option( 'p3-profiler_disable_opcode_cache', true );
899
  update_option( 'p3-profiler_use_current_ip', true );
900
  update_option( 'p3-profiler_ip_address', '' );
902
  }
903
 
904
  // Upgrading from < 1.1.2
905
+ if ( empty( $version) || version_compare( $version, '1.1.2' ) < 0 ) {
906
  update_option( 'p3-profiler_cache_buster', true );
907
  update_option( 'p3-profiler_version', '1.1.2' );
908
  }
909
 
910
+ // Upgrading from < 1.2.0
911
+ if ( empty( $version) || version_compare( $version, '1.2.0' ) < 0 ) {
912
+
913
+ // Set profiling option
914
+ update_option( 'p3-profiler_profiling_enabled', false );
915
+ update_option( 'p3-profiler_version', '1.2.0' );
916
+ update_option( 'p3-profiler_debug', false );
917
+ update_option( 'p3-profiler_debug_log', array() );
918
+
919
+ // Remove any .htaccess modifications
920
+ $file = ABSPATH . '/.htaccess';
921
+ if ( file_exists( $file ) && array() !== extract_from_markers( $file, 'p3-profiler' ) ) {
922
+ insert_with_markers( $file, 'p3-profiler', array( '# removed during 1.2.0 upgrade' ) );
923
+ }
924
+
925
+ // Remove .profiling_enabled if it's still present
926
+ if ( file_exists( P3_PATH . '/.profiling_enabled' ) ) {
927
+ @unlink( P3_PATH . '/.profiling_enabled' );
928
+ }
929
+ }
930
+
931
  // Ensure the profiles folder is there
932
  $uploads_dir = wp_upload_dir();
933
  $folder = $uploads_dir['basedir'] . DIRECTORY_SEPARATOR . 'profiles';
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: Godaddy, StarfieldTech
3
  Tags: debug, debugging, developer, development, performance, plugin, profiler, speed
4
  Requires at least: 3.3
5
  Tested up to: 3.3.1
6
- Stable tag: 1.1.3
7
 
8
  See which plugins are slowing down your site. This plugin creates a performance report for your site.
9
 
@@ -43,6 +43,9 @@ Manual installation:
43
 
44
  == Upgrade Notice ==
45
 
 
 
 
46
  = 1.1.3 =
47
  Fixed a regression bug re-introduced in v 1.1.2. Thanks to user adamf for finding this so quickly!
48
 
@@ -76,6 +79,27 @@ Thanks!
76
 
77
  == Changelog ==
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  = 1.1.3 =
80
  * Bugfix - regression bug re-introduced in v 1.1.2. Thanks to user adamf for finding this so quickly!
81
 
3
  Tags: debug, debugging, developer, development, performance, plugin, profiler, speed
4
  Requires at least: 3.3
5
  Tested up to: 3.3.1
6
+ Stable tag: 1.2.0
7
 
8
  See which plugins are slowing down your site. This plugin creates a performance report for your site.
9
 
43
 
44
  == Upgrade Notice ==
45
 
46
+ = 1.2.0 =
47
+ Many compatibility fixes based on user feedback. Upgrading is recommended.
48
+
49
  = 1.1.3 =
50
  Fixed a regression bug re-introduced in v 1.1.2. Thanks to user adamf for finding this so quickly!
51
 
79
 
80
  == Changelog ==
81
 
82
+ = 1.2.0 =
83
+ * Remove .profiling_enabled file, store profiling flag as a WordPress option
84
+ * Remove code that writes to .htaccess file
85
+ * Removed fix-flag-file page, no longer necessary
86
+ * Added a link to the "no visits recorded" message pointing to the help page
87
+ * Bugfix - with the manual profile "I'm done" button not showing the intended scan
88
+ * On upgrade, remove .htaccess auto_prepend_file code
89
+ * On upgrade, delete .profiling_enabled file
90
+ * Include a data point for all visits for all plugins on the detailed chart (If no data point exists, mark it as 0 to keep the line connected)
91
+ * Add Debug log feature to help diagnose why scans aren't recording properly on some sites
92
+ * Opcode optimizer detection / documentation
93
+ * Opcode optimizer compatibility
94
+ * Update the list of random URLs to scan - use 4 random categories, 4 random tags, 4 random posts, a random search word from the blog description, and the home page
95
+ * Don't include the site's RSS feed in the automated scan, it's causing problems in some browsers which expect the feed to be loaded as a document
96
+ * Support HTTP_X_REAL_IP
97
+ * Remove file locking, it's preventing the profiles from being saved on some hosts
98
+ * Removing calls to filter_var, some 5.2.x builds use --disable-filter so this isn't reliable
99
+ * Bugfix - Pausing a scan and clicking "View results" showed an error message
100
+ * Bugfix - Avoid using "../" for compatibility with open_basedir
101
+ * Upgrade routine was being done in the wrong order
102
+
103
  = 1.1.3 =
104
  * Bugfix - regression bug re-introduced in v 1.1.2. Thanks to user adamf for finding this so quickly!
105
 
templates/callouts.php CHANGED
@@ -49,6 +49,7 @@ if ( !defined('P3_PATH') )
49
  'p3_ip' : jQuery( '#p3-advanced-ip' ).val(),
50
  'p3_disable_opcode_cache' : jQuery( '#p3-disable-opcode-cache' ).prop( 'checked' ),
51
  'p3_cache_buster' : jQuery( '#p3-cache-buster' ).prop( 'checked' ),
 
52
  'p3_scan_name' : jQuery( "#p3-scan-name" ).val(),
53
  'action' : 'p3_start_scan',
54
  'p3_nonce' : jQuery( "#p3_nonce" ).val()
@@ -106,6 +107,7 @@ if ( !defined('P3_PATH') )
106
  'p3_ip' : jQuery( '#p3-advanced-ip' ).val(),
107
  'p3_disable_opcode_cache' : jQuery( '#p3-disable-opcode-cache' ).prop( 'checked' ),
108
  'p3_cache_buster' : jQuery( '#p3-cache-buster' ).prop( 'checked' ),
 
109
  'p3_scan_name' : jQuery( "#p3-scan-name" ).val(),
110
  'action' : 'p3_start_scan',
111
  'p3_nonce' : jQuery( "#p3_nonce" ).val()
@@ -209,7 +211,7 @@ if ( !defined('P3_PATH') )
209
  'resizable' : false,
210
  'modal' : true,
211
  'width' : 450,
212
- 'height' : 340,
213
  'title' : "Advanced Settings",
214
  'buttons' :
215
  [
@@ -225,6 +227,7 @@ if ( !defined('P3_PATH') )
225
  'p3_use_current_ip' : $( '#p3-use-current-ip' ).prop( 'checked' ),
226
  'p3_ip_address' : $( '#p3-advanced-ip' ).val(),
227
  'p3_cache_buster' : $( '#p3-cache-buster' ).prop( 'checked' ),
 
228
  'p3_nonce' : '<?php echo wp_create_nonce( 'p3_save_settings' ); ?>'
229
  }
230
  $.post( ajaxurl, data, function( response ) {
@@ -375,6 +378,7 @@ if ( !defined('P3_PATH') )
375
  'p3_ip' : jQuery( '#p3-advanced-ip' ).val(),
376
  'p3_disable_opcode_cache' : jQuery( '#p3-disable-opcode-cache' ).prop( 'checked' ),
377
  'p3_cache_buster' : jQuery( '#p3-cache-buster' ).prop( 'checked' ),
 
378
  'p3_scan_name' : jQuery( "#p3-scan-name" ).val(),
379
  'action' : 'p3_start_scan',
380
  'p3_nonce' : jQuery( "#p3_nonce" ).val()
@@ -402,7 +406,7 @@ if ( !defined('P3_PATH') )
402
  if ( response.indexOf( '.json' ) < 0 ) {
403
  alert( "There was an error processing your request. Please reload the page and try again. [" + response + "]");
404
  } else {
405
- location.href = "<?php echo add_query_arg( array( 'p3_action' => 'current-scan', 'current_scan' => 1 ) ); ?>&name=" + response;
406
  }
407
  })
408
  $( "#p3-scanner-dialog" ).dialog( "close" );
@@ -449,6 +453,7 @@ if ( !defined('P3_PATH') )
449
  location.href = "<?php echo add_query_arg( array( 'p3_action' => 'view-scan', 'current_scan' => '1', 'name' => null ) ); ?>&name=" + $( this ).attr( "data-scan-name" );
450
  });
451
  $( "#p3-view-incomplete-results-submit" ).click( function() {
 
452
  $( "#p3-view-results-submit" ).trigger( "click" );
453
  });
454
 
@@ -531,7 +536,7 @@ if ( !defined('P3_PATH') )
531
  echo $active_plugins;
532
  ?>
533
  </div>
534
- <div class="p3-callout-caption">( currently active )</div>
535
  </div>
536
  </div>
537
  </td>
@@ -549,7 +554,7 @@ if ( !defined('P3_PATH') )
549
  <?php printf( '%.3f', $this->profile->averages['plugins'] ); ?>
550
  <?php } ?>
551
  </div>
552
- <div class="p3-callout-caption">( sec. per visit )</div>
553
  </div>
554
  </div>
555
  </td>
@@ -567,7 +572,7 @@ if ( !defined('P3_PATH') )
567
  <?php printf( '%.1f%%', $this->profile->averages['plugin_impact'] ); ?>
568
  <?php } ?>
569
  </div>
570
- <div class="p3-callout-caption">( of page load time )</div>
571
  </div>
572
  </div>
573
  </td>
@@ -607,7 +612,7 @@ if ( !defined('P3_PATH') )
607
  <br />
608
  <div>
609
  <input type="checkbox" id="p3-disable-opcode-cache" <?php if ( true == get_option( 'p3-profiler_disable_opcode_cache' ) ) : ?>checked="checked"<?php endif; ?> />
610
- <label for="p3-disable-opcode-cache">Attempt to disable opcode caches <em>( recommended )</em></label>
611
  <br />
612
  <em class="p3-em">This can increase accuracy in plugin detection, but decrease accuracy in timing</em>
613
  </div>
@@ -616,7 +621,14 @@ if ( !defined('P3_PATH') )
616
  <input type="checkbox" id="p3-cache-buster" <?php if ( true == get_option( 'p3-profiler_cache_buster' ) ) : ?>checked="checked"<?php endif; ?> />
617
  <label for="p3-cache-buster">Attempt to circumvent browser cache</label>
618
  <br />
619
- <em class="p3-em">This may help fix a "No visits in this profile" error message. See the <a href="<?php echo add_query_arg( array( 'p3_action' => 'help', 'current_scan' => null ) ); ?>#q-circumvent-cache">help</a> page for details.</em>
 
 
 
 
 
 
 
620
  </div>
621
  </div>
622
 
49
  'p3_ip' : jQuery( '#p3-advanced-ip' ).val(),
50
  'p3_disable_opcode_cache' : jQuery( '#p3-disable-opcode-cache' ).prop( 'checked' ),
51
  'p3_cache_buster' : jQuery( '#p3-cache-buster' ).prop( 'checked' ),
52
+ 'p3_debug' : jQuery( '#p3-debug' ).prop( 'checked' ),
53
  'p3_scan_name' : jQuery( "#p3-scan-name" ).val(),
54
  'action' : 'p3_start_scan',
55
  'p3_nonce' : jQuery( "#p3_nonce" ).val()
107
  'p3_ip' : jQuery( '#p3-advanced-ip' ).val(),
108
  'p3_disable_opcode_cache' : jQuery( '#p3-disable-opcode-cache' ).prop( 'checked' ),
109
  'p3_cache_buster' : jQuery( '#p3-cache-buster' ).prop( 'checked' ),
110
+ 'p3_debug' : jQuery( '#p3-debug' ).prop( 'checked' ),
111
  'p3_scan_name' : jQuery( "#p3-scan-name" ).val(),
112
  'action' : 'p3_start_scan',
113
  'p3_nonce' : jQuery( "#p3_nonce" ).val()
211
  'resizable' : false,
212
  'modal' : true,
213
  'width' : 450,
214
+ 'height' : 425,
215
  'title' : "Advanced Settings",
216
  'buttons' :
217
  [
227
  'p3_use_current_ip' : $( '#p3-use-current-ip' ).prop( 'checked' ),
228
  'p3_ip_address' : $( '#p3-advanced-ip' ).val(),
229
  'p3_cache_buster' : $( '#p3-cache-buster' ).prop( 'checked' ),
230
+ 'p3_debug' : $( '#p3-debug' ).prop( 'checked' ),
231
  'p3_nonce' : '<?php echo wp_create_nonce( 'p3_save_settings' ); ?>'
232
  }
233
  $.post( ajaxurl, data, function( response ) {
378
  'p3_ip' : jQuery( '#p3-advanced-ip' ).val(),
379
  'p3_disable_opcode_cache' : jQuery( '#p3-disable-opcode-cache' ).prop( 'checked' ),
380
  'p3_cache_buster' : jQuery( '#p3-cache-buster' ).prop( 'checked' ),
381
+ 'p3_debug' : jQuery( '#p3-debug' ).prop( 'checked' ),
382
  'p3_scan_name' : jQuery( "#p3-scan-name" ).val(),
383
  'action' : 'p3_start_scan',
384
  'p3_nonce' : jQuery( "#p3_nonce" ).val()
406
  if ( response.indexOf( '.json' ) < 0 ) {
407
  alert( "There was an error processing your request. Please reload the page and try again. [" + response + "]");
408
  } else {
409
+ location.href = "<?php echo add_query_arg( array( 'p3_action' => 'view-scan', 'current_scan' => '1', 'name' => null ) ); ?>&name=" + response;
410
  }
411
  })
412
  $( "#p3-scanner-dialog" ).dialog( "close" );
453
  location.href = "<?php echo add_query_arg( array( 'p3_action' => 'view-scan', 'current_scan' => '1', 'name' => null ) ); ?>&name=" + $( this ).attr( "data-scan-name" );
454
  });
455
  $( "#p3-view-incomplete-results-submit" ).click( function() {
456
+ $( "#p3-view-results-submit" ).attr( "data-scan-name", $( "#p3-view-incomplete-results-submit" ).attr( "data-scan-name" ) );
457
  $( "#p3-view-results-submit" ).trigger( "click" );
458
  });
459
 
536
  echo $active_plugins;
537
  ?>
538
  </div>
539
+ <div class="p3-callout-caption">(currently active)</div>
540
  </div>
541
  </div>
542
  </td>
554
  <?php printf( '%.3f', $this->profile->averages['plugins'] ); ?>
555
  <?php } ?>
556
  </div>
557
+ <div class="p3-callout-caption">(sec. per visit)</div>
558
  </div>
559
  </div>
560
  </td>
572
  <?php printf( '%.1f%%', $this->profile->averages['plugin_impact'] ); ?>
573
  <?php } ?>
574
  </div>
575
+ <div class="p3-callout-caption">(of page load time)</div>
576
  </div>
577
  </div>
578
  </td>
612
  <br />
613
  <div>
614
  <input type="checkbox" id="p3-disable-opcode-cache" <?php if ( true == get_option( 'p3-profiler_disable_opcode_cache' ) ) : ?>checked="checked"<?php endif; ?> />
615
+ <label for="p3-disable-opcode-cache">Attempt to disable opcode optimizers <em>(recommended)</em></label>
616
  <br />
617
  <em class="p3-em">This can increase accuracy in plugin detection, but decrease accuracy in timing</em>
618
  </div>
621
  <input type="checkbox" id="p3-cache-buster" <?php if ( true == get_option( 'p3-profiler_cache_buster' ) ) : ?>checked="checked"<?php endif; ?> />
622
  <label for="p3-cache-buster">Attempt to circumvent browser cache</label>
623
  <br />
624
+ <em class="p3-em">This may help fix a "No visits recorded" error message. See the <a href="<?php echo add_query_arg( array( 'p3_action' => 'help', 'current_scan' => null ) ); ?>#q-debug-log">help</a> page for details.</em>
625
+ </div>
626
+ <br />
627
+ <div>
628
+ <input type="checkbox" id="p3-debug" <?php if ( true == get_option( 'p3-profiler_debug' ) ) : ?>checked="checked"<?php endif; ?> />
629
+ <label for="p3-debug">Debug mode</label>
630
+ <br />
631
+ <em class="p3-em">This will log the last 100 visits. Check the <a href="<?php echo add_query_arg( array( 'p3_action' => 'help', 'current_scan' => null ) ); ?>#q-debug-log">help</a> page to view log messages.</em>
632
  </div>
633
  </div>
634
 
templates/fix-flag-file.php DELETED
@@ -1,15 +0,0 @@
1
- <?php
2
- if ( !defined('P3_PATH') )
3
- die( 'Forbidden ');
4
- ?>
5
- <?php if ( file_exists( P3_FLAG_FILE ) && is_writable( P3_FLAG_FILE ) ) { ?>
6
- <h3>Fixed!</h3>
7
- The profiling flag file has been created and is writable.
8
- <?php } else { ?>
9
- <h3>Still broken!</h3>
10
- The profiling flag file needs to exist and be writable.
11
- <?php } ?>
12
- <br /><br />
13
- <code><?php echo realpath( P3_FLAG_FILE ); ?></code>
14
- <br /><br />
15
- <input type="button" class="button" onclick="location.href='<?php echo add_query_arg( array( 'p3_action' => 'current-scan' ) ); ?>';" value="Go back" />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
templates/help.php CHANGED
@@ -31,11 +31,25 @@ if ( !defined('P3_PATH') )
31
  $( this ).html( "Hide" );
32
  }
33
  });
34
- // $( "#p3-hide-glossary" ).trigger( "click" );
35
- $( "#p3-glossary-container" ).dblclick( function() {
36
- $( "#p3-hide-glossary" ).trigger( "click" );
37
- });
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  // Automatically create the table of contents
40
  var links = [];
41
  var i = 1;
@@ -101,7 +115,7 @@ if ( !defined('P3_PATH') )
101
  </div>
102
 
103
  <div class="p3-question">
104
- <h2 class="p3-help-question" data-question-id="q-circumvent-cache">How do I fix "No visits in this profile..." ?</h2>
105
  <blockquote>
106
  This error message means that after being disabled, the profiler did not record any traffic on your site. There are several common
107
  causes for this:
@@ -150,65 +164,16 @@ if ( !defined('P3_PATH') )
150
  <div class="p3-question">
151
  <h2 class="p3-help-question">How does my site load the plugin?</h2>
152
  <blockquote>
153
- The plugin should be active at the earliest point in the code execution. The plugin can be loaded through an
154
- auto_prepend_file configuration directive from a .htaccess file or a <a href="http://php.net/manual/en/configuration.file.per-user.php"
155
- target="_blank">.user.ini</a> file, but be careful. The .user.ini files are cached, so you must remove the entry from your
156
- .user.ini file before you remove this plugin.
157
- <br /><br />
158
- This plugin automatically enables itself in .htaccess if possible, or, if that doesn't succeed, it creates a
159
- <a href="http://codex.wordpress.org/Must_Use_Plugins" target="_blank">must-use</a> plugin to load before other plugins.
160
- If neither of those methods work, it runs like a regular plugin.
161
  <br /><br />
162
  You are currently using:
163
  <?php
164
-
165
- // .htaccess file test
166
- $htaccess_file = P3_PATH . '/../../../.htaccess';
167
- $htaccess_content = '';
168
- if ( file_exists( $htaccess_file ) ) {
169
- $htaccess_content = extract_from_markers( $htaccess_file, 'p3-profiler' );
170
- foreach ( $htaccess_content as $k => $v ) {
171
- if ( '#' == substr( trim( $v ), 0, 1 ) ) {
172
- unset( $htaccess_content[$k] ); // Get rid of comment lines
173
- }
174
- }
175
- $htaccess_content = implode( "\n", $htaccess_content );
176
- }
177
-
178
  // must-use plugin file
179
- $mu_file = P3_PATH . '/../../mu-plugins/p3-profiler.php';
180
-
181
- // List php ini files
182
- $ini_files = array_filter(
183
- array_merge(
184
- array( php_ini_loaded_file() ),
185
- explode( ',', php_ini_scanned_files() )
186
- )
187
- );
188
  ?>
189
-
190
- <?php /* .htaccess file is there, the profiler content is there, hasn't been commented out, and the auto_prepend_file directive is active */ ?>
191
- <?php if (
192
- file_exists( $htaccess_file ) &&
193
- !empty( $htaccess_content ) &&
194
- false !== strpos( $htaccess_content, 'start-profile.php' ) &&
195
- false !== strpos( ini_get( 'auto_prepend_file' ), 'start-profile.php' ) ) { ?>
196
- <a href="http://php.net/manual/en/configuration.changes.php" target="_blank">.htaccess file</a>
197
- - <code><?php echo realpath( $htaccess_file ); ?></code>
198
- <?php /* the auto_prepend_file directive is active */ ?>
199
- <?php } elseif ( false !== strpos( ini_get( 'auto_prepend_file' ), 'start-profile.php' ) ){ ?>
200
- <a href="http://www.php.net/manual/en/configuration.file.php" target="_blank">php.ini</a>
201
- <?php if ( version_compare( phpversion(), '5.3.0' ) >= 0 ) { ?>
202
- or <a href="http://www.php.net/manual/en/configuration.file.per-user.php" target="_blank">.user.ini</a>
203
- <?php } ?>
204
- entry from one of these files:
205
- <ul>
206
- <?php foreach ( $ini_files as $file ) { ?>
207
- <ol><code><?php echo trim( $file ); ?></code></ol>
208
- <?php } ?>
209
- </ul>
210
  <?php /* must-use plugin file is there and not-empty */ ?>
211
- <?php } elseif ( file_exists( $mu_file ) && filesize( $mu_file ) > 0 ){ ?>
212
  <a href="http://codex.wordpress.org/Must_Use_Plugins" target="_blank">must-use plugin</a>
213
  - <code><?php echo realpath( $mu_file ); ?></code>
214
  <?php /* default, using this plugin file */ ?>
@@ -266,11 +231,11 @@ if ( !defined('P3_PATH') )
266
  <div class="p3-question">
267
  <h2 class="p3-help-question">What can interfere with testing?</h2>
268
  <blockquote>
269
- Opcode caches can interfere with PHP backtraces. Leaving opcode caches turned on will result in timing that more accurately
270
  reflects your site's real performance, but the function calls to plugins may be "optimized" out of the backtraces and some
271
  plugins (especially those with only one hook) might not show up. Disabling opcode caches results in slower times, but shows all plugins.
272
  <br /><br />
273
- By default, this plugin attempts to clear any opcode caches before it runs. You can change this setting by clicking "Advanced
274
  Settings" under "Start Scan."
275
  <br /><br />
276
  Caching plugins that have an option to disable caches for logged in users will not give you the same performance profile that
@@ -280,6 +245,51 @@ if ( !defined('P3_PATH') )
280
  </blockquote>
281
  </div>
282
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
  <div class="p3-question">
284
  <h2 class="p3-help-question">How much room do these profiles take up on my server</h2>
285
  <blockquote>
@@ -354,6 +364,82 @@ if ( !defined('P3_PATH') )
354
  </blockquote>
355
  </div>
356
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
 
358
  <div class="p3-question">
359
  <h2 class="p3-help-question">What if I get a warning about usort()?</h2>
31
  $( this ).html( "Hide" );
32
  }
33
  });
 
 
 
 
34
 
35
+
36
+ // Debug log
37
+ $( "#p3-hide-debug-log" ).click( function() {
38
+ if ( "Hide" == $( this ).html() ) {
39
+ $( "#p3-debug-log-table thead" ).hide();
40
+ $( "#p3-debug-log-table tbody" ).hide();
41
+ $( "#p3-debug-log-table tfoot" ).hide();
42
+ $( this ).html( "Show" );
43
+ } else {
44
+ $( "#p3-debug-log-table thead" ).show();
45
+ $( "#p3-debug-log-table tbody" ).show();
46
+ $( "#p3-debug-log-table tfoot" ).show();
47
+ $( this ).html( "Hide" );
48
+ }
49
+ });
50
+ $( "#p3-debug-log-container table tbody tr:even ").addClass( "even" );
51
+
52
+
53
  // Automatically create the table of contents
54
  var links = [];
55
  var i = 1;
115
  </div>
116
 
117
  <div class="p3-question">
118
+ <h2 class="p3-help-question" data-question-id="q-circumvent-cache">How do I fix "No visits recorded..." ?</h2>
119
  <blockquote>
120
  This error message means that after being disabled, the profiler did not record any traffic on your site. There are several common
121
  causes for this:
164
  <div class="p3-question">
165
  <h2 class="p3-help-question">How does my site load the plugin?</h2>
166
  <blockquote>
167
+ This plugin automatically creates a <a href="http://codex.wordpress.org/Must_Use_Plugins" target="_blank">must-use</a>
168
+ plugin to load before other plugins. If that doesn't work, it runs like a regular plugin.
 
 
 
 
 
 
169
  <br /><br />
170
  You are currently using:
171
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  // must-use plugin file
173
+ $mu_file = WPMU_PLUGIN_DIR . '/p3-profiler.php';
 
 
 
 
 
 
 
 
174
  ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  <?php /* must-use plugin file is there and not-empty */ ?>
176
+ <?php if ( file_exists( $mu_file ) && filesize( $mu_file ) > 0 ){ ?>
177
  <a href="http://codex.wordpress.org/Must_Use_Plugins" target="_blank">must-use plugin</a>
178
  - <code><?php echo realpath( $mu_file ); ?></code>
179
  <?php /* default, using this plugin file */ ?>
231
  <div class="p3-question">
232
  <h2 class="p3-help-question">What can interfere with testing?</h2>
233
  <blockquote>
234
+ Opcode optimizers can interfere with PHP backtraces. Leaving opcode optimizers turned on will result in timing that more accurately
235
  reflects your site's real performance, but the function calls to plugins may be "optimized" out of the backtraces and some
236
  plugins (especially those with only one hook) might not show up. Disabling opcode caches results in slower times, but shows all plugins.
237
  <br /><br />
238
+ By default, this plugin attempts to disable any detected opcode optimizers when it runs. You can change this setting by clicking "Advanced
239
  Settings" under "Start Scan."
240
  <br /><br />
241
  Caching plugins that have an option to disable caches for logged in users will not give you the same performance profile that
245
  </blockquote>
246
  </div>
247
 
248
+ <div class="p3-question">
249
+ <h2 class="p3-help-question" data-question-id="q-opcode-optimizer">Is my site using an opcode optimizer?</h2>
250
+ <blockquote>
251
+ <?php $detected = 0; if ( extension_loaded( 'xcache' ) ) { $detected++; ?>
252
+ Your site is using XCache. Although XCache reports that no opcode optimization won't be implemented until
253
+ version 2.0, this has been known to cause problems with P3.<br />
254
+ <?php } ?>
255
+ <?php if ( extension_loaded( 'apc' ) ) { $detected++; ?>
256
+ Your site is using APC. This has not been known to cause problems with P3.<br />
257
+ <?php } ?>
258
+ <?php if ( extension_loaded( 'eaccelerator' ) && ini_get( 'eaccelerator.optimizer' ) ) { $detected++; ?>
259
+ Your site is using eaccelerator with optimization enabled. This has been known to cause problems with P3. To temporarily
260
+ disable the optimizer
261
+ <?php if ( 'apache2handler' == strtolower( php_sapi_name() ) ) { ?>
262
+ you can add <code>php_flag eaccelerator.optimizer Off</code> to your site's .htaccess file.
263
+ <?php } elseif ( version_compare( PHP_VERSION, '5.3.0' ) >= 0 ) { ?>
264
+ you can add <code>eaccelerator.optimizer = 0</code> to your site's <a href="http://php.net/manual/en/configuration.file.per-user.php" target="_blank"><?php echo ini_get( 'user_ini.filename' ); ?> file</a>.
265
+ <?php } else { ?>
266
+ you can ask your hosting provider.
267
+ <?php } ?>
268
+ <br />
269
+ <?php } ?>
270
+ <?php if ( extension_loaded( 'Zend Optimizer+' ) && ini_get( 'zend_optimizerplus.optimization_level' ) > 0 ) { $detected++; ?>
271
+ Your site is using Zend Optimizer+. This has not been known to cause problems with P3.<br />
272
+ <?php } ?>
273
+ <?php if ( extension_loaded( 'IonCube Loader' ) ) { $detected++; ?>
274
+ Your site is using the IonCube loader. This has not been known to cause problems with P3. <br />
275
+ <?php } ?>
276
+ <?php if ( extension_loaded( 'wincache' ) ) { $detected++; ?>
277
+ Your site is using wincache. This has not been known to cause problems with P3. <br />
278
+ <?php } ?>
279
+ <?php if ( extension_loaded( 'Zend Guard Loader' ) ) { $detected++; ?>
280
+ Your site is using the Zend Guard loader. This has not been known to cause problems with P3. <br />
281
+ <?php } ?>
282
+ <?php if ( extension_loaded( 'Zend Optimizer' ) ) { $detected++; ?>
283
+ Your site is using the Zend Optimizer. This extension has not been tested with P3. Please report any problems.<br />
284
+ <?php } ?>
285
+ <?php if ( !$detected ) { ?>
286
+ P3 has not detected any opcode optimizers on your site. Although none were detected, an opcode optimizer may still be present.
287
+ Contact your server administrator with any questions.
288
+ <?php } ?>
289
+ </blockquote>
290
+ </div>
291
+
292
+
293
  <div class="p3-question">
294
  <h2 class="p3-help-question">How much room do these profiles take up on my server</h2>
295
  <blockquote>
364
  </blockquote>
365
  </div>
366
 
367
+ <div class="p3-question">
368
+ <h2 class="p3-help-question" data-question-id="q-debug-log">Where can I view the debug log?</h2>
369
+ <blockquote>
370
+ Debug mode will record 100 visits to your site, then turn off automatically. You can view the log below. The entries
371
+ are shown in reverse order with the latest visits appearing at the top of the list. You can also
372
+ <a href="<?php echo wp_nonce_url( add_query_arg( array( 'p3_action' => 'clear-debug-log' ) ), 'p3-clear-debug-log' ) ; ?>" class="button-secondary">Clear the log</a> or
373
+ <a href="<?php echo wp_nonce_url( add_query_arg( array( 'p3_action' => 'download-debug-log' ) ), 'p3-download-debug-log' ) ; ?>" class="button-secondary">Download the log</a> as a CSV.
374
+ <br /><br />
375
+ <div id="p3-debug-log-container">
376
+ <div class="ui-widget-header" id="p3-debug-log-header" style="padding: 8px;">
377
+ <strong>Debug Log</strong>
378
+ <div style="position: relative; top: 0px; right: 80px; float: right;">
379
+ <a href="javascript:;" id="p3-hide-debug-log">Hide</a>
380
+ </div>
381
+ </div>
382
+ <div>
383
+ <table class="p3-results-table" id="p3-debug-log-table" cellpadding="0" cellspacing="0" border="0">
384
+ <thead>
385
+ <tr>
386
+ <td><strong>#</strong></td>
387
+ <td><strong>Profiling Enabled</strong></td>
388
+ <td><strong>Recording IP</strong></td>
389
+ <td><strong>Scan Name</strong></td>
390
+ <td><strong>Recording</strong></td>
391
+ <td><strong>Disable Optimizers</strong></td>
392
+ <td><strong>URL</strong></td>
393
+ <td><strong>Visitor IP</strong></td>
394
+ <td><strong>Time</strong></td>
395
+ <td><strong>PID</strong></td>
396
+ </tr>
397
+ </thead>
398
+ <tbody>
399
+ <?php $log = get_option( 'p3-profiler_debug_log' ); $c = count( $log ); foreach ( $log as $entry ) : ?>
400
+ <tr>
401
+ <td><?php echo $c--; ?></td>
402
+ <td><?php echo $entry['profiling_enabled'] ? 'true' : 'false'; ?></td>
403
+ <td><?php echo $entry['recording_ip']; ?></td>
404
+ <td>
405
+ <?php if ( file_exists(P3_PROFILES_PATH . '/' . $entry['scan_name'] . '.json' ) ) : ?>
406
+ <a href="<?php echo add_query_arg( array(
407
+ 'p3_action' => 'view-scan',
408
+ 'current-scan' => null,
409
+ 'name' => $entry['scan_name'] . '.json'
410
+ ) ); ?>"><?php echo $entry['scan_name']; ?></a>
411
+ <?php else : ?>
412
+ <?php echo $entry['scan_name']; ?>
413
+ <?php endif; ?>
414
+ </td>
415
+ <td><?php echo $entry['recording'] ? 'true' : 'false'; ?></td>
416
+ <td><?php echo $entry['disable_optimizers'] ? 'true' : 'false'; ?></td>
417
+ <td><?php echo htmlentities( $entry['url'] ); ?></td><?php // URL intentionally not clickable to avoid accidental replay attacks ?>
418
+ <td><?php echo $entry['visitor_ip']; ?></td>
419
+ <td><?php echo human_time_diff( $entry['time'] ) . ' ' . __('ago'); ?></td>
420
+ <td><?php echo $entry['pid']; ?></td>
421
+ </tr>
422
+ <?php endforeach ; ?>
423
+ </tbody>
424
+ <tfoot>
425
+ <tr>
426
+ <td><strong>#</strong></td>
427
+ <td><strong>Profiling Enabled</strong></td>
428
+ <td><strong>Recording IP</strong></td>
429
+ <td><strong>Scan Name</strong></td>
430
+ <td><strong>Recording</strong></td>
431
+ <td><strong>Disable Optimizers</strong></td>
432
+ <td><strong>URL</strong></td>
433
+ <td><strong>Visitor IP</strong></td>
434
+ <td><strong>Time</strong></td>
435
+ <td><strong>PID</strong></td>
436
+ </tr>
437
+ </tfoot>
438
+ </table>
439
+ </div>
440
+ </div>
441
+ </blockquote>
442
+ </div>
443
 
444
  <div class="p3-question">
445
  <h2 class="p3-help-question">What if I get a warning about usort()?</h2>
templates/template.php CHANGED
@@ -5,7 +5,7 @@ $button_history_checked = '';
5
  $button_help_checked = '';
6
  if ( 'current-scan' == $this->action || !empty( $_REQUEST['current_scan'] ) ) {
7
  $button_current_checked = 'checked="checked"';
8
- } elseif ( 'help' == $this->action || 'fix-flag-file' == $this->action ) {
9
  $button_help_checked = 'checked="checked"';
10
  } else {
11
  $button_history_checked = 'checked="checked"';
@@ -70,8 +70,8 @@ if ( 'current-scan' == $this->action || !empty( $_REQUEST['current_scan'] ) ) {
70
  <input type="radio" name="p3-nav" id="button-help" <?php echo $button_help_checked; ?> /><label for="button-help">Help</label>
71
 
72
  <div id="p3-scan-label">
73
- <?php if ( !empty( $profile ) ) : ?>
74
- Scan name: <?php echo $profile->profile_name; ?>
75
  <?php endif; ?>
76
  </div>
77
  </div>
@@ -84,8 +84,6 @@ if ( 'current-scan' == $this->action || !empty( $_REQUEST['current_scan'] ) ) {
84
  <?php include_once P3_PATH . '/templates/view-scan.php'; ?>
85
  <?php } elseif ( 'help' == $this->action ) { ?>
86
  <?php include_once P3_PATH . '/templates/help.php'; ?>
87
- <?php } elseif ( 'fix-flag-file' == $this->action ) { ?>
88
- <?php include_once P3_PATH . '/templates/fix-flag-file.php'; ?>
89
  <?php } else { ?>
90
  <?php include_once P3_PATH . '/templates/list-scans.php'; ?>
91
  <?php } ?>
5
  $button_help_checked = '';
6
  if ( 'current-scan' == $this->action || !empty( $_REQUEST['current_scan'] ) ) {
7
  $button_current_checked = 'checked="checked"';
8
+ } elseif ( 'help' == $this->action ) {
9
  $button_help_checked = 'checked="checked"';
10
  } else {
11
  $button_history_checked = 'checked="checked"';
70
  <input type="radio" name="p3-nav" id="button-help" <?php echo $button_help_checked; ?> /><label for="button-help">Help</label>
71
 
72
  <div id="p3-scan-label">
73
+ <?php if ( !empty( $this->profile ) ) : ?>
74
+ Scan name: <?php echo $this->profile->profile_name; ?>
75
  <?php endif; ?>
76
  </div>
77
  </div>
84
  <?php include_once P3_PATH . '/templates/view-scan.php'; ?>
85
  <?php } elseif ( 'help' == $this->action ) { ?>
86
  <?php include_once P3_PATH . '/templates/help.php'; ?>
 
 
87
  <?php } else { ?>
88
  <?php include_once P3_PATH . '/templates/list-scans.php'; ?>
89
  <?php } ?>
templates/view-scan.php CHANGED
@@ -555,12 +555,14 @@ $component_runtime_chart_id = substr( md5( uniqid() ), -8 );
555
  label: "<?php echo esc_js( $plugin ); ?>",
556
  data: [
557
  <?php foreach ( array_values( $url_stats ) as $k => $v ) { ?>
558
- <?php if ( array_key_exists( $plugin, $v['breakdown'] ) ) { ?>
559
- [
560
- <?php echo $k + 1; ?>,
561
  <?php echo $v['breakdown'][$plugin]; ?>
562
- ],
563
- <?php } ?>
 
 
564
  <?php } ?>
565
  ]
566
  },
@@ -947,7 +949,7 @@ $component_runtime_chart_id = substr( md5( uniqid() ), -8 );
947
  <em class="p3-em">
948
  (<span class="qtip-tip" title="How long the site took to load. This is an observed measurement (start timing
949
  when the page was requested, stop timing when the page was delivered to the browser, calculate the
950
- difference)."><?php printf( '%.4f', $this->profile->averages['observed'] ); ?> observed<span>,
951
  <span class="qtip-tip" title="The expected site load time calculated by adding plugin load time, core
952
  load time, theme load time, and profiler overhead.">
953
  <?php printf( '%.4f', $this->profile->averages['expected'] ); ?> expected</span>)
@@ -1005,26 +1007,26 @@ $component_runtime_chart_id = substr( md5( uniqid() ), -8 );
1005
  <!-- Email results dialog -->
1006
  <div id="p3-email-results-dialog" class="p3-dialog">
1007
  <div>
1008
- From:<br />
1009
  <input type="text" id="p3-email-results-from" style="width:95%;" size="35"
1010
  value="<?php $user = wp_get_current_user(); echo $user->user_email; ?>" title="Enter the e-mail address to send from" />
1011
  </div>
1012
  <br />
1013
  <div>
1014
- Recipient:<br />
1015
  <input type="text" id="p3-email-results-to" style="width:95%;" size="35"
1016
  value="<?php $user = wp_get_current_user(); echo $user->user_email; ?>"
1017
  title="Enter the e-mail address where you would like to send these results" />
1018
  </div>
1019
  <br />
1020
  <div>
1021
- Subject:<br />
1022
  <input type="text" id="p3-email-results-subject" style="width:95%;" size="35"
1023
  value="Performance Profile Results - <?php bloginfo( 'name' ); ?>" title="Enter the e-mail subject" />
1024
  </div>
1025
  <br />
1026
  <div>
1027
- Message: <em class="p3-em">( optional )</em><br />
1028
  <textarea id="p3-email-results-message" style="width: 95%; height: 100px;">Hello,
1029
 
1030
  I profiled my WordPress site's performance using the Profile Plugin and I wanted
@@ -1032,7 +1034,7 @@ to share the results with you. Please take a look at the information below:</te
1032
  </div>
1033
  <br />
1034
  <div>
1035
- Results: <em class="p3-em">( system generated, do not edit )</em><br />
1036
  <textarea disabled="disabled" id="p3-email-results-results" style="width: 95%; height: 120px;"><?php
1037
  echo "WordPress Plugin Profile Report\n";
1038
  echo "===========================================\n";
555
  label: "<?php echo esc_js( $plugin ); ?>",
556
  data: [
557
  <?php foreach ( array_values( $url_stats ) as $k => $v ) { ?>
558
+ [
559
+ <?php echo $k + 1; ?>,
560
+ <?php if ( array_key_exists( $plugin, $v['breakdown'] ) ) : ?>
561
  <?php echo $v['breakdown'][$plugin]; ?>
562
+ <?php else : ?>
563
+ 0
564
+ <?php endif; ?>
565
+ ],
566
  <?php } ?>
567
  ]
568
  },
949
  <em class="p3-em">
950
  (<span class="qtip-tip" title="How long the site took to load. This is an observed measurement (start timing
951
  when the page was requested, stop timing when the page was delivered to the browser, calculate the
952
+ difference)."><?php printf( '%.4f', $this->profile->averages['observed'] ); ?> observed</span>,
953
  <span class="qtip-tip" title="The expected site load time calculated by adding plugin load time, core
954
  load time, theme load time, and profiler overhead.">
955
  <?php printf( '%.4f', $this->profile->averages['expected'] ); ?> expected</span>)
1007
  <!-- Email results dialog -->
1008
  <div id="p3-email-results-dialog" class="p3-dialog">
1009
  <div>
1010
+ <span id="p3-email-from-label">From:</span><br />
1011
  <input type="text" id="p3-email-results-from" style="width:95%;" size="35"
1012
  value="<?php $user = wp_get_current_user(); echo $user->user_email; ?>" title="Enter the e-mail address to send from" />
1013
  </div>
1014
  <br />
1015
  <div>
1016
+ <span id="p3-email-recipient-label">Recipient:</span><br />
1017
  <input type="text" id="p3-email-results-to" style="width:95%;" size="35"
1018
  value="<?php $user = wp_get_current_user(); echo $user->user_email; ?>"
1019
  title="Enter the e-mail address where you would like to send these results" />
1020
  </div>
1021
  <br />
1022
  <div>
1023
+ <span id="p3-email-subject-label">Subject:</span><br />
1024
  <input type="text" id="p3-email-results-subject" style="width:95%;" size="35"
1025
  value="Performance Profile Results - <?php bloginfo( 'name' ); ?>" title="Enter the e-mail subject" />
1026
  </div>
1027
  <br />
1028
  <div>
1029
+ <span id="p3-email-message-label">Message: <em class="p3-em">(optional)</em><br /></span>
1030
  <textarea id="p3-email-results-message" style="width: 95%; height: 100px;">Hello,
1031
 
1032
  I profiled my WordPress site's performance using the Profile Plugin and I wanted
1034
  </div>
1035
  <br />
1036
  <div>
1037
+ <span id="p3-email-results-label">Results: <em class="p3-em">(system generated, do not edit)</em></span><br />
1038
  <textarea disabled="disabled" id="p3-email-results-results" style="width: 95%; height: 120px;"><?php
1039
  echo "WordPress Plugin Profile Report\n";
1040
  echo "===========================================\n";