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.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 +131 -69 1.6.81.7.4 View file →
@@ -6,9 +6,9 @@
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 14 if (! defined('ABSPATH') ) {
@@ -19,9 +19,16 @@
19 19 // Various constants
20 20
21 21 // The profiles directory can be defined in the wp-config.php script
22 22 if (! defined('CODE_PROFILER_UPLOAD_DIR') ) {
23 - $upload_dir = wp_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 + }
24 31 define('CODE_PROFILER_UPLOAD_DIR', $upload_dir['basedir'] .'/code-profiler');
25 32 }
26 33 define('CODE_PROFILER_LOG', CODE_PROFILER_UPLOAD_DIR .'/log.php');
27 34 define('CODE_PROFILER_TMP_IOSTATS_LOG', 'iostats.tmp');
@@ -30,47 +37,79 @@
30 37 define('CODE_PROFILER_TMP_DISKIO_LOG', 'diskio.tmp');
31 38 define('CODE_PROFILER_TMP_CONNECTIONS_LOG', 'connections.tmp');
32 39 define('CODE_PROFILER_UPDATE_NOTICE', '<div class="updated notice is-dismissible"><p>%s</p></div>');
33 40 define('CODE_PROFILER_ERROR_NOTICE', '<div class="error notice is-dismissible"><p>%s</p></div>');
34 -global $wp_version;
35 -if (! defined('CODE_PROFILER_UA') ) { // UA signatures can be user-defined in the wp-config.php
36 - define ('CODE_PROFILER_UA', [
37 - esc_html__('Desktop', 'code-profiler') => [
38 - 'Firefox' => 'Mozilla/5.0 (Linux x86_64; rv:110.0) Gecko/20100101 Firefox/110.0',
39 - 'Chrome' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)'.
40 - ' Chrome/111.0.0.0 Safari/537.36',
41 - 'Edge' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,'.
42 - ' like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/110.0.1587.63'
43 - ],
44 - esc_html__('Mobile', 'code-profiler') => [
45 - 'Android Phone' => 'Mozilla/5.0 (Android 13; Mobile; rv:68.0) Gecko/68.0 Firefox/110.0',
46 - 'Android Tablet' => 'Mozilla/5.0 (Linux; Android 13.0; SAMSUNG-SM-T377A Build/NMF26X)'.
47 - ' AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Mobile Safari/537.36',
48 - 'iPhone' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_3_1 like Mac OS X) AppleWebKit/605.1.15'.
49 - ' (KHTML, like Gecko) Version/16.3 Mobile/15E148 Safari/604.1',
50 - 'iPad' => 'Mozilla/5.0 (iPad; CPU OS 16_3_1 like Mac OS X) AppleWebKit/605.1.15'.
51 - ' (KHTML, like Gecko) GSA/213.0.449417121 Mobile/15E148 Safari/605.1.15'
52 - ],
53 - esc_html__('Bot', 'code-profiler') => [
54 - 'Google Bot' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
55 - 'WordPress' => 'Mozilla/5.0 (compatible; CodeProfiler for WordPress/'. $wp_version .
56 - '; https://code-profiler.com/)'
57 - ]
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 +}
58 45
59 - ] );
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 + ]);
60 86 }
61 87
62 -if (! defined('CODE_PROFILER_MUPLUGIN') ) {
63 - // MU plugin's name can be defined in the wp-config.php
64 - 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];
65 110 }
66 -define('CODE_PROFILER_ACCURACY', [
67 - 1 => __('Highest', 'code-profiler'),
68 - 5 => __('High', 'code-profiler'),
69 - 10 => __('Moderate', 'code-profiler'),
70 - 15 => __('Low', 'code-profiler'),
71 - 20 => __('Lowest', 'code-profiler')
72 -]);
111 +
73 112 // =====================================================================
74 113 // Prevent cURL timeout if a plugin changes its timeout options.
75 114
76 115 function code_profiler_curl_timeout( $handle, $parsed_args, $url ) {
@@ -300,36 +339,32 @@
300 339 if (! defined('DISABLE_WP_CRON') ) {
301 340 define('DISABLE_WP_CRON', true );
302 341 }
303 342 }
343 +}
304 344
305 -}
306 345 // =====================================================================
307 -// Verify the security key when running the profile.
346 +// Verify the security key when running the profiler.
308 347
309 348 function code_profiler_verify_key() {
310 349
311 350 $response = [
312 351 'status' => 'error',
313 - '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')
314 354 ];
315 355
316 - $cp_options = get_option('code-profiler');
356 + if ( empty( $_REQUEST['profiler_key'] ) ) {
357 + $response['message'] = sprintf( $response['message'], '001');
317 358
318 - if ( empty( $cp_options['hash'] ) ) {
319 - $response['message'] = sprintf( $response['message'], '#1');
320 -
321 359 } else {
322 - if ( empty( $_REQUEST['profiler_key'] ) ) {
323 - $response['message'] = sprintf( $response['message'], '#2');
324 -
325 - } else {
326 - if ( $cp_options['hash'] == sha1( $_REQUEST['profiler_key'] ) ) {
327 - return;
328 - } else {
329 - $response['message'] = sprintf( $response['message'], '#3');
330 - }
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;
331 365 }
366 + $response['message'] = sprintf( $response['message'], '002');
332 367 }
333 368 wp_send_json( $response );
334 369
335 370 }
@@ -368,18 +403,37 @@
368 403 code_profiler_write2log( $string, 8, $create );
369 404 }
370 405
371 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 +// =====================================================================
372 426 // Verify if a profile exists and return its full path.
373 427
374 428 function code_profiler_get_profile_path( $id, $type = 'slugs') {
375 429
376 - $return = false;
430 + if (! empty( $id ) && preg_match('/^\d{10}\.\d+$/', $id ) ) {
377 431
378 - if (! empty( $id ) && preg_match('/^\d{10}\.\d+$/', $id ) ) {
379 - $glob = glob( CODE_PROFILER_UPLOAD_DIR ."/$id.*.$type.profile" );
432 + $glob = code_profiler_glob(CODE_PROFILER_UPLOAD_DIR, "$id\..+\.$type\.profile$", true);
433 +
380 434 if ( is_array( $glob ) && ! empty( $glob[0] ) ) {
381 - if ( preg_match( "`/$id\.(.+?).$type.profile$`", $glob[0], $match ) ) {
435 + if ( preg_match( "`$id\.(.+?).$type.profile$`", $glob[0], $match ) ) {
382 436
383 437 return CODE_PROFILER_UPLOAD_DIR. "/$id.{$match[1]}";
384 438 }
385 439 }
@@ -407,10 +461,17 @@
407 461 $buffer['error'] = $err;
408 462 return $buffer;
409 463 }
410 464
465 + /**
466 + * We don't use fgetcsv() as it requires the $escape parameter since PHP 8.4
467 + */
411 468 while (! feof( $fh ) ) {
412 - $buffer[] = fgetcsv( $fh, 1000, "\t" );
469 + $tmp = trim( fgets( $fh, 1000 ) );
470 + if (! $tmp ) {
471 + continue;
472 + }
473 + $buffer[] = explode( "\t", $tmp );
413 474 }
414 475
415 476 fclose( $fh );
416 477
@@ -540,29 +601,30 @@
540 601 return $string;
541 602 }
542 603
543 604 // =====================================================================
544 -// Remove *tmp files left after an HTTP error (4xx or 5xx).
605 +// Remove *tmp files left in the profiles folder.
545 606
546 607 function code_profiler_cleantmpfiles() {
547 608
548 - $glob = glob( CODE_PROFILER_UPLOAD_DIR .'/*.tmp');
609 + $glob = code_profiler_glob( CODE_PROFILER_UPLOAD_DIR, '\.tmp$', true );
610 +
549 611 if ( is_array( $glob ) ) {
550 - $count = 0;
551 612 foreach( $glob as $file ) {
552 - $count++;
553 613 unlink( $file );
554 614 }
555 - if ( $count ) {
556 - code_profiler_log_info( sprintf(
557 - __('Deleting %s temporary files found in the profiles folder', 'code-profiler'),
558 - (int) $count
559 - ) );
560 - }
561 615 }
562 616 }
563 617
564 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 +// =====================================================================
565 627 // Clear the log if it's bigger than 100KB.
566 628
567 629 function code_profiler_clearlog() {
568 630
@@ -591,9 +653,9 @@
591 653 esc_html(
592 654 'Thank you for using %sCode Profiler%s.',
593 655 'code-profiler'
594 656 ),
595 - '<a href="https://code-profiler.com" target="_blank">',
657 + '<a href="https://nintechnet.com/codeprofiler/" target="_blank">',
596 658 '</a>'
597 659 ).
598 660 '</span>';
599 661 }