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 +200 -81 1.6.41.7.4 View file →
@@ -1,6 +1,6 @@
1 1 <?php
2 -/*
2 +/**
3 3 +=====================================================================+
4 4 | ____ _ ____ __ _ _ |
5 5 | / ___|___ __| | ___ | _ \ _ __ ___ / _(_) | ___ _ __ |
6 6 | | | / _ \ / _` |/ _ \ | |_) | '__/ _ \| |_| | |/ _ \ '__| |
@@ -6,66 +6,110 @@
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');
26 38 define('CODE_PROFILER_TMP_CONNECTIONS_LOG', 'connections.tmp');
27 39 define('CODE_PROFILER_UPDATE_NOTICE', '<div class="updated notice is-dismissible"><p>%s</p></div>');
28 40 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 - ]
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 +}
53 45
54 - ] );
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 + ]);
55 86 }
56 87
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');
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];
60 110 }
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 -]);
111 +
68 112 // =====================================================================
69 113 // Prevent cURL timeout if a plugin changes its timeout options.
70 114
71 115 function code_profiler_curl_timeout( $handle, $parsed_args, $url ) {
@@ -279,14 +323,15 @@
279 323
280 324 function code_profiler_disable_opcode() {
281 325
282 326 try {
283 - if (extension_loaded('Zend OPcache')) {
327 + if ( extension_loaded('Zend OPcache') ) {
284 328 ini_set('opcache.enable', 0);
285 329 } elseif ( extension_loaded('wincache') ) {
286 330 ini_set('wincache.fcenabled', 0);
287 331 }
288 332 set_time_limit(0);
333 + ini_set('memory_limit', -1);
289 334
290 335 } catch ( Exception $e ) { }
291 336
292 337 $cp_options = get_option('code-profiler');
@@ -294,36 +339,32 @@
294 339 if (! defined('DISABLE_WP_CRON') ) {
295 340 define('DISABLE_WP_CRON', true );
296 341 }
297 342 }
343 +}
298 344
299 -}
300 345 // =====================================================================
301 -// Verify the security key when running the profile.
346 +// Verify the security key when running the profiler.
302 347
303 348 function code_profiler_verify_key() {
304 349
305 350 $response = [
306 351 'status' => 'error',
307 - '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')
308 354 ];
309 355
310 - $cp_options = get_option('code-profiler');
356 + if ( empty( $_REQUEST['profiler_key'] ) ) {
357 + $response['message'] = sprintf( $response['message'], '001');
311 358
312 - if ( empty( $cp_options['hash'] ) ) {
313 - $response['message'] = sprintf( $response['message'], '#1');
314 -
315 359 } else {
316 - if ( empty( $_REQUEST['profiler_key'] ) ) {
317 - $response['message'] = sprintf( $response['message'], '#2');
318 -
319 - } else {
320 - if ( $cp_options['hash'] == sha1( $_REQUEST['profiler_key'] ) ) {
321 - return;
322 - } else {
323 - $response['message'] = sprintf( $response['message'], '#3');
324 - }
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;
325 365 }
366 + $response['message'] = sprintf( $response['message'], '002');
326 367 }
327 368 wp_send_json( $response );
328 369
329 370 }
@@ -362,18 +403,37 @@
362 403 code_profiler_write2log( $string, 8, $create );
363 404 }
364 405
365 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 +// =====================================================================
366 426 // Verify if a profile exists and return its full path.
367 427
368 428 function code_profiler_get_profile_path( $id, $type = 'slugs') {
369 429
370 - $return = false;
430 + if (! empty( $id ) && preg_match('/^\d{10}\.\d+$/', $id ) ) {
371 431
372 - if (! empty( $id ) && preg_match('/^\d{10}\.\d+$/', $id ) ) {
373 - $glob = glob( CODE_PROFILER_UPLOAD_DIR ."/$id.*.$type.profile" );
432 + $glob = code_profiler_glob(CODE_PROFILER_UPLOAD_DIR, "$id\..+\.$type\.profile$", true);
433 +
374 434 if ( is_array( $glob ) && ! empty( $glob[0] ) ) {
375 - if ( preg_match( "`/$id\.(.+?).$type.profile$`", $glob[0], $match ) ) {
435 + if ( preg_match( "`$id\.(.+?).$type.profile$`", $glob[0], $match ) ) {
376 436
377 437 return CODE_PROFILER_UPLOAD_DIR. "/$id.{$match[1]}";
378 438 }
379 439 }
@@ -401,10 +461,17 @@
401 461 $buffer['error'] = $err;
402 462 return $buffer;
403 463 }
404 464
465 + /**
466 + * We don't use fgetcsv() as it requires the $escape parameter since PHP 8.4
467 + */
405 468 while (! feof( $fh ) ) {
406 - $buffer[] = fgetcsv( $fh, 1000, "\t" );
469 + $tmp = trim( fgets( $fh, 1000 ) );
470 + if (! $tmp ) {
471 + continue;
472 + }
473 + $buffer[] = explode( "\t", $tmp );
407 474 }
408 475
409 476 fclose( $fh );
410 477
@@ -459,9 +526,9 @@
459 526
460 527 $string = $open;
461 528
462 529 if ( empty( $decode->items ) ) {
463 - $tmp = 'N/A';
530 + $tmp = __('N/A', 'code-profiler');
464 531 } else {
465 532 $tmp = (int) --$decode->items;
466 533 }
467 534 $string .= sprintf(
@@ -471,9 +538,9 @@
471 538
472 539 $string .= $div;
473 540
474 541 if ( empty( $decode->time ) ) {
475 - $tmp = 'N/A';
542 + $tmp = __('N/A', 'code-profiler');
476 543 } else {
477 544 $tmp = number_format( $decode->time, 4 );
478 545 }
479 546 $string .= sprintf(
@@ -483,9 +550,9 @@
483 550
484 551 $string .= $div;
485 552
486 553 if ( empty( $decode->memory ) ) {
487 - $tmp = 'N/A';
554 + $tmp = __('N/A', 'code-profiler');
488 555 } else {
489 556 $tmp = number_format( $decode->memory, 2);
490 557 }
491 558 $string .= sprintf(
@@ -495,11 +562,11 @@
495 562
496 563 $string .= $div;
497 564
498 565 if ( empty( $decode->io ) ) {
499 - $tmp = 'N/A';
566 + $tmp = __('N/A', 'code-profiler');
500 567 } else {
501 - $tmp = number_format( $decode->io );
568 + $tmp = number_format( (int) $decode->io );
502 569 }
503 570 $string .= sprintf(
504 571 __('File I/O operations: %s', 'code-profiler'),
505 572 $tmp
@@ -507,11 +574,11 @@
507 574
508 575 $string .= $div;
509 576
510 577 if ( empty( $decode->queries ) ) {
511 - $tmp = 'N/A';
578 + $tmp = __('N/A', 'code-profiler');
512 579 } else {
513 - $tmp = number_format( $decode->queries );
580 + $tmp = number_format( (int) $decode->queries );
514 581 }
515 582 $string .= sprintf(
516 583 __('SQL queries: %s', 'code-profiler'),
517 584 $tmp
@@ -516,8 +583,20 @@
516 583 __('SQL queries: %s', 'code-profiler'),
517 584 $tmp
518 585 );
519 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 +
520 599 $string .= $close;
521 600
522 601 return $string;
523 602 }
@@ -522,29 +601,30 @@
522 601 return $string;
523 602 }
524 603
525 604 // =====================================================================
526 -// Remove *tmp files left after an HTTP error (4xx or 5xx).
605 +// Remove *tmp files left in the profiles folder.
527 606
528 607 function code_profiler_cleantmpfiles() {
529 608
530 - $glob = glob( CODE_PROFILER_UPLOAD_DIR .'/*.tmp');
609 + $glob = code_profiler_glob( CODE_PROFILER_UPLOAD_DIR, '\.tmp$', true );
610 +
531 611 if ( is_array( $glob ) ) {
532 - $count = 0;
533 612 foreach( $glob as $file ) {
534 - $count++;
535 613 unlink( $file );
536 614 }
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 615 }
544 616 }
545 617
546 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 +// =====================================================================
547 627 // Clear the log if it's bigger than 100KB.
548 628
549 629 function code_profiler_clearlog() {
550 630
@@ -573,12 +653,51 @@
573 653 esc_html(
574 654 'Thank you for using %sCode Profiler%s.',
575 655 'code-profiler'
576 656 ),
577 - '<a href="https://code-profiler.com" target="_blank">',
657 + '<a href="https://nintechnet.com/codeprofiler/" target="_blank">',
578 658 '</a>'
579 659 ).
580 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;
581 700 }
582 701
583 702 // =====================================================================
584 703 // EOF