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/ajax.php +143 -39 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') ) {
@@ -72,15 +72,8 @@
72 72 code_profiler_wp_send_json( $response );
73 73 }
74 74
75 75 code_profiler_log_debug(
76 - esc_html__('Cleaning up the temporary folder', 'code-profiler')
77 - );
78 -
79 - // Clean-up temp files left in the profiles folder
80 - code_profiler_cleantmpfiles();
81 -
82 - code_profiler_log_debug(
83 76 esc_html__('Retrieving parameters #1', 'code-profiler')
84 77 );
85 78
86 79 // Frontend or backend
@@ -191,15 +184,18 @@
191 184 );
192 185
193 186 // Create security key
194 187 $profiler_key = bin2hex( random_bytes( 16 ) );
195 - $cp_options['hash'] = sha1( $profiler_key );
188 + touch( CODE_PROFILER_UPLOAD_DIR .'/key_'. sha1( $profiler_key ) .'.tmp');
196 189
197 190 code_profiler_log_debug(
198 191 esc_html__('Building HTTP query', 'code-profiler')
199 192 );
200 193
201 - // Build query
194 + /**
195 + * Build the query.
196 + */
197 + $raw_url = $url;
202 198 $url = add_query_arg( [
203 199 'CODE_PROFILER_ON' => $microtime,
204 200 'profiler_key' => $profiler_key
205 201 ], $url );
@@ -231,14 +227,17 @@
231 227 esc_html__('Building custom HTTP headers', 'code-profiler')
232 228 );
233 229 $is_custom_headers = '';
234 230 foreach( $custom_headers as $custom_header ) {
235 - list( $key, $value ) = explode( ':', "$custom_header:" );
231 + if ( strpos( $custom_header, ':') === false ) {
232 + continue;
233 + }
234 + list( $key, $value ) = explode(':', $custom_header, 2 );
236 235 // Lowercase header name
237 236 $key = trim( strtolower( $key ) );
238 237 $value = trim( $value );
239 238 // We want printable ASCII characters only
240 - $value = preg_replace('/[\x00-\x1f\x7f-\xff]/', '', $value);
239 + $value = code_profiler_ASCII_filter( $value );
241 240 if (! empty( $key ) && ! empty( $value ) ) {
242 241 $headers['headers'][ $key ] = $value;
243 242 $is_custom_headers .= "$key: $value\n";
244 243 }
@@ -434,8 +433,32 @@
434 433 } else {
435 434 unset( $cp_options['cookies'] );
436 435 }
437 436
437 + /**
438 + * Optional file and folder exclusions.
439 + */
440 + $tmp_exclusions = [];
441 + if (! empty( $_POST['exclusions'] ) ) {
442 + $tmp_array = explode( PHP_EOL, trim( stripslashes( $_POST['exclusions'] ) ) );
443 + foreach( $tmp_array as $item ) {
444 + $item = trim( code_profiler_ASCII_filter( $item ) );
445 + if ( $item ) {
446 + $tmp_exclusions[] = $item;
447 + }
448 + }
449 + }
450 + /**
451 + * Remove duplicates.
452 + */
453 + $exclusions = array_unique( $tmp_exclusions );
454 +
455 + if ( $exclusions) {
456 + $cp_options['exclusions'] = json_encode( $exclusions );
457 + } else {
458 + unset( $cp_options['exclusions'] );
459 + }
460 +
438 461 update_option('code-profiler', $cp_options );
439 462
440 463 code_profiler_log_debug(
441 464 esc_html__('Sending HTTP request', 'code-profiler')
@@ -460,25 +483,82 @@
460 483 code_profiler_log_debug(
461 484 esc_html__('Fetching HTTP response', 'code-profiler')
462 485 );
463 486
487 + /**
488 + * Always log last HTTP response headers and body,
489 + * except sensitive data (cookies & PHP session ID).
490 + */
491 + if ( isset( $res['headers'] ) && isset( $res['body'] ) ) {
492 + /**
493 + * Search for an existing log or create it.
494 + */
495 + $last_log = code_profiler_glob(
496 + CODE_PROFILER_UPLOAD_DIR,
497 + '^last_request\.\d+?\.\d+?\.log$',
498 + true
499 + );
500 + if ( empty( $last_log[0] ) ) {
501 + $last_log[0] = CODE_PROFILER_UPLOAD_DIR .'/last_request.'. microtime( true ) .'.log';
502 + }
503 + /**
504 + * Parse headers.
505 + */
506 + $headers = "HTTP {$res['response']['code']} {$res['response']['message']}\n";
507 +
508 + foreach( $res['headers'] as $key => $value ) {
509 + /**
510 + * Remove cookies.
511 + */
512 + if ( $key == 'set-cookie') {
513 + $headers .= ucfirst( $key ) .': *** '. __('Removed', 'code-profiler') ." ***\n";
514 + } else {
515 + /**
516 + * HTTP headers can contain arrays.
517 + */
518 + if ( is_array( $value ) ) {
519 + foreach( $value as $k => $v ) {
520 + $headers .= ucfirst( $key ) .": $v\n";
521 + }
522 + } else {
523 + $headers .= ucfirst( $key ) .": $value\n";
524 + }
525 + }
526 + }
527 + /**
528 + * Save to the log.
529 + */
530 + file_put_contents( $last_log[0],
531 + "==================================================\n".
532 + __('Requested page:', 'code-profiler') ."\n\n".
533 + "$raw_url\n".
534 + "==================================================\n".
535 + __('Response headers:', 'code-profiler') ."\n\n".
536 + $headers .
537 + "==================================================\n".
538 + __('Response body:', 'code-profiler') ."\n\n".
539 + print_r( $res['body'], true ).
540 + "\n==================================================\n"
541 + );
542 + }
543 +
464 544 // HTTP status code
465 545 if (! empty( $cp_options['http_response'] ) ) {
466 546 if ( preg_match( "/{$cp_options['http_response']}/", $res['response']['code'] ) ) {
547 +
548 + $msg = '';
549 +
467 550 $log = esc_html__(
551 + /* Translators: HTTP response code and message */
468 552 'The website returned the following HTTP status code: %s %s.', 'code-profiler'
469 553 );
470 - if ( $res['response']['code'] >= 500 ) {
471 - $msg = $log .' '. esc_html__(
472 - 'You may find more details about this error in your PHP error log.',
473 - 'code-profiler'
474 - );
475 - } else {
476 - $msg = $log .' '. esc_html__('By default, the profiler will always abort and throw an error '.
477 - 'if the server did not return a 200 HTTP status code. You can change that behaviour in '.
478 - 'the Settings section if the page you are profiling needs to return a different '.
479 - 'code (3xx, 4xx or 5xx).', 'code-profiler');
554 +
555 + if ( $res['response']['code'] < 500 ) {
556 + $log .= ' '. esc_html__('By default, the profiler will always abort and throw an error if the server did not return a 200 HTTP status code. You can change that behaviour in the "Settings" section if the page you are profiling needs to return a different code (3xx, 4xx or 5xx).', 'code-profiler');
480 557 }
558 +
559 + $msg .= $log .' '. esc_html__('You may find more details about this error in your PHP error log and/or in the "Logs" section.', 'code-profiler');
560 +
481 561 $response['message'] = sprintf(
482 562 $msg,
483 563 (int) $res['response']['code'],
484 564 $res['response']['message']
@@ -485,8 +565,21 @@
485 565 );
486 566 code_profiler_log_error(
487 567 sprintf( $log, $res['response']['code'], $res['response']['message'] )
488 568 );
569 +
570 + // If it is a 301/302 redirection, we write the new URL to the log
571 + if ( in_array( $res['response']['code'], [301, 302] ) &&
572 + isset( $res['headers']['location'] ) ) {
573 +
574 + code_profiler_log_error(
575 + sprintf(
576 + /* Translators: URL */
577 + esc_html__('The URL redirects to: %s', 'code-profiler'),
578 + $res['headers']['location']
579 + )
580 + );
581 + }
489 582 code_profiler_wp_send_json( $response );
490 583 }
491 584 }
492 585
@@ -529,14 +622,8 @@
529 622 function codeprofiler_prepare_report() {
530 623
531 624 $response = ['status' => 'error'];
532 625
533 - code_profiler_log_debug(
534 - esc_html__('Entering AJAX endpoint (report preparation)', 'code-profiler')
535 - );
536 -
537 - code_profiler_hide_errors();
538 -
539 626 // If this is an AJAX call, make sure it comes from an admin/superadmin.
540 627 if ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'codeprofiler_prepare_report') {
541 628 // Admin/Superadmin only
542 629 if (! is_super_admin() ) {
@@ -547,8 +634,14 @@
547 634 }
548 635 }
549 636
550 637 code_profiler_log_debug(
638 + esc_html__('Entering AJAX endpoint (report preparation)', 'code-profiler')
639 + );
640 +
641 + code_profiler_hide_errors();
642 +
643 + code_profiler_log_debug(
551 644 esc_html__('Verifying security nonce', 'code-profiler')
552 645 );
553 646
554 647 // Verify the security nonce
@@ -596,13 +689,8 @@
596 689 // Take a 1s break so that we can spot any potential error
597 690 // in the backend before AJAX refresh the page
598 691 usleep( 1000000 );
599 692
600 - // Clear hash
601 - $cp_options = get_option('code-profiler');
602 - unset( $cp_options['hash'] );
603 - update_option('code-profiler', $cp_options );
604 -
605 693 code_profiler_log_info(
606 694 esc_html__('All done, exiting profiler', 'code-profiler')
607 695 );
608 696 $response['cp_profile'] = $microtime;
@@ -635,9 +723,9 @@
635 723
636 724 // Admin/Superadmin only
637 725 if (! is_super_admin() ) {
638 726 $response['message'] = esc_html__(
639 - 'You are not allowed to performed this action', 'code-profiler'
727 + 'You are not allowed to performed this action.', 'code-profiler'
640 728 );
641 729 wp_send_json( $response );
642 730 }
643 731
@@ -643,9 +731,9 @@
643 731
644 732 // Verify the security nonce
645 733 if ( empty( $_POST['cp_nonce'] ) || ! wp_verify_nonce( $_POST['cp_nonce'], 'rename-profile') ) {
646 734 $response['message'] = esc_html__(
647 - 'Missing or wrong security nonce. Reload the page and try again', 'code-profiler'
735 + 'Missing or wrong security nonce. Reload the page and try again.', 'code-profiler'
648 736 );
649 737 wp_send_json( $response );
650 738 }
651 739
@@ -667,18 +755,34 @@
667 755 wp_send_json( $response );
668 756 }
669 757 $profile = $_POST['profile'];
670 758
671 - $glob = glob( CODE_PROFILER_UPLOAD_DIR ."/$profile*" );
759 + $glob = code_profiler_glob( CODE_PROFILER_UPLOAD_DIR, "^$profile", true );
760 +
761 + $res = false;
762 +
672 763 if ( is_array( $glob ) ) {
673 764 foreach( $glob as $path ) {
674 765 // preg_quote is needed for Windows servers because ABSPATH will contain backslashes
675 - if ( preg_match('`^'. preg_quote( CODE_PROFILER_UPLOAD_DIR ) .
676 - '/(\d{10}\.\d{4})\..+?\.([a-z]+?\.profile)$`', $path, $match ) ) {
766 + if ( preg_match('`^'. preg_quote( CODE_PROFILER_UPLOAD_DIR . DIRECTORY_SEPARATOR ) .
767 + '(\d{10}\.\d{4})\..+?\.([a-z]+?\.profile)$`', $path, $match ) ) {
677 768
678 - rename( $path, CODE_PROFILER_UPLOAD_DIR . "/{$match[1]}.$new_name.{$match[2]}" );
769 + $res = rename( $path, CODE_PROFILER_UPLOAD_DIR . "/{$match[1]}.$new_name.{$match[2]}" );
770 + if ( $res === false ) {
771 + $response['message'] = esc_html__(
772 + 'The operation failed.', 'code-profiler'
773 + );
774 + wp_send_json( $response );
775 + }
679 776 }
680 777 }
778 + }
779 +
780 + if ( $res === false ) {
781 + $response['message'] = esc_html__(
782 + 'The operation failed.', 'code-profiler'
783 + );
784 + wp_send_json( $response );
681 785 }
682 786
683 787 $response['status'] = 'success';
684 788 $response['newname'] = $new_name;