PluginProbe
Code Profiler – WordPress Performance Profiling and Debugging Made Easy / 1.9.6
Code Profiler – WordPress Performance Profiling and Debugging Made Easy v1.9.6
1.9.6 1.9.5 1.9.4 1.9.3 trunk 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.6 1.6.1 1.6.10 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 All 41 releases
← All changes | lib/helper.php +410 -95 1.6.51.9.6 View file →
@@ -1,6 +1,6 @@
1 1 <?php
2 -/*
2 +/**
3 3 +=====================================================================+
4 4 | ____ _ ____ __ _ _ |
5 5 | / ___|___ __| | ___ | _ \ _ __ ___ / _(_) | ___ _ __ |
6 6 | | | / _ \ / _` |/ _ \ | |_) | '__/ _ \| |_| | |/ _ \ '__| |
@@ -6,66 +6,112 @@
6 6 | | | / _ \ / _` |/ _ \ | |_) | '__/ _ \| |_| | |/ _ \ '__| |
7 7 | | |__| (_) | (_| | __/ | __/| | | (_) | _| | | __/ | |
8 8 | \____\___/ \__,_|\___| |_| |_| \___/|_| |_|_|\___|_| |
9 9 | |
10 - | (c) Jerome Bruandet ~ https://code-profiler.com/ |
10 + | (c) Jerome Bruandet ~ https://nintechnet.com/codeprofiler/ |
11 11 +=====================================================================+
12 12 */
13 13
14 -if (! defined('ABSPATH') ) { die('Forbidden'); }
14 +if (! defined('ABSPATH') ) {
15 + die('Forbidden');
16 +}
15 17
16 18 // =====================================================================
17 19 // Various constants
18 20
19 -$upload_dir = wp_upload_dir();
20 -define('CODE_PROFILER_UPLOAD_DIR', $upload_dir['basedir'] .'/code-profiler');
21 +// The profiles directory can be defined in the wp-config.php script
22 +if (! defined('CODE_PROFILER_UPLOAD_DIR') ) {
23 + // When running Code Profiler via WP CLI on a child site of a multisite installation,
24 + // we need to get the main site upload folder otherwise wp_upload_dir will return
25 + // the child site's
26 + if ( is_multisite() && ! ( is_main_network() && is_main_site() && defined('MULTISITE') ) ) {
27 + $upload_dir = code_profiler_upload_dir();
28 + } else {
29 + $upload_dir = wp_upload_dir();
30 + }
31 + define('CODE_PROFILER_UPLOAD_DIR', $upload_dir['basedir'] .'/code-profiler');
32 +}
21 33 define('CODE_PROFILER_LOG', CODE_PROFILER_UPLOAD_DIR .'/log.php');
22 34 define('CODE_PROFILER_TMP_IOSTATS_LOG', 'iostats.tmp');
23 35 define('CODE_PROFILER_TMP_SUMMARY_LOG', 'summary.tmp');
24 -define('CODE_PROFILER_TMP_TICKS_LOG', 'ticks.tmp');
36 +define('CODE_PROFILER_TMP_RERUN_LOG', 'rerun.tmp');
37 +define('CODE_PROFILER_TMP_CALLS_LOG', 'calls.tmp');
25 38 define('CODE_PROFILER_TMP_DISKIO_LOG', 'diskio.tmp');
26 39 define('CODE_PROFILER_TMP_CONNECTIONS_LOG', 'connections.tmp');
27 40 define('CODE_PROFILER_UPDATE_NOTICE', '<div class="updated notice is-dismissible"><p>%s</p></div>');
28 41 define('CODE_PROFILER_ERROR_NOTICE', '<div class="error notice is-dismissible"><p>%s</p></div>');
29 -global $wp_version;
30 -if (! defined('CODE_PROFILER_UA') ) { // UA signatures can be user-defined in the wp-config.php
31 - define ('CODE_PROFILER_UA', [
32 - esc_html__('Desktop', 'code-profiler') => [
33 - 'Firefox' => 'Mozilla/5.0 (Linux x86_64; rv:110.0) Gecko/20100101 Firefox/110.0',
34 - 'Chrome' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)'.
35 - ' Chrome/111.0.0.0 Safari/537.36',
36 - 'Edge' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,'.
37 - ' like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/110.0.1587.63'
38 - ],
39 - esc_html__('Mobile', 'code-profiler') => [
40 - 'Android Phone' => 'Mozilla/5.0 (Android 13; Mobile; rv:68.0) Gecko/68.0 Firefox/110.0',
41 - 'Android Tablet' => 'Mozilla/5.0 (Linux; Android 13.0; SAMSUNG-SM-T377A Build/NMF26X)'.
42 - ' AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Mobile Safari/537.36',
43 - 'iPhone' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_3_1 like Mac OS X) AppleWebKit/605.1.15'.
44 - ' (KHTML, like Gecko) Version/16.3 Mobile/15E148 Safari/604.1',
45 - 'iPad' => 'Mozilla/5.0 (iPad; CPU OS 16_3_1 like Mac OS X) AppleWebKit/605.1.15'.
46 - ' (KHTML, like Gecko) GSA/213.0.449417121 Mobile/15E148 Safari/605.1.15'
47 - ],
48 - esc_html__('Bot', 'code-profiler') => [
49 - 'Google Bot' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
50 - 'WordPress' => 'Mozilla/5.0 (compatible; CodeProfiler for WordPress/'. $wp_version .
51 - '; https://code-profiler.com/)'
52 - ]
42 +define('CODE_PROFILER_WARNING_NOTICE', '<div class="notice notice-warning"><p>%s</p></div>');
43 +if (! defined('CODE_PROFILER_MUPLUGIN') ) {
44 + // MU plugin's name can be defined in the wp-config.php
45 + define('CODE_PROFILER_MUPLUGIN', '0----code-profiler.php');
46 +}
53 47
54 - ] );
48 +/**
49 + * Since WP 6.7, translation loading must not be triggered too early.
50 + */
51 +add_action('init', 'code_profiler_i18n_constants');
52 +function code_profiler_i18n_constants() {
53 +
54 + global $wp_version;
55 + if (! defined('CODE_PROFILER_UA') ) { // UA signatures can be user-defined in the wp-config.php
56 + define ('CODE_PROFILER_UA', [
57 + esc_html__('Desktop', 'code-profiler') => [
58 + 'Firefox' => 'Mozilla/5.0 (Linux x86_64; rv:149.0) Gecko/20100101 Firefox/149.0',
59 + 'Chrome' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML,'.
60 + ' like Gecko) Chrome/147.0.0.0 Safari/537.36',
61 + 'Edge' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,'.
62 + ' like Gecko) Chrome/147.0.0.0 Safari/537.36 Edg/Chrome/147.0.7727.50'
63 + ],
64 + esc_html__('Mobile', 'code-profiler') => [
65 + 'Android Phone' => 'Mozilla/5.0 (Android 16; Mobile; rv:68.0) Gecko/68.0 Firefox/149.0',
66 + 'Android Tablet' => 'Mozilla/5.0 (Linux; Android 16.0; SAMSUNG-SM-T377A Build/NMF26X)'.
67 + ' AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.7727.50 Mobile Safari/537.36',
68 + 'iPhone' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_7_7 like Mac OS X) AppleWebKit/605.1.15'.
69 + ' (KHTML, like Gecko) Version/26.0 Mobile/15E148 Safari/604.1',
70 + 'iPad' => 'Mozilla/5.0 (iPad; CPU OS 18_7_7 like Mac OS X) AppleWebKit/605.1.15'.
71 + ' (KHTML, like Gecko) GSA/213.0.449417121 Mobile/15E148 Safari/605.1.15'
72 + ],
73 + esc_html__('Bot', 'code-profiler') => [
74 + 'Google Bot' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
75 + 'WordPress' => 'Mozilla/5.0 (compatible; CodeProfiler for WordPress/'. $wp_version .
76 + '; https://nintechnet.com/codeprofiler/)'
77 + ]
78 +
79 + ] );
80 + }
81 + define('CODE_PROFILER_ACCURACY', [
82 + 1 => __('Highest', 'code-profiler'),
83 + 5 => __('High', 'code-profiler'),
84 + 10 => __('Moderate', 'code-profiler'),
85 + 15 => __('Low', 'code-profiler'),
86 + 20 => __('Lowest', 'code-profiler')
87 + ]);
55 88 }
56 89
57 -if (! defined('CODE_PROFILER_MUPLUGIN') ) {
58 - // MU plugin's name can be defined in the wp-config.php
59 - define('CODE_PROFILER_MUPLUGIN', '0----code-profiler.php');
90 +// =====================================================================
91 +// Find the main site upload dir on a multisite installation.
92 +// Used when running the profiler via WP CLI.
93 +// This code is based on the WP private _wp_upload_dir function.
94 +
95 +function code_profiler_upload_dir() {
96 +
97 + $upload_path = trim( get_option('upload_path') );
98 + if ( empty( $upload_path ) || 'wp-content/uploads' === $upload_path ) {
99 + $basedir = WP_CONTENT_DIR . '/uploads';
100 + } elseif ( strpos( $upload_path, ABSPATH ) !== 0 ) {
101 + // $basedir is absolute, $upload_path is (maybe) relative to ABSPATH.
102 + $basedir = path_join( ABSPATH, $upload_path );
103 + } else {
104 + $basedir = $upload_path;
105 + }
106 +
107 + if ( defined('UPLOADS') && ! ( is_multisite() && get_site_option('ms_files_rewriting') ) ) {
108 + $basedir = ABSPATH . UPLOADS;
109 + }
110 +
111 + return ['basedir' => $basedir];
60 112 }
61 -define('CODE_PROFILER_ACCURACY', [
62 - 1 => __('Highest (default)', 'code-profiler'),
63 - 5 => __('High', 'code-profiler'),
64 - 10 => __('Moderate', 'code-profiler'),
65 - 15 => __('Low', 'code-profiler'),
66 - 20 => __('Lowest', 'code-profiler')
67 -]);
113 +
68 114 // =====================================================================
69 115 // Prevent cURL timeout if a plugin changes its timeout options.
70 116
71 117 function code_profiler_curl_timeout( $handle, $parsed_args, $url ) {
@@ -83,34 +129,123 @@
83 129 // Update version in the DB and check if options must be updated.
84 130
85 131 function code_profiler_init_update() {
86 132
87 - $cp_options = get_option('code-profiler');
88 - if ( empty( $cp_options['version'] ) ||
89 - version_compare( $cp_options['version'], CODE_PROFILER_VERSION, '<') ) {
133 + if ( ( $cp_options = get_option('code-profiler') ) == false ) {
134 + /**
135 + * "Automatic conversion of false to array is deprecated" since PHP 8.1
136 + */
137 + $cp_options = [];
138 + }
90 139
140 + if ( empty( $cp_options['version'] ) ) {
91 141 $cp_options['version'] = CODE_PROFILER_VERSION;
142 + update_option('code-profiler', $cp_options );
92 143
144 + } elseif ( version_compare( $cp_options['version'], CODE_PROFILER_VERSION, '<') ) {
145 +
93 146 // Version 1.1
94 - if (! isset( $cp_options['enable_wpcli'] ) ) {
95 - $cp_options['enable_wpcli'] = 1;
147 + if ( version_compare( $cp_options['version'], '1.1', '<' ) ) {
148 + if (! isset( $cp_options['enable_wpcli'] ) ) {
149 + $cp_options['enable_wpcli'] = 1;
150 + }
96 151 }
97 152
98 153 // Version 1.2
99 - if (! isset( $cp_options['disable_wpcron'] ) ) {
100 - $cp_options['disable_wpcron'] = 1;
154 + if ( version_compare( $cp_options['version'], '1.2', '<' ) ) {
155 + if (! isset( $cp_options['disable_wpcron'] ) ) {
156 + $cp_options['disable_wpcron'] = 1;
157 + }
101 158 }
102 159
103 160 // Version 1.3.1
104 - if (! isset( $cp_options['http_response'] ) ) {
105 - $cp_options['http_response'] = '^(?:3|4|5)\d{2}$';
161 + if ( version_compare( $cp_options['version'], '1.3.1', '<' ) ) {
162 + if (! isset( $cp_options['http_response'] ) ) {
163 + $cp_options['http_response'] = '^(?:3|4|5)\d{2}$';
164 + }
106 165 }
107 166
108 167 // Version 1.5
109 - if (! isset( $cp_options['accuracy'] ) ) {
110 - $cp_options['accuracy'] = 1;
168 + if ( version_compare( $cp_options['version'], '1.5', '<' ) ) {
169 + if (! isset( $cp_options['accuracy'] ) ) {
170 + $cp_options['accuracy'] = 1;
171 + }
111 172 }
112 173
174 + // Version 1.7.5
175 + if ( version_compare( $cp_options['version'], '1.7.5', '<' ) ) {
176 + if (! isset( $cp_options['php_error'] ) ) {
177 + $cp_options['php_error'] = 1;
178 + }
179 + }
180 +
181 + // Version 1.8
182 + if ( version_compare( $cp_options['version'], '1.8', '<' ) ) {
183 + if ( isset( $cp_options['mem_where'] ) ) {
184 + $cp_options['mem']['x_end'] = $cp_options['mem_where'];
185 + unset( $cp_options['mem_where'] );
186 + }
187 + if ( isset( $cp_options['mem_post'] ) ) {
188 + $cp_options['mem']['post'] = $cp_options['mem_post'];
189 + unset( $cp_options['mem_post'] );
190 + }
191 + if ( isset( $cp_options['mem_user'] ) ) {
192 + $cp_options['mem']['x_auth'] = $cp_options['mem_user'];
193 + unset( $cp_options['mem_user'] );
194 + }
195 + if ( isset( $cp_options['mem_username'] ) ) {
196 + $cp_options['mem']['username'] = $cp_options['mem_username'];
197 + unset( $cp_options['mem_username'] );
198 + }
199 + if ( isset( $cp_options['mem_method'] ) ) {
200 + $cp_options['mem']['method'] = $cp_options['mem_method'];
201 + unset( $cp_options['mem_method'] );
202 + }
203 + if ( isset( $cp_options['mem_theme'] ) ) {
204 + $cp_options['mem']['theme'] = $cp_options['mem_theme'];
205 + unset( $cp_options['mem_theme'] );
206 + }
207 + if ( isset( $cp_options['ua'] ) ) {
208 + $cp_options['mem']['user_agent'] = $cp_options['ua'];
209 + unset( $cp_options['ua'] );
210 + }
211 + if ( isset( $cp_options['cookies'] ) ) {
212 + $cp_options['mem']['cookies'] = $cp_options['cookies'];
213 + unset( $cp_options['cookies'] );
214 + }
215 + if ( isset( $cp_options['mem_content_type'] ) ) {
216 + $cp_options['mem']['content_type'] = $cp_options['mem_content_type'];
217 + unset( $cp_options['mem_content_type'] );
218 + }
219 + if ( isset( $cp_options['payload'] ) ) {
220 + $cp_options['mem']['payload'] = $cp_options['payload'];
221 + unset( $cp_options['payload'] );
222 + }
223 + if ( isset( $cp_options['custom_headers'] ) ) {
224 + $cp_options['mem']['custom_headers'] = $cp_options['custom_headers'];
225 + unset( $cp_options['custom_headers'] );
226 + }
227 + if ( isset( $cp_options['exclusions'] ) ) {
228 + $cp_options['mem']['exclusions'] = $cp_options['exclusions'];
229 + unset( $cp_options['exclusions'] );
230 + }
231 + }
232 +
233 + // Version 1.8.1
234 + if ( version_compare( $cp_options['version'], '1.8.1', '<' ) ) {
235 + CodeProfiler_WPCron::install();
236 + }
237 +
238 + /**
239 + * Version 1.9.2
240 + */
241 + if ( version_compare( $cp_options['version'], '1.9.2', '<' ) ) {
242 + unset( $cp_options['warn_composer'] );
243 + }
244 +
245 + // Adjust current version
246 + $cp_options['version'] = CODE_PROFILER_VERSION;
247 +
113 248 // Update version in the DB
114 249 update_option('code-profiler', $cp_options );
115 250 }
116 251
@@ -123,13 +258,17 @@
123 258
124 259 function code_profiler_check_uploadsdir() {
125 260
126 261 if (! file_exists( CODE_PROFILER_UPLOAD_DIR ) ) {
127 - mkdir( CODE_PROFILER_UPLOAD_DIR, 0755 );
262 + wp_mkdir_p( CODE_PROFILER_UPLOAD_DIR );
128 263 }
129 - if (! is_writable( CODE_PROFILER_UPLOAD_DIR ) ) {
130 - // PHP running as an Apache module?
131 - chmod( CODE_PROFILER_UPLOAD_DIR, 0777 );
264 + if (! is_writable( CODE_PROFILER_UPLOAD_DIR ) || ! is_dir( CODE_PROFILER_UPLOAD_DIR ) ) {
265 + wp_die(
266 + sprintf(
267 + __('Error: The %s folder cannot be created or is read only', 'code-profiler'),
268 + esc_html( CODE_PROFILER_UPLOAD_DIR ) .'/'
269 + )
270 + );
132 271 }
133 272 if (! file_exists( CODE_PROFILER_UPLOAD_DIR .'/index.html') ) {
134 273 touch( CODE_PROFILER_UPLOAD_DIR .'/index.html');
135 274 }
@@ -244,9 +383,8 @@
244 383 'chart_type' => 'x',
245 384 'chart_max_plugins' => 25,
246 385 'hide_empty_value' => 1,
247 386 'table_max_rows' => 30,
248 - 'warn_composer' => 1,
249 387 'enable_wpcli' => 1,
250 388 'disable_wpcron' => 1,
251 389 'http_response' => '^(?:3|4|5)\d{2}$',
252 390 'accuracy' => 1,
@@ -279,54 +417,75 @@
279 417
280 418 function code_profiler_disable_opcode() {
281 419
282 420 try {
283 - if (extension_loaded('Zend OPcache')) {
421 + if ( extension_loaded('Zend OPcache') ) {
284 422 ini_set('opcache.enable', 0);
285 423 } elseif ( extension_loaded('wincache') ) {
286 424 ini_set('wincache.fcenabled', 0);
287 425 }
288 426 set_time_limit(0);
427 + ini_set('memory_limit', -1);
289 428
290 429 } catch ( Exception $e ) { }
291 430
292 431 $cp_options = get_option('code-profiler');
432 + /**
433 + * Disable WP-CRON.
434 + */
293 435 if (! empty( $cp_options['disable_wpcron'] ) ) {
294 436 if (! defined('DISABLE_WP_CRON') ) {
295 437 define('DISABLE_WP_CRON', true );
296 438 }
297 439 }
440 + /**
441 + * Enable PHP error logging.
442 + */
443 + if (! empty( $cp_options['php_error'] ) ) {
444 + ini_set('log_errors', 1 );
445 + $phplog = ini_get('error_log');
446 + if ( empty( $phplog ) || $phplog === false ) {
447 + ini_set('error_log', WP_CONTENT_DIR .'/debug.log');
448 + } else {
449 + ini_set('error_log', $phplog );
450 + }
451 + }
452 +}
298 453
299 -}
300 454 // =====================================================================
301 -// Verify the security key when running the profile.
455 +// Verify the security key when running the profiler.
302 456
303 457 function code_profiler_verify_key() {
304 458
305 459 $response = [
306 460 'status' => 'error',
307 - 'message' => __('Security keys do not match. Reload the page and try again (%s)', 'code-profiler')
461 + // We cannot load translation here.
462 + 'message' => 'Security keys do not match. Reload the page and try again (%s)'
308 463 ];
309 464
310 - $cp_options = get_option('code-profiler');
465 + if ( empty( $_REQUEST['profiler_key'] ) ) {
466 + $response['message'] = sprintf( $response['message'], '001');
311 467
312 - if ( empty( $cp_options['hash'] ) ) {
313 - $response['message'] = sprintf( $response['message'], '#1');
314 -
315 468 } else {
316 - if ( empty( $_REQUEST['profiler_key'] ) ) {
317 - $response['message'] = sprintf( $response['message'], '#2');
469 + $file = CODE_PROFILER_UPLOAD_DIR .'/key_'. sha1( $_REQUEST['profiler_key'] ) .'.tmp';
470 + if ( file_exists( $file ) ) {
471 + /**
472 + * We limit the TTL to max $expire seconds to match code_profiler_cleantmpfiles().
473 + */
474 + $now = time();
475 + $expire = 20; // seconds
476 + if ( filemtime( $file ) + $expire < $now ) {
477 + $response['message'] = sprintf( $response['message'], '003');
478 + wp_send_json( $response );
479 + }
318 480
319 - } else {
320 - if ( $cp_options['hash'] == sha1( $_REQUEST['profiler_key'] ) ) {
321 - return;
322 - } else {
323 - $response['message'] = sprintf( $response['message'], '#3');
324 - }
481 + // Delete it and accept the request
482 + unlink( $file );
483 + return;
325 484 }
485 + $response['message'] = sprintf( $response['message'], '002');
326 486 }
327 487 wp_send_json( $response );
328 -
329 488 }
330 489
331 490 // =====================================================================
332 491 // Write message to the log.
@@ -362,18 +521,37 @@
362 521 code_profiler_write2log( $string, 8, $create );
363 522 }
364 523
365 524 // =====================================================================
525 +// Retrieve and return matching files from a directory.
526 +
527 +function code_profiler_glob( $directory, $regex, $pathname = false ) {
528 +
529 + $list = [];
530 +
531 + foreach ( new DirectoryIterator( $directory ) as $finfo ) {
532 + if (! $finfo->isDot() && preg_match("`$regex`", $finfo->getFilename() ) ) {
533 + if ( $pathname ) {
534 + $list[] = $finfo->getPathname();
535 + } else {
536 + $list[] = $finfo->getFilename();
537 + }
538 + }
539 + }
540 + return $list;
541 +}
542 +
543 +// =====================================================================
366 544 // Verify if a profile exists and return its full path.
367 545
368 546 function code_profiler_get_profile_path( $id, $type = 'slugs') {
369 547
370 - $return = false;
548 + if (! empty( $id ) && preg_match('/^\d{10}\.\d+$/', $id ) ) {
371 549
372 - if (! empty( $id ) && preg_match('/^\d{10}\.\d+$/', $id ) ) {
373 - $glob = glob( CODE_PROFILER_UPLOAD_DIR ."/$id.*.$type.profile" );
550 + $glob = code_profiler_glob(CODE_PROFILER_UPLOAD_DIR, "$id\..+\.$type\.profile$", true);
551 +
374 552 if ( is_array( $glob ) && ! empty( $glob[0] ) ) {
375 - if ( preg_match( "`/$id\.(.+?).$type.profile$`", $glob[0], $match ) ) {
553 + if ( preg_match( "`$id\.(.+?).$type.profile$`", $glob[0], $match ) ) {
376 554
377 555 return CODE_PROFILER_UPLOAD_DIR. "/$id.{$match[1]}";
378 556 }
379 557 }
@@ -401,10 +579,17 @@
401 579 $buffer['error'] = $err;
402 580 return $buffer;
403 581 }
404 582
583 + /**
584 + * We don't use fgetcsv() as it requires the $escape parameter since PHP 8.4
585 + */
405 586 while (! feof( $fh ) ) {
406 - $buffer[] = fgetcsv( $fh, 1000, "\t" );
587 + $tmp = trim( fgets( $fh, 1000 ) );
588 + if (! $tmp ) {
589 + continue;
590 + }
591 + $buffer[] = explode( "\t", $tmp );
407 592 }
408 593
409 594 fclose( $fh );
410 595
@@ -459,9 +644,9 @@
459 644
460 645 $string = $open;
461 646
462 647 if ( empty( $decode->items ) ) {
463 - $tmp = 'N/A';
648 + $tmp = __('N/A', 'code-profiler');
464 649 } else {
465 650 $tmp = (int) --$decode->items;
466 651 }
467 652 $string .= sprintf(
@@ -471,9 +656,9 @@
471 656
472 657 $string .= $div;
473 658
474 659 if ( empty( $decode->time ) ) {
475 - $tmp = 'N/A';
660 + $tmp = __('N/A', 'code-profiler');
476 661 } else {
477 662 $tmp = number_format( $decode->time, 4 );
478 663 }
479 664 $string .= sprintf(
@@ -483,9 +668,9 @@
483 668
484 669 $string .= $div;
485 670
486 671 if ( empty( $decode->memory ) ) {
487 - $tmp = 'N/A';
672 + $tmp = __('N/A', 'code-profiler');
488 673 } else {
489 674 $tmp = number_format( $decode->memory, 2);
490 675 }
491 676 $string .= sprintf(
@@ -495,9 +680,9 @@
495 680
496 681 $string .= $div;
497 682
498 683 if ( empty( $decode->io ) ) {
499 - $tmp = 'N/A';
684 + $tmp = __('N/A', 'code-profiler');
500 685 } else {
501 686 $tmp = number_format( (int) $decode->io );
502 687 }
503 688 $string .= sprintf(
@@ -507,9 +692,9 @@
507 692
508 693 $string .= $div;
509 694
510 695 if ( empty( $decode->queries ) ) {
511 - $tmp = 'N/A';
696 + $tmp = __('N/A', 'code-profiler');
512 697 } else {
513 698 $tmp = number_format( (int) $decode->queries );
514 699 }
515 700 $string .= sprintf(
@@ -516,8 +701,20 @@
516 701 __('SQL queries: %s', 'code-profiler'),
517 702 $tmp
518 703 );
519 704
705 + $string .= $div;
706 +
707 + if ( empty( CODE_PROFILER_ACCURACY[ $decode->precision ] ) ) {
708 + $tmp = __('N/A', 'code-profiler');
709 + } else {
710 + $tmp = CODE_PROFILER_ACCURACY[ $decode->precision ];
711 + }
712 + $string .= sprintf(
713 + __('Accuracy: %s', 'code-profiler'),
714 + $tmp
715 + );
716 +
520 717 $string .= $close;
521 718
522 719 return $string;
523 720 }
@@ -522,29 +719,49 @@
522 719 return $string;
523 720 }
524 721
525 722 // =====================================================================
526 -// Remove *tmp files left after an HTTP error (4xx or 5xx).
723 +// Remove *tmp files left in the profiles folder.
527 724
528 725 function code_profiler_cleantmpfiles() {
529 726
530 - $glob = glob( CODE_PROFILER_UPLOAD_DIR .'/*.tmp');
727 + $glob = code_profiler_glob( CODE_PROFILER_UPLOAD_DIR, '\.tmp$', true );
728 +
531 729 if ( is_array( $glob ) ) {
532 - $count = 0;
730 +
731 + $now = time();
533 732 foreach( $glob as $file ) {
534 - $count++;
733 + /**
734 + * Temporary files deletion:
735 + * - +20 seconds for temp sessions (to match the TTL checked at runtime).
736 + * - +10 minutes for unmatched temp profiles.
737 + */
738 + if ( strpos( $file, CODE_PROFILER_UPLOAD_DIR .'/key_') === 0 ) {
739 + if ( filemtime( $file ) + 20 > $now ) {
740 + continue;
741 + }
742 + } else {
743 + if ( filemtime( $file ) + 60 * 10 > $now ) {
744 + continue;
745 + }
746 + }
747 + /**
748 + * Delete all temp files.
749 + */
535 750 unlink( $file );
536 751 }
537 - if ( $count ) {
538 - code_profiler_log_info( sprintf(
539 - __('Deleting %s temporary files found in the profiles folder', 'code-profiler'),
540 - (int) $count
541 - ) );
542 - }
543 752 }
544 753 }
545 754
546 755 // =====================================================================
756 +// Remove non-ASCII characters from a string.
757 +
758 +function code_profiler_ASCII_filter( $string ) {
759 +
760 + return preg_replace('/[\x00-\x1f\x7f-\xff]/', '', $string );
761 +}
762 +
763 +// =====================================================================
547 764 // Clear the log if it's bigger than 100KB.
548 765
549 766 function code_profiler_clearlog() {
550 767
@@ -573,12 +790,110 @@
573 790 esc_html(
574 791 'Thank you for using %sCode Profiler%s.',
575 792 'code-profiler'
576 793 ),
577 - '<a href="https://code-profiler.com" target="_blank">',
794 + '<a href="https://nintechnet.com/codeprofiler/" target="_blank">',
578 795 '</a>'
579 796 ).
580 797 '</span>';
798 +}
799 +
800 +
801 +// =====================================================================
802 +// Hide/display an element depending on some value.
803 +
804 +function code_profiler_showhide( $var, $val ) {
805 +
806 + if ( $var == $val ) {
807 + echo " style='display:block'";
808 + } else {
809 + echo " style='display:none'";
810 + }
811 +}
812 +
813 +// =====================================================================
814 +// Retrieve all themes.
815 +
816 +function code_profiler_get_themes() {
817 +
818 + $list = [];
819 +
820 + // Make sure the function is loaded
821 + if (! function_exists('wp_get_themes') ) {
822 + require_once ABSPATH . 'wp-includes/theme.php';
823 + }
824 + $themes = wp_get_themes();
825 + foreach( $themes as $k => $v ) {
826 + if ( $v->Name ) {
827 + $list[ $k ] = [
828 + 'n' => $v->Name,
829 +
830 + 't' => $v->Template
831 + ];
832 + } else {
833 + $list[ $k ] = [
834 + 'n' => $k,
835 + 't' => $v->Template
836 + ];
837 + }
838 + }
839 + return $list;
840 +}
841 +
842 +// =====================================================================
843 +// Retrieve all available cron events.
844 +
845 +function code_profiler_get_crons() {
846 +
847 + $list = [];
848 +
849 + $wp_crons = _get_cron_array();
850 +
851 + if ( empty( $wp_crons ) ) {
852 + return $list;
853 + }
854 +
855 + foreach ( $wp_crons as $timestamp => $cronhooks ) {
856 + foreach ( $cronhooks as $hook => $keys ) {
857 + $list[] = $hook;
858 + }
859 + }
860 + sort( $list );
861 + return $list;
862 +}
863 +
864 +// =====================================================================
865 +// Create a file with the ABSPATH.
866 +
867 +function code_profiler_create_tmpfile() {
868 +
869 + $tmp_folder = dirname( __DIR__ ) .'/tmp';
870 + $tmp_file = "$tmp_folder/profiler.inc.php";
871 +
872 + if (! is_dir( $tmp_folder ) ) {
873 + $res = @ mkdir( $tmp_folder );
874 + if ( false === $res ) {
875 + return sprintf(
876 + __('Cannot create temporary folder: [%s]. Any attempt to profile a cron event will likely fail.', 'code-profiler'),
877 + $tmp_folder
878 + );
879 + }
880 + }
881 +
882 + if (! is_file( "$tmp_folder/index.html" ) ) {
883 + touch( "$tmp_folder/index.html" );
884 + }
885 +
886 + $res = @ file_put_contents(
887 + $tmp_file,
888 + "<?php\nconst ABSPATH = '". ABSPATH ."';\n"
889 + );
890 + if ( false === $res ) {
891 + return sprintf(
892 + __('Cannot create temporary file: [%s]. Any attempt to profile a cron event will likely fail.', 'code-profiler'),
893 + $tmp_file
894 + );
895 + }
581 896 }
582 897
583 898 // =====================================================================
584 899 // EOF