PluginProbe
Code Profiler – WordPress Performance Profiling and Debugging Made Easy / 1.8.2
Code Profiler – WordPress Performance Profiling and Debugging Made Easy v1.8.2
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
code-profiler / lib / helper.php

helper.php in Code Profiler – WordPress Performance Profiling and Debugging Made Easy 1.8.2, at lib/helper.php

803 lines 22.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 +=====================================================================+
4 | ____ _ ____ __ _ _ |
5 | / ___|___ __| | ___ | _ \ _ __ ___ / _(_) | ___ _ __ |
6 | | | / _ \ / _` |/ _ \ | |_) | '__/ _ \| |_| | |/ _ \ '__| |
7 | | |__| (_) | (_| | __/ | __/| | | (_) | _| | | __/ | |
8 | \____\___/ \__,_|\___| |_| |_| \___/|_| |_|_|\___|_| |
9 | |
10 | (c) Jerome Bruandet ~ https://nintechnet.com/codeprofiler/ |
11 +=====================================================================+
12 */
13
14 if (! defined('ABSPATH') ) {
15 die('Forbidden');
16 }
17
18 // =====================================================================
19 // Various constants
20
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 }
33 define('CODE_PROFILER_LOG', CODE_PROFILER_UPLOAD_DIR .'/log.php');
34 define('CODE_PROFILER_TMP_IOSTATS_LOG', 'iostats.tmp');
35 define('CODE_PROFILER_TMP_SUMMARY_LOG', 'summary.tmp');
36 define('CODE_PROFILER_TMP_RERUN_LOG', 'rerun.tmp');
37 define('CODE_PROFILER_TMP_CALLS_LOG', 'calls.tmp');
38 define('CODE_PROFILER_TMP_DISKIO_LOG', 'diskio.tmp');
39 define('CODE_PROFILER_TMP_CONNECTIONS_LOG', 'connections.tmp');
40 define('CODE_PROFILER_UPDATE_NOTICE', '<div class="updated notice is-dismissible"><p>%s</p></div>');
41 define('CODE_PROFILER_ERROR_NOTICE', '<div class="error notice is-dismissible"><p>%s</p></div>');
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 }
47
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:135.0) Gecko/20100101 Firefox/135.0',
59 'Chrome' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML,'.
60 ' like Gecko) Chrome/133.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/133.0.0.0 Safari/537.36 Edg/131.0.2903.86'
63 ],
64 esc_html__('Mobile', 'code-profiler') => [
65 'Android Phone' => 'Mozilla/5.0 (Android 15; Mobile; rv:68.0) Gecko/68.0 Firefox/135.0',
66 'Android Tablet' => 'Mozilla/5.0 (Linux; Android 15.0; SAMSUNG-SM-T377A Build/NMF26X)'.
67 ' AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Mobile Safari/537.36',
68 'iPhone' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_7_2 like Mac OS X) AppleWebKit/605.1.15'.
69 ' (KHTML, like Gecko) Version/17_7_2 Mobile/15E148 Safari/604.1',
70 'iPad' => 'Mozilla/5.0 (iPad; CPU OS 17_7_2 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 ]);
88 }
89
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];
112 }
113
114 // =====================================================================
115 // Prevent cURL timeout if a plugin changes its timeout options.
116
117 function code_profiler_curl_timeout( $handle, $parsed_args, $url ) {
118
119 if ( isset( $_REQUEST['action'] ) &&
120 $_REQUEST['action'] == 'codeprofiler_start_profiler') {
121
122 curl_setopt( $handle, CURLOPT_CONNECTTIMEOUT, 300 );
123 curl_setopt( $handle, CURLOPT_TIMEOUT, 300 );
124 }
125 }
126 add_action('http_api_curl', 'code_profiler_curl_timeout', 1000, 3 );
127
128 // =====================================================================
129 // Update version in the DB and check if options must be updated.
130
131 function code_profiler_init_update() {
132
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 }
139
140 if ( empty( $cp_options['version'] ) ||
141 version_compare( $cp_options['version'], CODE_PROFILER_VERSION, '<') ) {
142
143 // Version 1.1
144 if ( version_compare( $cp_options['version'], '1.1', '<' ) ) {
145 if (! isset( $cp_options['enable_wpcli'] ) ) {
146 $cp_options['enable_wpcli'] = 1;
147 }
148 }
149
150 // Version 1.2
151 if ( version_compare( $cp_options['version'], '1.2', '<' ) ) {
152 if (! isset( $cp_options['disable_wpcron'] ) ) {
153 $cp_options['disable_wpcron'] = 1;
154 }
155 }
156
157 // Version 1.3.1
158 if ( version_compare( $cp_options['version'], '1.3.1', '<' ) ) {
159 if (! isset( $cp_options['http_response'] ) ) {
160 $cp_options['http_response'] = '^(?:3|4|5)\d{2}$';
161 }
162 }
163
164 // Version 1.5
165 if ( version_compare( $cp_options['version'], '1.5', '<' ) ) {
166 if (! isset( $cp_options['accuracy'] ) ) {
167 $cp_options['accuracy'] = 1;
168 }
169 }
170
171 // Version 1.7.5
172 if ( version_compare( $cp_options['version'], '1.7.5', '<' ) ) {
173 if (! isset( $cp_options['php_error'] ) ) {
174 $cp_options['php_error'] = 1;
175 }
176 }
177
178 // Version 1.8
179 if ( version_compare( $cp_options['version'], '1.8', '<' ) ) {
180 if ( isset( $cp_options['mem_where'] ) ) {
181 $cp_options['mem']['x_end'] = $cp_options['mem_where'];
182 unset( $cp_options['mem_where'] );
183 }
184 if ( isset( $cp_options['mem_post'] ) ) {
185 $cp_options['mem']['post'] = $cp_options['mem_post'];
186 unset( $cp_options['mem_post'] );
187 }
188 if ( isset( $cp_options['mem_user'] ) ) {
189 $cp_options['mem']['x_auth'] = $cp_options['mem_user'];
190 unset( $cp_options['mem_user'] );
191 }
192 if ( isset( $cp_options['mem_username'] ) ) {
193 $cp_options['mem']['username'] = $cp_options['mem_username'];
194 unset( $cp_options['mem_username'] );
195 }
196 if ( isset( $cp_options['mem_method'] ) ) {
197 $cp_options['mem']['method'] = $cp_options['mem_method'];
198 unset( $cp_options['mem_method'] );
199 }
200 if ( isset( $cp_options['mem_theme'] ) ) {
201 $cp_options['mem']['theme'] = $cp_options['mem_theme'];
202 unset( $cp_options['mem_theme'] );
203 }
204 if ( isset( $cp_options['ua'] ) ) {
205 $cp_options['mem']['user_agent'] = $cp_options['ua'];
206 unset( $cp_options['ua'] );
207 }
208 if ( isset( $cp_options['cookies'] ) ) {
209 $cp_options['mem']['cookies'] = $cp_options['cookies'];
210 unset( $cp_options['cookies'] );
211 }
212 if ( isset( $cp_options['mem_content_type'] ) ) {
213 $cp_options['mem']['content_type'] = $cp_options['mem_content_type'];
214 unset( $cp_options['mem_content_type'] );
215 }
216 if ( isset( $cp_options['payload'] ) ) {
217 $cp_options['mem']['payload'] = $cp_options['payload'];
218 unset( $cp_options['payload'] );
219 }
220 if ( isset( $cp_options['custom_headers'] ) ) {
221 $cp_options['mem']['custom_headers'] = $cp_options['custom_headers'];
222 unset( $cp_options['custom_headers'] );
223 }
224 if ( isset( $cp_options['exclusions'] ) ) {
225 $cp_options['mem']['exclusions'] = $cp_options['exclusions'];
226 unset( $cp_options['exclusions'] );
227 }
228 }
229
230 // Version 1.8.1
231 if ( version_compare( $cp_options['version'], '1.8.1', '<' ) ) {
232 CodeProfiler_WPCron::install();
233 }
234
235 // Adjust current version
236 $cp_options['version'] = CODE_PROFILER_VERSION;
237
238 // Update version in the DB
239 update_option('code-profiler', $cp_options );
240 }
241
242 }
243 add_action('admin_init', 'code_profiler_init_update');
244
245 // =====================================================================
246 // Verify or create our storage folder in the uploads directory.
247 // Call during activation and access to the plugin.
248
249 function code_profiler_check_uploadsdir() {
250
251 if (! file_exists( CODE_PROFILER_UPLOAD_DIR ) ) {
252 mkdir( CODE_PROFILER_UPLOAD_DIR, 0755 );
253 }
254 if (! is_writable( CODE_PROFILER_UPLOAD_DIR ) ) {
255 // PHP running as an Apache module?
256 chmod( CODE_PROFILER_UPLOAD_DIR, 0777 );
257 }
258 if (! file_exists( CODE_PROFILER_UPLOAD_DIR .'/index.html') ) {
259 touch( CODE_PROFILER_UPLOAD_DIR .'/index.html');
260 }
261 // For Apache & Litespeed
262 if (! file_exists( CODE_PROFILER_UPLOAD_DIR .'/.htaccess') ) {
263 file_put_contents(
264 CODE_PROFILER_UPLOAD_DIR .'/.htaccess',
265 'Require all denied'
266 );
267 }
268 // Make sure there's a MU plugin directory
269 if (! is_dir( WPMU_PLUGIN_DIR ) ) {
270 wp_mkdir_p( WPMU_PLUGIN_DIR );
271 }
272
273
274 if (! file_exists( WPMU_PLUGIN_DIR .'/'. CODE_PROFILER_MUPLUGIN ) ) {
275
276 if (! is_writable( WPMU_PLUGIN_DIR ) ) {
277 wp_die(
278 sprintf(
279 __('Error: The MU folder is read only, please make it writable: %s', 'code-profiler'),
280 esc_html( WPMU_PLUGIN_DIR ) .'/'
281 )
282 );
283 }
284
285 if (! file_exists( __DIR__ .'/mu.plugin') ) {
286 code_profiler_log_error( sprintf(
287 esc_html__('Cannot find the MU plugin: %s', 'code-profiler'),
288 __DIR__ .'/mu.plugin'
289 ));
290 } else {
291 $res = copy( __DIR__ .'/mu.plugin', WPMU_PLUGIN_DIR .'/'. CODE_PROFILER_MUPLUGIN );
292 if ( $res === false ) {
293 code_profiler_log_error( sprintf(
294 esc_html__('Cannot copy the MU plugin to %s', 'code-profiler'),
295 WPMU_PLUGIN_DIR
296 ));
297 }
298 }
299 } else {
300 // Update MU plugin it if needed
301 if ( md5_file( WPMU_PLUGIN_DIR .'/'. CODE_PROFILER_MUPLUGIN ) !== md5_file( __DIR__ .'/mu.plugin') ) {
302 copy( __DIR__ .'/mu.plugin', WPMU_PLUGIN_DIR .'/'. CODE_PROFILER_MUPLUGIN );
303 }
304 }
305
306 // Log file
307 if (! file_exists( CODE_PROFILER_LOG ) ) {
308 file_put_contents( CODE_PROFILER_LOG, "<?php exit; ?>\n" );
309 }
310
311 }
312
313 // =====================================================================
314 // Check the PHP memory limit and return a suggested size
315 // for the profiler's buffer.
316
317 function code_profiler_suggested_memory() {
318
319 $memory_limit = ini_get('memory_limit');
320
321 if ('-1' == $memory_limit ) {
322 // Return max size
323 return 10;
324 }
325
326 if ( preg_match('/^(\d+)([PTGMK])$/i', $memory_limit, $match ) ) {
327 $bytes = (int) $match[1];
328 switch ( strtoupper( $match[2] ) ) {
329 case 'P':
330 $bytes *= 1024;
331 case 'T':
332 $bytes *= 1024;
333 case 'G':
334 $bytes *= 1024;
335 case 'M':
336 $bytes *= 1024;
337 case 'K':
338 $bytes *= 1024;
339 }
340 // 256 MB
341 if ( $bytes >= 268435456 ) {
342 return 10;
343 // 128 MB
344 } elseif ( $bytes >= 134217728 ) {
345 return 7;
346 // 64 MB
347 } elseif ( $bytes >= 67108864 ) {
348 return 4;
349 // <64 MB
350 } else {
351 return 1;
352 }
353 }
354 // Don't know :/
355 return 5;
356 }
357
358 // =====================================================================
359 // Create the default options.
360
361 function code_profiler_default_options() {
362
363 $buffer = code_profiler_suggested_memory();
364
365 $cp_options = [
366 'show_paths' => 'relative',
367 'display_name' => 'full',
368 'truncate_name' => 30,
369 'chart_type' => 'x',
370 'chart_max_plugins' => 25,
371 'hide_empty_value' => 1,
372 'table_max_rows' => 30,
373 'warn_composer' => 1,
374 'enable_wpcli' => 1,
375 'disable_wpcron' => 1,
376 'http_response' => '^(?:3|4|5)\d{2}$',
377 'accuracy' => 1,
378 'buffer' => (int) $buffer
379 ];
380
381 update_option('code-profiler', $cp_options );
382
383 }
384
385 // ===================================================================== 2023-06-14
386 // Create a profile name.
387
388 function code_profiler_profile_name() {
389
390 return date('Y-m-d_') . substr( time(), 4 );
391 }
392
393 // ===================================================================== 2023-06-14
394 // Disable PHP display_errors so that notice, warning and error messages
395 // don't show up in the AJAX response.
396
397 function code_profiler_hide_errors() {
398
399 ini_set('display_errors', 0 );
400 }
401
402 // =====================================================================
403 // Disable opcode cache.
404
405 function code_profiler_disable_opcode() {
406
407 try {
408 if ( extension_loaded('Zend OPcache') ) {
409 ini_set('opcache.enable', 0);
410 } elseif ( extension_loaded('wincache') ) {
411 ini_set('wincache.fcenabled', 0);
412 }
413 set_time_limit(0);
414 ini_set('memory_limit', -1);
415
416 } catch ( Exception $e ) { }
417
418 $cp_options = get_option('code-profiler');
419 /**
420 * Disable WP-CRON.
421 */
422 if (! empty( $cp_options['disable_wpcron'] ) ) {
423 if (! defined('DISABLE_WP_CRON') ) {
424 define('DISABLE_WP_CRON', true );
425 }
426 }
427 /**
428 * Enable PHP error logging.
429 */
430 if (! empty( $cp_options['php_error'] ) ) {
431 ini_set('log_errors', 1 );
432 $phplog = ini_get('error_log');
433 if ( empty( $phplog ) || $phplog === false ) {
434 ini_set('error_log', WP_CONTENT_DIR .'/debug.log');
435 } else {
436 ini_set('error_log', $phplog );
437 }
438 }
439 }
440
441 // =====================================================================
442 // Verify the security key when running the profiler.
443
444 function code_profiler_verify_key() {
445
446 $response = [
447 'status' => 'error',
448 // We cannot load translation here.
449 'message' => 'Security keys do not match. Reload the page and try again (%s)'
450 ];
451
452 if ( empty( $_REQUEST['profiler_key'] ) ) {
453 $response['message'] = sprintf( $response['message'], '001');
454
455 } else {
456 $file = CODE_PROFILER_UPLOAD_DIR .'/key_'. sha1( $_REQUEST['profiler_key'] ) .'.tmp';
457 if ( file_exists( $file ) ) {
458 // Delete it and accept the request
459 unlink( $file );
460 return;
461 }
462 $response['message'] = sprintf( $response['message'], '002');
463 }
464 wp_send_json( $response );
465
466 }
467
468 // =====================================================================
469 // Write message to the log.
470 // Log level can be a combination of INFO (1), WARN (2), ERROR (4)
471 // and DEBUG (8).
472
473 function code_profiler_write2log( $message, $level, $create ) {
474
475 if ( empty( $create ) ) {
476 file_put_contents(
477 CODE_PROFILER_LOG,
478 time() ."~~$level~~$message\n",
479 FILE_APPEND
480 );
481 } else {
482 file_put_contents(
483 CODE_PROFILER_LOG,
484 time() ."~~$level~~$message\n"
485 );
486 }
487 }
488
489 function code_profiler_log_info( $string, $create = 0 ) {
490 code_profiler_write2log( $string, 1, $create );
491 }
492 function code_profiler_log_warn( $string, $create = 0 ) {
493 code_profiler_write2log( $string, 2, $create );
494 }
495 function code_profiler_log_error( $string, $create = 0 ) {
496 code_profiler_write2log( $string, 4, $create );
497 }
498 function code_profiler_log_debug( $string, $create = 0 ) {
499 code_profiler_write2log( $string, 8, $create );
500 }
501
502 // =====================================================================
503 // Retrieve and return matching files from a directory.
504
505 function code_profiler_glob( $directory, $regex, $pathname = false ) {
506
507 $list = [];
508
509 foreach ( new DirectoryIterator( $directory ) as $finfo ) {
510 if (! $finfo->isDot() && preg_match("`$regex`", $finfo->getFilename() ) ) {
511 if ( $pathname ) {
512 $list[] = $finfo->getPathname();
513 } else {
514 $list[] = $finfo->getFilename();
515 }
516 }
517 }
518 return $list;
519 }
520
521 // =====================================================================
522 // Verify if a profile exists and return its full path.
523
524 function code_profiler_get_profile_path( $id, $type = 'slugs') {
525
526 if (! empty( $id ) && preg_match('/^\d{10}\.\d+$/', $id ) ) {
527
528 $glob = code_profiler_glob(CODE_PROFILER_UPLOAD_DIR, "$id\..+\.$type\.profile$", true);
529
530 if ( is_array( $glob ) && ! empty( $glob[0] ) ) {
531 if ( preg_match( "`$id\.(.+?).$type.profile$`", $glob[0], $match ) ) {
532
533 return CODE_PROFILER_UPLOAD_DIR. "/$id.{$match[1]}";
534 }
535 }
536 }
537 return false;
538 }
539
540 // =====================================================================
541 // Open, parse and return the content of a profile file.
542
543 function code_profiler_get_profile_data( $file, $type = 'slugs') {
544
545 $buffer = [];
546
547 $fh = fopen( "$file.$type.profile", 'rb');
548
549 if ( $fh === false ) {
550 $err = sprintf(
551 CODE_PROFILER_ERROR_NOTICE,
552 sprintf(
553 esc_html__('Unable to open profile file: %s.', 'code-profiler'),
554 esc_html( "$file.$type.profile" )
555 )
556 );
557 $buffer['error'] = $err;
558 return $buffer;
559 }
560
561 /**
562 * We don't use fgetcsv() as it requires the $escape parameter since PHP 8.4
563 */
564 while (! feof( $fh ) ) {
565 $tmp = trim( fgets( $fh, 1000 ) );
566 if (! $tmp ) {
567 continue;
568 }
569 $buffer[] = explode( "\t", $tmp );
570 }
571
572 fclose( $fh );
573
574 if ( empty( $buffer ) ) {
575 $err = sprintf(
576 CODE_PROFILER_ERROR_NOTICE,
577 sprintf(
578 esc_html__('Profile file is empty or corrupted: %s.', 'code-profiler'),
579 esc_html( "$file.$type.profile" )
580 )
581 );
582 $buffer['error'] = $err;
583 return $buffer;
584 }
585
586 // Get rid of the empty field created by fgetcsv
587 return array_filter( $buffer );
588 }
589
590 // =====================================================================
591 // Exit with a json-encoded error message except if we're running
592 // from WP CLI
593
594 function code_profiler_wp_send_json( $response ) {
595
596 if ( defined('WP_CLI') && WP_CLI ) {
597 WP_CLI::error( $response['message'] );
598 }
599 wp_send_json( $response );
600 }
601
602 // =====================================================================
603 // Retrieve the summary stats for a given profile.
604
605 function code_profiler_getsummarystats( $profile_path, $type = 'html') {
606
607 if ( $type == 'html') {
608 $open = '<ul><li>&#10148; ';
609 $div = '</li><li>&#10148; ';
610 $close = '</li></ul>';
611 } else {
612 // WP-CLI
613 $open = " \u{27A4} ";
614 $div = "\n \u{27A4} ";
615 $close = "\n\n";
616 }
617
618 if (! file_exists( "$profile_path.summary.profile" ) ) {
619 return false;
620 }
621 $decode = json_decode( file_get_contents( "$profile_path.summary.profile" ) );
622
623 $string = $open;
624
625 if ( empty( $decode->items ) ) {
626 $tmp = __('N/A', 'code-profiler');
627 } else {
628 $tmp = (int) --$decode->items;
629 }
630 $string .= sprintf(
631 __('%s plugins and 1 theme', 'code-profiler'),
632 $tmp
633 );
634
635 $string .= $div;
636
637 if ( empty( $decode->time ) ) {
638 $tmp = __('N/A', 'code-profiler');
639 } else {
640 $tmp = number_format( $decode->time, 4 );
641 }
642 $string .= sprintf(
643 __('Execution time: %ss', 'code-profiler'),
644 $tmp
645 );
646
647 $string .= $div;
648
649 if ( empty( $decode->memory ) ) {
650 $tmp = __('N/A', 'code-profiler');
651 } else {
652 $tmp = number_format( $decode->memory, 2);
653 }
654 $string .= sprintf(
655 __('Peak memory: %s MB', 'code-profiler'),
656 $tmp
657 );
658
659 $string .= $div;
660
661 if ( empty( $decode->io ) ) {
662 $tmp = __('N/A', 'code-profiler');
663 } else {
664 $tmp = number_format( (int) $decode->io );
665 }
666 $string .= sprintf(
667 __('File I/O operations: %s', 'code-profiler'),
668 $tmp
669 );
670
671 $string .= $div;
672
673 if ( empty( $decode->queries ) ) {
674 $tmp = __('N/A', 'code-profiler');
675 } else {
676 $tmp = number_format( (int) $decode->queries );
677 }
678 $string .= sprintf(
679 __('SQL queries: %s', 'code-profiler'),
680 $tmp
681 );
682
683 $string .= $div;
684
685 if ( empty( CODE_PROFILER_ACCURACY[ $decode->precision ] ) ) {
686 $tmp = __('N/A', 'code-profiler');
687 } else {
688 $tmp = CODE_PROFILER_ACCURACY[ $decode->precision ];
689 }
690 $string .= sprintf(
691 __('Accuracy: %s', 'code-profiler'),
692 $tmp
693 );
694
695 $string .= $close;
696
697 return $string;
698 }
699
700 // =====================================================================
701 // Remove *tmp files left in the profiles folder.
702
703 function code_profiler_cleantmpfiles() {
704
705 $glob = code_profiler_glob( CODE_PROFILER_UPLOAD_DIR, '\.tmp$', true );
706
707 if ( is_array( $glob ) ) {
708 foreach( $glob as $file ) {
709 unlink( $file );
710 }
711 }
712 }
713
714 // =====================================================================
715 // Remove non-ASCII characters from a string.
716
717 function code_profiler_ASCII_filter( $string ) {
718
719 return preg_replace('/[\x00-\x1f\x7f-\xff]/', '', $string );
720 }
721
722 // =====================================================================
723 // Clear the log if it's bigger than 100KB.
724
725 function code_profiler_clearlog() {
726
727 if ( file_exists( CODE_PROFILER_LOG ) && filesize( CODE_PROFILER_LOG ) > 100000 ) {
728 file_put_contents( CODE_PROFILER_LOG, "<?php exit; ?>\n" );
729 }
730 }
731
732 // ===================================================================== 2023-06-15
733 // We don't want to be bothered by other themes/plugins' admin notices.
734
735 add_action('admin_head', 'code_profiler_hide_admin_notices');
736
737 function code_profiler_hide_admin_notices() {
738 if ( isset( $_GET['page'] ) && $_GET['page'] == 'code-profiler') {
739 remove_all_actions('admin_notices');
740 remove_all_actions('all_admin_notices');
741 add_filter('admin_footer_text', 'code_profiler_admin_footer');
742 }
743 }
744
745 function code_profiler_admin_footer () {
746 echo '<span id="footer-thankyou">'.
747 sprintf(
748 /* Translators: %s are the '<a href="">' and '</a>' anchors */
749 esc_html(
750 'Thank you for using %sCode Profiler%s.',
751 'code-profiler'
752 ),
753 '<a href="https://nintechnet.com/codeprofiler/" target="_blank">',
754 '</a>'
755 ).
756 '</span>';
757 }
758
759
760 // =====================================================================
761 // Hide/display an element depending on some value.
762
763 function code_profiler_showhide( $var, $val ) {
764
765 if ( $var == $val ) {
766 echo " style='display:block'";
767 } else {
768 echo " style='display:none'";
769 }
770 }
771
772 // =====================================================================
773 // Retrieve all themes.
774
775 function code_profiler_get_themes() {
776
777 $list = [];
778
779 // Make sure the function is loaded
780 if (! function_exists('wp_get_themes') ) {
781 require_once ABSPATH . 'wp-includes/theme.php';
782 }
783 $themes = wp_get_themes();
784 foreach( $themes as $k => $v ) {
785 if ( $v->Name ) {
786 $list[ $k ] = [
787 'n' => $v->Name,
788
789 't' => $v->Template
790 ];
791 } else {
792 $list[ $k ] = [
793 'n' => $k,
794 't' => $v->Template
795 ];
796 }
797 }
798 return $list;
799 }
800
801 // =====================================================================
802 // EOF
803