PluginProbe
Code Profiler – WordPress Performance Profiling and Debugging Made Easy / 1.7.4
Code Profiler – WordPress Performance Profiling and Debugging Made Easy v1.7.4
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 1.6.8 All 40 releases
← All changes | lib/helper.php +350 -92 1.51.7.4 View file →
@@ -1,6 +1,6 @@
1 1 <?php
2 -/*
2 +/**
3 3 +=====================================================================+
4 4 | ____ _ ____ __ _ _ |
5 5 | / ___|___ __| | ___ | _ \ _ __ ___ / _(_) | ___ _ __ |
6 6 | | | / _ \ / _` |/ _ \ | |_) | '__/ _ \| |_| | |/ _ \ '__| |
@@ -6,66 +6,125 @@
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_CALLS_LOG', 'calls.tmp');
25 37 define('CODE_PROFILER_TMP_DISKIO_LOG', 'diskio.tmp');
38 +define('CODE_PROFILER_TMP_CONNECTIONS_LOG', 'connections.tmp');
26 39 define('CODE_PROFILER_UPDATE_NOTICE', '<div class="updated notice is-dismissible"><p>%s</p></div>');
27 40 define('CODE_PROFILER_ERROR_NOTICE', '<div class="error notice is-dismissible"><p>%s</p></div>');
28 -global $wp_version;
29 -if (! defined('CODE_PROFILER_UA') ) { // UA signatures can be user-defined in the wp-config.php
30 - define ('CODE_PROFILER_UA', [
31 - esc_html__('Desktop', 'code-profiler') => [
32 - 'Firefox' => 'Mozilla/5.0 (Linux x86_64; rv:104.0) Gecko/20100101 Firefox/104.0',
33 - 'Chrome' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)'.
34 - ' Chrome/105.0.0.0 Safari/537.36',
35 - 'Edge' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,'.
36 - ' like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.27'
37 - ],
38 - esc_html__('Mobile', 'code-profiler') => [
39 - 'Android Phone' => 'Mozilla/5.0 (Android 12; Mobile; rv:68.0) Gecko/68.0 Firefox/104.0',
40 - 'Android Tablet' => 'Mozilla/5.0 (Linux; Android 12.0; SAMSUNG-SM-T377A Build/NMF26X)'.
41 - ' AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Mobile Safari/537.36',
42 - 'iPhone' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_5 like Mac OS X) AppleWebKit/605.1.15'.
43 - ' (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1',
44 - 'iPad' => 'Mozilla/5.0 (iPad; CPU OS 15_5 like Mac OS X) AppleWebKit/605.1.15'.
45 - ' (KHTML, like Gecko) GSA/213.0.449417121 Mobile/15E148 Safari/604.1'
46 - ],
47 - esc_html__('Bot', 'code-profiler') => [
48 - 'Google Bot' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
49 - 'WordPress' => 'Mozilla/5.0 (compatible; CodeProfiler for WordPress/'. $wp_version .
50 - '; https://code-profiler.com/)'
51 - ]
41 +if (! defined('CODE_PROFILER_MUPLUGIN') ) {
42 + // MU plugin's name can be defined in the wp-config.php
43 + define('CODE_PROFILER_MUPLUGIN', '0----code-profiler.php');
44 +}
52 45
53 - ] );
46 +/**
47 + * Since WP 6.7, translation loading must not be triggered too early.
48 + */
49 +add_action('init', 'code_profiler_i18n_constants');
50 +function code_profiler_i18n_constants() {
51 +
52 + global $wp_version;
53 + if (! defined('CODE_PROFILER_UA') ) { // UA signatures can be user-defined in the wp-config.php
54 + define ('CODE_PROFILER_UA', [
55 + esc_html__('Desktop', 'code-profiler') => [
56 + 'Firefox' => 'Mozilla/5.0 (Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0',
57 + 'Chrome' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML,'.
58 + ' like Gecko) Chrome/133.0.0.0 Safari/537.36',
59 + 'Edge' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,'.
60 + ' like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/131.0.2903.86'
61 + ],
62 + esc_html__('Mobile', 'code-profiler') => [
63 + 'Android Phone' => 'Mozilla/5.0 (Android 15; Mobile; rv:68.0) Gecko/68.0 Firefox/135.0',
64 + 'Android Tablet' => 'Mozilla/5.0 (Linux; Android 15.0; SAMSUNG-SM-T377A Build/NMF26X)'.
65 + ' AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Mobile Safari/537.36',
66 + 'iPhone' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_7_2 like Mac OS X) AppleWebKit/605.1.15'.
67 + ' (KHTML, like Gecko) Version/17_7_2 Mobile/15E148 Safari/604.1',
68 + 'iPad' => 'Mozilla/5.0 (iPad; CPU OS 17_7_2 like Mac OS X) AppleWebKit/605.1.15'.
69 + ' (KHTML, like Gecko) GSA/213.0.449417121 Mobile/15E148 Safari/605.1.15'
70 + ],
71 + esc_html__('Bot', 'code-profiler') => [
72 + 'Google Bot' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
73 + 'WordPress' => 'Mozilla/5.0 (compatible; CodeProfiler for WordPress/'. $wp_version .
74 + '; https://nintechnet.com/codeprofiler/)'
75 + ]
76 +
77 + ] );
78 + }
79 + define('CODE_PROFILER_ACCURACY', [
80 + 1 => __('Highest', 'code-profiler'),
81 + 5 => __('High', 'code-profiler'),
82 + 10 => __('Moderate', 'code-profiler'),
83 + 15 => __('Low', 'code-profiler'),
84 + 20 => __('Lowest', 'code-profiler')
85 + ]);
54 86 }
55 87
56 -if (! defined('CODE_PROFILER_MUPLUGIN') ) {
57 - // MU plugin's name can be defined in the wp-config.php
58 - define('CODE_PROFILER_MUPLUGIN', '0----code-profiler.php');
88 +// =====================================================================
89 +// Find the main site upload dir on a multisite installation.
90 +// Used when running the profiler via WP CLI.
91 +// This code is based on the WP private _wp_upload_dir function.
92 +
93 +function code_profiler_upload_dir() {
94 +
95 + $upload_path = trim( get_option('upload_path') );
96 + if ( empty( $upload_path ) || 'wp-content/uploads' === $upload_path ) {
97 + $basedir = WP_CONTENT_DIR . '/uploads';
98 + } elseif ( strpos( $upload_path, ABSPATH ) !== 0 ) {
99 + // $basedir is absolute, $upload_path is (maybe) relative to ABSPATH.
100 + $basedir = path_join( ABSPATH, $upload_path );
101 + } else {
102 + $basedir = $upload_path;
103 + }
104 +
105 + if ( defined('UPLOADS') && ! ( is_multisite() && get_site_option('ms_files_rewriting') ) ) {
106 + $basedir = ABSPATH . UPLOADS;
107 + }
108 +
109 + return ['basedir' => $basedir];
59 110 }
60 -define('CODE_PROFILER_ACCURACY', [
61 - 1 => __('Highest (default)', 'code-profiler'),
62 - 5 => __('High', 'code-profiler'),
63 - 10 => __('Moderate', 'code-profiler'),
64 - 15 => __('Low', 'code-profiler'),
65 - 20 => __('Lowest', 'code-profiler')
66 -]);
111 +
67 112 // =====================================================================
113 +// Prevent cURL timeout if a plugin changes its timeout options.
114 +
115 +function code_profiler_curl_timeout( $handle, $parsed_args, $url ) {
116 +
117 + if ( isset( $_REQUEST['action'] ) &&
118 + $_REQUEST['action'] == 'codeprofiler_start_profiler') {
119 +
120 + curl_setopt( $handle, CURLOPT_CONNECTTIMEOUT, 300 );
121 + curl_setopt( $handle, CURLOPT_TIMEOUT, 300 );
122 + }
123 +}
124 +add_action('http_api_curl', 'code_profiler_curl_timeout', 1000, 3 );
125 +
126 +// =====================================================================
68 127 // Update version in the DB and check if options must be updated.
69 128
70 129 function code_profiler_init_update() {
71 130
@@ -110,8 +169,12 @@
110 169
111 170 if (! file_exists( CODE_PROFILER_UPLOAD_DIR ) ) {
112 171 mkdir( CODE_PROFILER_UPLOAD_DIR, 0755 );
113 172 }
173 + if (! is_writable( CODE_PROFILER_UPLOAD_DIR ) ) {
174 + // PHP running as an Apache module?
175 + chmod( CODE_PROFILER_UPLOAD_DIR, 0777 );
176 + }
114 177 if (! file_exists( CODE_PROFILER_UPLOAD_DIR .'/index.html') ) {
115 178 touch( CODE_PROFILER_UPLOAD_DIR .'/index.html');
116 179 }
117 180 // For Apache & Litespeed
@@ -128,8 +191,17 @@
128 191
129 192
130 193 if (! file_exists( WPMU_PLUGIN_DIR .'/'. CODE_PROFILER_MUPLUGIN ) ) {
131 194
195 + if (! is_writable( WPMU_PLUGIN_DIR ) ) {
196 + wp_die(
197 + sprintf(
198 + __('Error: The MU folder is read only, please make it writable: %s', 'code-profiler'),
199 + esc_html( WPMU_PLUGIN_DIR ) .'/'
200 + )
201 + );
202 + }
203 +
132 204 if (! file_exists( __DIR__ .'/mu.plugin') ) {
133 205 code_profiler_log_error( sprintf(
134 206 esc_html__('Cannot find the MU plugin: %s', 'code-profiler'),
135 207 __DIR__ .'/mu.plugin'
@@ -157,12 +229,59 @@
157 229
158 230 }
159 231
160 232 // =====================================================================
233 +// Check the PHP memory limit and return a suggested size
234 +// for the profiler's buffer.
235 +
236 +function code_profiler_suggested_memory() {
237 +
238 + $memory_limit = ini_get('memory_limit');
239 +
240 + if ('-1' == $memory_limit ) {
241 + // Return max size
242 + return 10;
243 + }
244 +
245 + if ( preg_match('/^(\d+)([PTGMK])$/i', $memory_limit, $match ) ) {
246 + $bytes = (int) $match[1];
247 + switch ( strtoupper( $match[2] ) ) {
248 + case 'P':
249 + $bytes *= 1024;
250 + case 'T':
251 + $bytes *= 1024;
252 + case 'G':
253 + $bytes *= 1024;
254 + case 'M':
255 + $bytes *= 1024;
256 + case 'K':
257 + $bytes *= 1024;
258 + }
259 + // 256 MB
260 + if ( $bytes >= 268435456 ) {
261 + return 10;
262 + // 128 MB
263 + } elseif ( $bytes >= 134217728 ) {
264 + return 7;
265 + // 64 MB
266 + } elseif ( $bytes >= 67108864 ) {
267 + return 4;
268 + // <64 MB
269 + } else {
270 + return 1;
271 + }
272 + }
273 + // Don't know :/
274 + return 5;
275 +}
276 +
277 +// =====================================================================
161 278 // Create the default options.
162 279
163 280 function code_profiler_default_options() {
164 281
282 + $buffer = code_profiler_suggested_memory();
283 +
165 284 $cp_options = [
166 285 'show_paths' => 'relative',
167 286 'display_name' => 'full',
168 287 'truncate_name' => 30,
@@ -173,9 +292,10 @@
173 292 'warn_composer' => 1,
174 293 'enable_wpcli' => 1,
175 294 'disable_wpcron' => 1,
176 295 'http_response' => '^(?:3|4|5)\d{2}$',
177 - 'accuracy' => 1
296 + 'accuracy' => 1,
297 + 'buffer' => (int) $buffer
178 298 ];
179 299
180 300 update_option('code-profiler', $cp_options );
181 301
@@ -180,15 +300,23 @@
180 300 update_option('code-profiler', $cp_options );
181 301
182 302 }
183 303
184 -// =====================================================================
304 +// ===================================================================== 2023-06-14
185 305 // Create a profile name.
186 306
187 307 function code_profiler_profile_name() {
188 308
189 309 return date('Y-m-d_') . substr( time(), 4 );
310 +}
190 311
312 +// ===================================================================== 2023-06-14
313 +// Disable PHP display_errors so that notice, warning and error messages
314 +// don't show up in the AJAX response.
315 +
316 +function code_profiler_hide_errors() {
317 +
318 + ini_set('display_errors', 0 );
191 319 }
192 320
193 321 // =====================================================================
194 322 // Disable opcode cache.
@@ -195,14 +323,15 @@
195 323
196 324 function code_profiler_disable_opcode() {
197 325
198 326 try {
199 - if (extension_loaded('Zend OPcache')) {
327 + if ( extension_loaded('Zend OPcache') ) {
200 328 ini_set('opcache.enable', 0);
201 329 } elseif ( extension_loaded('wincache') ) {
202 330 ini_set('wincache.fcenabled', 0);
203 331 }
204 332 set_time_limit(0);
333 + ini_set('memory_limit', -1);
205 334
206 335 } catch ( Exception $e ) { }
207 336
208 337 $cp_options = get_option('code-profiler');
@@ -210,36 +339,32 @@
210 339 if (! defined('DISABLE_WP_CRON') ) {
211 340 define('DISABLE_WP_CRON', true );
212 341 }
213 342 }
343 +}
214 344
215 -}
216 345 // =====================================================================
217 -// Verify the security key when running the profile.
346 +// Verify the security key when running the profiler.
218 347
219 348 function code_profiler_verify_key() {
220 349
221 350 $response = [
222 351 'status' => 'error',
223 - 'message' => __('Security keys do not match. Reload the page and try again (%s)', 'code-profiler')
352 + 'message' => __('Security keys do not match. Reload the page and try again (%s)',
353 + 'code-profiler')
224 354 ];
225 355
226 - $cp_options = get_option('code-profiler');
356 + if ( empty( $_REQUEST['profiler_key'] ) ) {
357 + $response['message'] = sprintf( $response['message'], '001');
227 358
228 - if ( empty( $cp_options['hash'] ) ) {
229 - $response['message'] = sprintf( $response['message'], '#1');
230 -
231 359 } else {
232 - if ( empty( $_REQUEST['profiler_key'] ) ) {
233 - $response['message'] = sprintf( $response['message'], '#2');
234 -
235 - } else {
236 - if ( $cp_options['hash'] == sha1( $_REQUEST['profiler_key'] ) ) {
237 - return;
238 - } else {
239 - $response['message'] = sprintf( $response['message'], '#3');
240 - }
360 + $file = CODE_PROFILER_UPLOAD_DIR .'/key_'. sha1( $_REQUEST['profiler_key'] ) .'.tmp';
361 + if ( file_exists( $file ) ) {
362 + // Delete it and accept the request
363 + unlink( $file );
364 + return;
241 365 }
366 + $response['message'] = sprintf( $response['message'], '002');
242 367 }
243 368 wp_send_json( $response );
244 369
245 370 }
@@ -245,30 +370,70 @@
245 370 }
246 371
247 372 // =====================================================================
248 373 // Write message to the log.
249 -// Log level can be a combination of INFO (1), WARN (2) and ERROR (4).
374 +// Log level can be a combination of INFO (1), WARN (2), ERROR (4)
375 +// and DEBUG (8).
250 376
251 -function code_profiler_write2log( $message, $level = 1 ) {
377 +function code_profiler_write2log( $message, $level, $create ) {
252 378
253 - file_put_contents( CODE_PROFILER_LOG, time() ."~~$level~~$message\n", FILE_APPEND );
379 + if ( empty( $create ) ) {
380 + file_put_contents(
381 + CODE_PROFILER_LOG,
382 + time() ."~~$level~~$message\n",
383 + FILE_APPEND
384 + );
385 + } else {
386 + file_put_contents(
387 + CODE_PROFILER_LOG,
388 + time() ."~~$level~~$message\n"
389 + );
390 + }
254 391 }
255 392
256 -function code_profiler_log_info( $string ) { code_profiler_write2log( $string, 1 ); }
257 -function code_profiler_log_warn( $string ) { code_profiler_write2log( $string, 2 ); }
258 -function code_profiler_log_error( $string ) { code_profiler_write2log( $string, 4 ); }
393 +function code_profiler_log_info( $string, $create = 0 ) {
394 + code_profiler_write2log( $string, 1, $create );
395 +}
396 +function code_profiler_log_warn( $string, $create = 0 ) {
397 + code_profiler_write2log( $string, 2, $create );
398 +}
399 +function code_profiler_log_error( $string, $create = 0 ) {
400 + code_profiler_write2log( $string, 4, $create );
401 +}
402 +function code_profiler_log_debug( $string, $create = 0 ) {
403 + code_profiler_write2log( $string, 8, $create );
404 +}
259 405
260 406 // =====================================================================
407 +// Retrieve and return matching files from a directory.
408 +
409 +function code_profiler_glob( $directory, $regex, $pathname = false ) {
410 +
411 + $list = [];
412 +
413 + foreach ( new DirectoryIterator( $directory ) as $finfo ) {
414 + if (! $finfo->isDot() && preg_match("`$regex`", $finfo->getFilename() ) ) {
415 + if ( $pathname ) {
416 + $list[] = $finfo->getPathname();
417 + } else {
418 + $list[] = $finfo->getFilename();
419 + }
420 + }
421 + }
422 + return $list;
423 +}
424 +
425 +// =====================================================================
261 426 // Verify if a profile exists and return its full path.
262 427
263 428 function code_profiler_get_profile_path( $id, $type = 'slugs') {
264 429
265 - $return = false;
430 + if (! empty( $id ) && preg_match('/^\d{10}\.\d+$/', $id ) ) {
266 431
267 - if (! empty( $id ) && preg_match('/^\d{10}\.\d+$/', $id ) ) {
268 - $glob = glob( CODE_PROFILER_UPLOAD_DIR ."/$id.*.$type.profile" );
432 + $glob = code_profiler_glob(CODE_PROFILER_UPLOAD_DIR, "$id\..+\.$type\.profile$", true);
433 +
269 434 if ( is_array( $glob ) && ! empty( $glob[0] ) ) {
270 - if ( preg_match( "`/$id\.(.+?).$type.profile$`", $glob[0], $match ) ) {
435 + if ( preg_match( "`$id\.(.+?).$type.profile$`", $glob[0], $match ) ) {
271 436
272 437 return CODE_PROFILER_UPLOAD_DIR. "/$id.{$match[1]}";
273 438 }
274 439 }
@@ -296,10 +461,17 @@
296 461 $buffer['error'] = $err;
297 462 return $buffer;
298 463 }
299 464
465 + /**
466 + * We don't use fgetcsv() as it requires the $escape parameter since PHP 8.4
467 + */
300 468 while (! feof( $fh ) ) {
301 - $buffer[] = fgetcsv( $fh, 1000, "\t" );
469 + $tmp = trim( fgets( $fh, 1000 ) );
470 + if (! $tmp ) {
471 + continue;
472 + }
473 + $buffer[] = explode( "\t", $tmp );
302 474 }
303 475
304 476 fclose( $fh );
305 477
@@ -354,56 +526,77 @@
354 526
355 527 $string = $open;
356 528
357 529 if ( empty( $decode->items ) ) {
358 - return false;
530 + $tmp = __('N/A', 'code-profiler');
531 + } else {
532 + $tmp = (int) --$decode->items;
359 533 }
360 - $decode->items--;
361 534 $string .= sprintf(
362 535 __('%s plugins and 1 theme', 'code-profiler'),
363 - (int) $decode->items
536 + $tmp
364 537 );
365 538
366 539 $string .= $div;
367 540
368 541 if ( empty( $decode->time ) ) {
369 - return false;
542 + $tmp = __('N/A', 'code-profiler');
543 + } else {
544 + $tmp = number_format( $decode->time, 4 );
370 545 }
371 546 $string .= sprintf(
372 547 __('Execution time: %ss', 'code-profiler'),
373 - number_format( $decode->time, 4 )
548 + $tmp
374 549 );
375 550
376 551 $string .= $div;
377 552
378 553 if ( empty( $decode->memory ) ) {
379 - return false;
554 + $tmp = __('N/A', 'code-profiler');
555 + } else {
556 + $tmp = number_format( $decode->memory, 2);
380 557 }
381 558 $string .= sprintf(
382 559 __('Peak memory: %s MB', 'code-profiler'),
383 - number_format( $decode->memory, 2)
560 + $tmp
384 561 );
385 562
386 563 $string .= $div;
387 564
388 565 if ( empty( $decode->io ) ) {
389 - return false;
566 + $tmp = __('N/A', 'code-profiler');
567 + } else {
568 + $tmp = number_format( (int) $decode->io );
390 569 }
391 570 $string .= sprintf(
392 571 __('File I/O operations: %s', 'code-profiler'),
393 - number_format( $decode->io )
572 + $tmp
394 573 );
395 574
396 575 $string .= $div;
397 576
398 577 if ( empty( $decode->queries ) ) {
399 - return false;
578 + $tmp = __('N/A', 'code-profiler');
579 + } else {
580 + $tmp = number_format( (int) $decode->queries );
400 581 }
401 582 $string .= sprintf(
402 583 __('SQL queries: %s', 'code-profiler'),
403 - number_format( $decode->queries )
584 + $tmp
404 585 );
405 586
587 + $string .= $div;
588 +
589 + if ( empty( CODE_PROFILER_ACCURACY[ $decode->precision ] ) ) {
590 + $tmp = __('N/A', 'code-profiler');
591 + } else {
592 + $tmp = CODE_PROFILER_ACCURACY[ $decode->precision ];
593 + }
594 + $string .= sprintf(
595 + __('Accuracy: %s', 'code-profiler'),
596 + $tmp
597 + );
598 +
406 599 $string .= $close;
407 600
408 601 return $string;
409 602 }
@@ -408,29 +601,40 @@
408 601 return $string;
409 602 }
410 603
411 604 // =====================================================================
412 -// Remove *tmp files left after an HTTP error (4xx or 5xx).
605 +// Remove *tmp files left in the profiles folder.
413 606
414 607 function code_profiler_cleantmpfiles() {
415 608
416 - $glob = glob( CODE_PROFILER_UPLOAD_DIR .'/*.tmp');
609 + $glob = code_profiler_glob( CODE_PROFILER_UPLOAD_DIR, '\.tmp$', true );
610 +
417 611 if ( is_array( $glob ) ) {
418 - $count = 0;
419 612 foreach( $glob as $file ) {
420 - $count++;
421 613 unlink( $file );
422 614 }
423 - if ( $count ) {
424 - code_profiler_log_info( sprintf(
425 - __('Deleting %s temporary files found in the profiles folder', 'code-profiler'),
426 - (int) $count
427 - ) );
428 - }
429 615 }
430 616 }
431 617
432 618 // =====================================================================
619 +// Remove non-ASCII characters from a string.
620 +
621 +function code_profiler_ASCII_filter( $string ) {
622 +
623 + return preg_replace('/[\x00-\x1f\x7f-\xff]/', '', $string );
624 +}
625 +
626 +// =====================================================================
627 +// Clear the log if it's bigger than 100KB.
628 +
629 +function code_profiler_clearlog() {
630 +
631 + if ( file_exists( CODE_PROFILER_LOG ) && filesize( CODE_PROFILER_LOG ) > 100000 ) {
632 + file_put_contents( CODE_PROFILER_LOG, "<?php exit; ?>\n" );
633 + }
634 +}
635 +
636 +// ===================================================================== 2023-06-15
433 637 // We don't want to be bothered by other themes/plugins' admin notices.
434 638
435 639 add_action('admin_head', 'code_profiler_hide_admin_notices');
436 640
@@ -437,9 +641,63 @@
437 641 function code_profiler_hide_admin_notices() {
438 642 if ( isset( $_GET['page'] ) && $_GET['page'] == 'code-profiler') {
439 643 remove_all_actions('admin_notices');
440 644 remove_all_actions('all_admin_notices');
645 + add_filter('admin_footer_text', 'code_profiler_admin_footer');
441 646 }
647 +}
648 +
649 +function code_profiler_admin_footer () {
650 + echo '<span id="footer-thankyou">'.
651 + sprintf(
652 + /* Translators: %s are the '<a href="">' and '</a>' anchors */
653 + esc_html(
654 + 'Thank you for using %sCode Profiler%s.',
655 + 'code-profiler'
656 + ),
657 + '<a href="https://nintechnet.com/codeprofiler/" target="_blank">',
658 + '</a>'
659 + ).
660 + '</span>';
661 +}
662 +
663 +// =====================================================================
664 +// Display/hide an element depending on some value
665 +
666 +function code_profiler_hide( $var, $val ) {
667 +
668 + if ( $var == $val ) {
669 + echo " style='display:none'";
670 + }
671 +}
672 +
673 +// =====================================================================
674 +// Retrieve all themes.
675 +
676 +function code_profiler_get_themes() {
677 +
678 + $list = [];
679 +
680 + // Make sure the function is loaded
681 + if (! function_exists('wp_get_themes') ) {
682 + require_once ABSPATH . 'wp-includes/theme.php';
683 + }
684 + $themes = wp_get_themes();
685 + foreach( $themes as $k => $v ) {
686 + if ( $v->Name ) {
687 + $list[ $k ] = [
688 + 'n' => $v->Name,
689 +
690 + 't' => $v->Template
691 + ];
692 + } else {
693 + $list[ $k ] = [
694 + 'n' => $k,
695 + 't' => $v->Template
696 + ];
697 + }
698 + }
699 + return $list;
442 700 }
443 701
444 702 // =====================================================================
445 703 // EOF