| @@ -6,15 +6,17 @@ | ||
| 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 | +// ===================================================================== 2023-11-17 | |
| 17 | 19 | // Start the profiler. |
| 18 | 20 | |
| 19 | 21 | add_action('wp_ajax_codeprofiler_start_profiler', 'codeprofiler_start_profiler'); |
| 20 | 22 | |
| @@ -21,8 +23,10 @@ | ||
| 21 | 23 | function codeprofiler_start_profiler() { |
| 22 | 24 | |
| 23 | 25 | $response = ['status' => 'error']; |
| 24 | 26 | |
| 27 | + code_profiler_hide_errors(); | |
| 28 | + | |
| 25 | 29 | $cp_options = get_option('code-profiler'); |
| 26 | 30 | |
| 27 | 31 | code_profiler_log_debug( |
| 28 | 32 | esc_html__('Entering AJAX endpoint (profiler initialization)', 'code-profiler') |
| @@ -43,10 +47,15 @@ | ||
| 43 | 47 | esc_html__('Verifying security nonce', 'code-profiler') |
| 44 | 48 | ); |
| 45 | 49 | |
| 46 | 50 | // Verify the security nonce |
| 47 | - if ( empty( $_POST['cp_nonce'] ) || ! wp_verify_nonce( $_POST['cp_nonce'], 'start_profiler_nonce') ) { | |
| 48 | - $msg = esc_html__('Missing or wrong security nonce. Reload the page and try again', 'code-profiler'); | |
| 51 | + if ( empty( $_POST['cp_nonce'] ) || | |
| 52 | + ! wp_verify_nonce( $_POST['cp_nonce'], 'start_profiler_nonce') ) { | |
| 53 | + | |
| 54 | + $msg = esc_html__( | |
| 55 | + 'Missing or wrong security nonce. Reload the page and try again', | |
| 56 | + 'code-profiler' | |
| 57 | + ); | |
| 49 | 58 | $response['message'] = $msg; |
| 50 | 59 | code_profiler_log_error( $msg ); |
| 51 | 60 | code_profiler_wp_send_json( $response ); |
| 52 | 61 | } |
| @@ -63,21 +72,18 @@ | ||
| 63 | 72 | code_profiler_wp_send_json( $response ); |
| 64 | 73 | } |
| 65 | 74 | |
| 66 | 75 | code_profiler_log_debug( |
| 67 | - esc_html__('Cleaning up the temporary folder', 'code-profiler') | |
| 68 | - ); | |
| 69 | - | |
| 70 | - // Clean-up temp files left in the profiles folder | |
| 71 | - code_profiler_cleantmpfiles(); | |
| 72 | - | |
| 73 | - code_profiler_log_debug( | |
| 74 | 76 | esc_html__('Retrieving parameters #1', 'code-profiler') |
| 75 | 77 | ); |
| 76 | 78 | |
| 77 | 79 | // Frontend or backend |
| 78 | - if ( empty( $_POST['where'] ) || ! in_array( $_POST['where'], ['frontend', 'backend', 'custom'] ) ) { | |
| 79 | - $msg = sprintf( esc_html__('Missing or incorrect parameter (%s)', 'code-profiler'), 'where'); | |
| 80 | + if ( empty( $_POST['where'] ) || | |
| 81 | + ! in_array( $_POST['where'], ['frontend', 'backend', 'custom'] ) ) { | |
| 82 | + | |
| 83 | + $msg = sprintf( | |
| 84 | + esc_html__('Missing or incorrect parameter (%s)', 'code-profiler'), 'where' | |
| 85 | + ); | |
| 80 | 86 | $response['message'] = $msg; |
| 81 | 87 | code_profiler_log_error( $msg ); |
| 82 | 88 | code_profiler_wp_send_json( $response ); |
| 83 | 89 | } |
| @@ -103,13 +109,10 @@ | ||
| 103 | 109 | esc_html__('Retrieving parameters #3', 'code-profiler') |
| 104 | 110 | ); |
| 105 | 111 | |
| 106 | 112 | // Authentication |
| 107 | - if ( empty( $_POST['user'] ) || ! in_array( $_POST['user'], ['authenticated', 'unauthenticated'] ) ) { | |
| 108 | - $msg = sprintf( esc_html__('Missing or incorrect parameter (%s)', 'code-profiler'), 'user'); | |
| 109 | - $response['message'] = $msg; | |
| 110 | - code_profiler_log_error( $msg ); | |
| 111 | - code_profiler_wp_send_json( $response ); | |
| 113 | + if ( empty( $_POST['user'] ) || $_POST['user'] != 'authenticated' ) { | |
| 114 | + $_POST['user'] = 'unauthenticated'; | |
| 112 | 115 | } |
| 113 | 116 | $cp_options['mem_user'] = $_POST['user']; |
| 114 | 117 | |
| 115 | 118 | code_profiler_log_debug( |
| @@ -122,14 +125,17 @@ | ||
| 122 | 125 | $profile = sanitize_file_name( $_POST['profile'] ); |
| 123 | 126 | } |
| 124 | 127 | |
| 125 | 128 | // URI to profile |
| 126 | - $url = esc_url_raw( $_POST['post'] ); | |
| 129 | + $url = esc_url_raw( $_POST['post'] ); | |
| 130 | + $siteurl = esc_html( site_url() ); | |
| 127 | 131 | code_profiler_log_info( sprintf( |
| 128 | - esc_html__('Initializing Code Profiler v%s for %s (profile: %s)', 'code-profiler'), | |
| 132 | + /* Translators: version, site url, profile name, profile url */ | |
| 133 | + esc_html__('Initializing Code Profiler v%s on %s. Profile: %s - %s', 'code-profiler'), | |
| 129 | 134 | CODE_PROFILER_VERSION, |
| 130 | - $url, | |
| 131 | - $profile | |
| 135 | + $siteurl, | |
| 136 | + $profile, | |
| 137 | + $url | |
| 132 | 138 | ) ); |
| 133 | 139 | |
| 134 | 140 | code_profiler_log_debug( |
| 135 | 141 | esc_html__('Retrieving parameters #5', 'code-profiler') |
| @@ -153,8 +159,27 @@ | ||
| 153 | 159 | $ua_signature = CODE_PROFILER_UA['Desktop']['Firefox']; |
| 154 | 160 | } |
| 155 | 161 | $cp_options['ua'] = $ua; |
| 156 | 162 | |
| 163 | + // Theme | |
| 164 | + $themes = code_profiler_get_themes(); | |
| 165 | + if ( empty( $_POST['theme'] ) || empty( $themes[ $_POST['theme'] ] ) ) { | |
| 166 | + $theme = ''; | |
| 167 | + unset( $cp_options['mem_theme'] ); | |
| 168 | + } else { | |
| 169 | + code_profiler_log_debug( | |
| 170 | + esc_html__('Retrieving parameters #6', 'code-profiler') | |
| 171 | + ); | |
| 172 | + $theme = $_POST['theme']; | |
| 173 | + $cp_options['mem_theme'] = $theme; | |
| 174 | + // Append the template to the stylesheet | |
| 175 | + if (! empty( $themes[ $theme ]['t'] ) ) { | |
| 176 | + $theme .= "::{$themes[ $theme ]['t']}"; | |
| 177 | + } else { | |
| 178 | + $theme .= "::$theme"; | |
| 179 | + } | |
| 180 | + } | |
| 181 | + | |
| 157 | 182 | code_profiler_log_debug( |
| 158 | 183 | esc_html__('Creating security key', 'code-profiler') |
| 159 | 184 | ); |
| 160 | 185 | |
| @@ -159,15 +184,18 @@ | ||
| 159 | 184 | ); |
| 160 | 185 | |
| 161 | 186 | // Create security key |
| 162 | 187 | $profiler_key = bin2hex( random_bytes( 16 ) ); |
| 163 | - $cp_options['hash'] = sha1( $profiler_key ); | |
| 188 | + touch( CODE_PROFILER_UPLOAD_DIR .'/key_'. sha1( $profiler_key ) .'.tmp'); | |
| 164 | 189 | |
| 165 | 190 | code_profiler_log_debug( |
| 166 | 191 | esc_html__('Building HTTP query', 'code-profiler') |
| 167 | 192 | ); |
| 168 | 193 | |
| 169 | - // Build query | |
| 194 | + /** | |
| 195 | + * Build the query. | |
| 196 | + */ | |
| 197 | + $raw_url = $url; | |
| 170 | 198 | $url = add_query_arg( [ |
| 171 | 199 | 'CODE_PROFILER_ON' => $microtime, |
| 172 | 200 | 'profiler_key' => $profiler_key |
| 173 | 201 | ], $url ); |
| @@ -182,14 +210,47 @@ | ||
| 182 | 210 | 'sslverify' => apply_filters('https_local_ssl_verify', false ), |
| 183 | 211 | 'timeout' => 300, // 300-second timeout instead of the default 5s |
| 184 | 212 | 'redirection' => 0, // We don't want to be redirected |
| 185 | 213 | 'headers' => [ |
| 186 | - 'code-profiler-key' => $profiler_key, | |
| 187 | - 'Accept-Language' => 'en-US,en;q=0.5', | |
| 188 | - 'User-Agent' => $ua_signature | |
| 214 | + // Lowercase header name | |
| 215 | + 'code-profiler-key' => $profiler_key, | |
| 216 | + 'accept-language' => 'en-US,en;q=0.5', | |
| 217 | + 'user-agent' => $ua_signature, | |
| 218 | + 'theme' => $theme | |
| 189 | 219 | ] |
| 190 | 220 | ]; |
| 191 | 221 | |
| 222 | + // Custom HTTP headers | |
| 223 | + if (! empty( $_POST['custom_headers'] ) ) { | |
| 224 | + $custom_headers = explode( PHP_EOL, trim( stripslashes( $_POST['custom_headers'] ) ) ); | |
| 225 | + if (! empty( $custom_headers[0] ) ) { | |
| 226 | + code_profiler_log_debug( | |
| 227 | + esc_html__('Building custom HTTP headers', 'code-profiler') | |
| 228 | + ); | |
| 229 | + $is_custom_headers = ''; | |
| 230 | + foreach( $custom_headers as $custom_header ) { | |
| 231 | + if ( strpos( $custom_header, ':') === false ) { | |
| 232 | + continue; | |
| 233 | + } | |
| 234 | + list( $key, $value ) = explode(':', $custom_header, 2 ); | |
| 235 | + // Lowercase header name | |
| 236 | + $key = trim( strtolower( $key ) ); | |
| 237 | + $value = trim( $value ); | |
| 238 | + // We want printable ASCII characters only | |
| 239 | + $value = code_profiler_ASCII_filter( $value ); | |
| 240 | + if (! empty( $key ) && ! empty( $value ) ) { | |
| 241 | + $headers['headers'][ $key ] = $value; | |
| 242 | + $is_custom_headers .= "$key: $value\n"; | |
| 243 | + } | |
| 244 | + } | |
| 245 | + } | |
| 246 | + } | |
| 247 | + if (! empty( $is_custom_headers ) ) { | |
| 248 | + $cp_options['custom_headers'] = json_encode( $is_custom_headers ); | |
| 249 | + } else { | |
| 250 | + unset( $cp_options['custom_headers'] ); | |
| 251 | + } | |
| 252 | + | |
| 192 | 253 | code_profiler_log_debug( |
| 193 | 254 | esc_html__('Checking HTTP options', 'code-profiler') |
| 194 | 255 | ); |
| 195 | 256 | |
| @@ -212,12 +273,12 @@ | ||
| 212 | 273 | |
| 213 | 274 | // Used for authentication |
| 214 | 275 | if ( is_ssl() ) { |
| 215 | 276 | $cookie_auth = SECURE_AUTH_COOKIE; |
| 216 | - $scheme = 'secure_auth'; | |
| 277 | + $scheme = 'secure_auth'; | |
| 217 | 278 | } else { |
| 218 | 279 | $cookie_auth = AUTH_COOKIE; |
| 219 | - $scheme = 'auth'; | |
| 280 | + $scheme = 'auth'; | |
| 220 | 281 | } |
| 221 | 282 | |
| 222 | 283 | // Retrieve the user name (since 1.4.3) |
| 223 | 284 | if (! defined('WP_CLI') ) { |
| @@ -234,10 +295,14 @@ | ||
| 234 | 295 | $response['message'] = $msg; |
| 235 | 296 | code_profiler_log_error( $msg ); |
| 236 | 297 | code_profiler_wp_send_json( $response ); |
| 237 | 298 | } |
| 238 | - $cp_options['mem_username'] = strtolower( $username ); | |
| 239 | - $headers['cookies'][ $cookie_auth ] = wp_generate_auth_cookie( $user_object->ID, time() + 180, $scheme ); | |
| 299 | + $cp_options['mem_username'] = strtolower( $username ); | |
| 300 | + $headers['cookies'][ $cookie_auth ] = wp_generate_auth_cookie( | |
| 301 | + $user_object->ID, | |
| 302 | + time() + 180, | |
| 303 | + $scheme | |
| 304 | + ); | |
| 240 | 305 | if ( empty( $headers['cookies'][ $cookie_auth ] ) ) { |
| 241 | 306 | $msg = esc_html__('Unable to create the authentication cookie', 'code-profiler'); |
| 242 | 307 | code_profiler_log_error( $msg ); |
| 243 | 308 | $response['message'] = $msg; |
| @@ -242,9 +307,13 @@ | ||
| 242 | 307 | code_profiler_log_error( $msg ); |
| 243 | 308 | $response['message'] = $msg; |
| 244 | 309 | code_profiler_wp_send_json( $response ); |
| 245 | 310 | } |
| 246 | - $headers['cookies'][ LOGGED_IN_COOKIE ] = wp_generate_auth_cookie( $user_object->ID, time() + 180, 'logged_in'); | |
| 311 | + $headers['cookies'][ LOGGED_IN_COOKIE ] = wp_generate_auth_cookie( | |
| 312 | + $user_object->ID, | |
| 313 | + time() + 180, | |
| 314 | + 'logged_in' | |
| 315 | + ); | |
| 247 | 316 | if ( empty( $headers['cookies'][ LOGGED_IN_COOKIE ] ) ) { |
| 248 | 317 | $msg = esc_html__('Unable to create the "logged_in" cookie', 'code-profiler'); |
| 249 | 318 | code_profiler_log_error( $msg ); |
| 250 | 319 | $response['message'] = $msg; |
| @@ -251,10 +320,14 @@ | ||
| 251 | 320 | code_profiler_wp_send_json( $response ); |
| 252 | 321 | } |
| 253 | 322 | // WP CLI |
| 254 | 323 | } else { |
| 255 | - $id = get_current_user_id(); | |
| 256 | - $headers['cookies'][ $cookie_auth ] = wp_generate_auth_cookie( $id, time() + 180, $scheme ); | |
| 324 | + $id = get_current_user_id(); | |
| 325 | + $headers['cookies'][ $cookie_auth ] = wp_generate_auth_cookie( | |
| 326 | + $id, | |
| 327 | + time() + 180, | |
| 328 | + $scheme | |
| 329 | + ); | |
| 257 | 330 | if ( empty( $headers['cookies'][ $cookie_auth ] ) ) { |
| 258 | 331 | $msg = esc_html__('Unable to create the authentication cookie', 'code-profiler'); |
| 259 | 332 | code_profiler_log_error( $msg ); |
| 260 | 333 | $response['message'] = $msg; |
| @@ -259,9 +332,13 @@ | ||
| 259 | 332 | code_profiler_log_error( $msg ); |
| 260 | 333 | $response['message'] = $msg; |
| 261 | 334 | code_profiler_wp_send_json( $response ); |
| 262 | 335 | } |
| 263 | - $headers['cookies'][ LOGGED_IN_COOKIE ] = wp_generate_auth_cookie( $id, time() + 180, 'logged_in'); | |
| 336 | + $headers['cookies'][ LOGGED_IN_COOKIE ] = wp_generate_auth_cookie( | |
| 337 | + $id, | |
| 338 | + time() + 180, | |
| 339 | + 'logged_in' | |
| 340 | + ); | |
| 264 | 341 | if ( empty( $headers['cookies'][ LOGGED_IN_COOKIE ] ) ) { |
| 265 | 342 | $msg = esc_html__('Unable to create the "logged_in" cookie', 'code-profiler'); |
| 266 | 343 | code_profiler_log_error( $msg ); |
| 267 | 344 | $response['message'] = $msg; |
| @@ -267,12 +344,12 @@ | ||
| 267 | 344 | $response['message'] = $msg; |
| 268 | 345 | code_profiler_wp_send_json( $response ); |
| 269 | 346 | } |
| 270 | 347 | } |
| 271 | - $session_id = session_id(); | |
| 348 | + $session_id = session_id(); | |
| 272 | 349 | if ( $session_id !== false ) { |
| 273 | - $session_name = session_name(); | |
| 274 | - $headers['cookies'][ $session_name ] = $session_id; | |
| 350 | + $session_name = session_name(); | |
| 351 | + $headers['cookies'][ $session_name ] = $session_id; | |
| 275 | 352 | } |
| 276 | 353 | } |
| 277 | 354 | |
| 278 | 355 | if ( function_exists('opcache_reset') ) { |
| @@ -283,37 +360,58 @@ | ||
| 283 | 360 | } |
| 284 | 361 | |
| 285 | 362 | // GET or POST method |
| 286 | 363 | if (! empty( $_POST['method'] ) && $_POST['method'] == 'post') { |
| 287 | - $safe_method = 'wp_safe_remote_post'; | |
| 288 | - $cp_options['mem_method'] = 'post'; | |
| 364 | + $safe_method = 'wp_safe_remote_post'; | |
| 365 | + $cp_options['mem_method'] = 'post'; | |
| 289 | 366 | |
| 367 | + // Content-type | |
| 368 | + $content_type = [ | |
| 369 | + 1 => 'application/x-www-form-urlencoded', | |
| 370 | + 2 => 'application/json' | |
| 371 | + ]; | |
| 372 | + if ( empty( $_POST['content_type'] ) || | |
| 373 | + ! in_array( $_POST['content_type'], [ 1, 2 ] ) ) { | |
| 374 | + | |
| 375 | + $cp_options['mem_content_type'] = 1; | |
| 376 | + } else { | |
| 377 | + $cp_options['mem_content_type'] = (int) $_POST['content_type']; | |
| 378 | + } | |
| 379 | + $headers['headers']['content-type'] = $content_type[ $cp_options['mem_content_type'] ]; | |
| 380 | + | |
| 290 | 381 | // Optional POST payload |
| 291 | 382 | if (! empty( $_POST['payload'] ) ) { |
| 383 | + $_payload = trim( stripslashes( $_POST['payload'] ) ); | |
| 292 | 384 | |
| 293 | 385 | code_profiler_log_debug( |
| 294 | 386 | esc_html__('Building POST payload', 'code-profiler') |
| 295 | 387 | ); |
| 296 | 388 | |
| 297 | - $payload_array = explode( PHP_EOL, trim( $_POST['payload'] ) ); | |
| 298 | - foreach( $payload_array as $item ) { | |
| 299 | - $payload = explode('=', trim( $item ), 2 ); | |
| 300 | - if ( isset( $payload[1] ) ) { | |
| 301 | - $payload[0] = trim( $payload[0] ); | |
| 302 | - $payload[1] = trim( $payload[1] ); | |
| 303 | - $headers['body'][ $payload[0] ] = $payload[1]; | |
| 389 | + // application/x-www-form-urlencoded | |
| 390 | + if ( $cp_options['mem_content_type'] == 1 ) { | |
| 391 | + $payload_array = explode( PHP_EOL, $_payload ); | |
| 392 | + foreach( $payload_array as $item ) { | |
| 393 | + $payload = explode('=', trim( $item ), 2 ); | |
| 394 | + if ( isset( $payload[1] ) ) { | |
| 395 | + $payload[0] = trim( $payload[0] ); | |
| 396 | + $payload[1] = trim( $payload[1] ); | |
| 397 | + $headers['body'][ $payload[0] ] = $payload[1]; | |
| 398 | + } | |
| 304 | 399 | } |
| 400 | + } else { | |
| 401 | + | |
| 402 | + $headers['body'] = $_payload; | |
| 305 | 403 | } |
| 306 | - $cp_options['payload'] = json_encode( $_POST['payload'] ); | |
| 307 | - $cp_options['mem_payload'] = $_POST['payload']; | |
| 404 | + $cp_options['payload'] = json_encode( $_payload ); | |
| 405 | + | |
| 308 | 406 | } else { |
| 309 | 407 | // POST request without a payload |
| 310 | 408 | unset( $cp_options['payload'] ); |
| 311 | - $cp_options['mem_payload'] = ''; | |
| 312 | 409 | } |
| 410 | + | |
| 313 | 411 | } else { |
| 314 | - $safe_method = 'wp_safe_remote_get'; | |
| 315 | - $cp_options['mem_method'] = 'get'; | |
| 412 | + $safe_method = 'wp_safe_remote_get'; | |
| 413 | + $cp_options['mem_method'] = 'get'; | |
| 316 | 414 | } |
| 317 | 415 | |
| 318 | 416 | // Optional user-defined cookies |
| 319 | 417 | if (! empty( $_POST['cookies'] ) ) { |
| @@ -321,9 +419,9 @@ | ||
| 321 | 419 | code_profiler_log_debug( |
| 322 | 420 | esc_html__('Building HTTP Cookies', 'code-profiler') |
| 323 | 421 | ); |
| 324 | 422 | |
| 325 | - $cookies_array = explode( PHP_EOL, trim( $_POST['cookies'] ) ); | |
| 423 | + $cookies_array = explode( PHP_EOL, trim( stripslashes( $_POST['cookies'] ) ) ); | |
| 326 | 424 | foreach( $cookies_array as $item ) { |
| 327 | 425 | $cookie = explode('=', trim( $item ), 2 ); |
| 328 | 426 | if ( isset( $cookie[1] ) ) { |
| 329 | 427 | $cookie[0] = trim( $cookie[0] ); |
| @@ -335,8 +433,32 @@ | ||
| 335 | 433 | } else { |
| 336 | 434 | unset( $cp_options['cookies'] ); |
| 337 | 435 | } |
| 338 | 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 | + | |
| 339 | 461 | update_option('code-profiler', $cp_options ); |
| 340 | 462 | |
| 341 | 463 | code_profiler_log_debug( |
| 342 | 464 | esc_html__('Sending HTTP request', 'code-profiler') |
| @@ -361,20 +483,103 @@ | ||
| 361 | 483 | code_profiler_log_debug( |
| 362 | 484 | esc_html__('Fetching HTTP response', 'code-profiler') |
| 363 | 485 | ); |
| 364 | 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 | + | |
| 365 | 544 | // HTTP status code |
| 366 | 545 | if (! empty( $cp_options['http_response'] ) ) { |
| 367 | 546 | if ( preg_match( "/{$cp_options['http_response']}/", $res['response']['code'] ) ) { |
| 368 | - $msg = esc_html__('The website returned the following HTTP status code: %s %s.', 'code-profiler'). | |
| 369 | - ' '. | |
| 370 | - 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'); | |
| 547 | + | |
| 548 | + $msg = ''; | |
| 549 | + | |
| 550 | + $log = esc_html__( | |
| 551 | + /* Translators: HTTP response code and message */ | |
| 552 | + 'The website returned the following HTTP status code: %s %s.', 'code-profiler' | |
| 553 | + ); | |
| 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'); | |
| 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 | + | |
| 371 | 561 | $response['message'] = sprintf( |
| 372 | 562 | $msg, |
| 373 | 563 | (int) $res['response']['code'], |
| 374 | - esc_html( $res['response']['message'] ) | |
| 564 | + $res['response']['message'] | |
| 375 | 565 | ); |
| 376 | - code_profiler_log_error( sprintf( $msg, $res['response']['code'], $res['response']['message'] ) ); | |
| 566 | + code_profiler_log_error( | |
| 567 | + sprintf( $log, $res['response']['code'], $res['response']['message'] ) | |
| 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 | + } | |
| 377 | 582 | code_profiler_wp_send_json( $response ); |
| 378 | 583 | } |
| 379 | 584 | } |
| 380 | 585 | |
| @@ -409,9 +614,9 @@ | ||
| 409 | 614 | return json_encode( $response ); |
| 410 | 615 | |
| 411 | 616 | } |
| 412 | 617 | |
| 413 | -// ===================================================================== | |
| 618 | +// ===================================================================== 2023-11-17 | |
| 414 | 619 | |
| 415 | 620 | add_action('wp_ajax_codeprofiler_prepare_report', 'codeprofiler_prepare_report'); |
| 416 | 621 | |
| 417 | 622 | function codeprofiler_prepare_report() { |
| @@ -417,12 +622,8 @@ | ||
| 417 | 622 | function codeprofiler_prepare_report() { |
| 418 | 623 | |
| 419 | 624 | $response = ['status' => 'error']; |
| 420 | 625 | |
| 421 | - code_profiler_log_debug( | |
| 422 | - esc_html__('Entering AJAX endpoint (report preparation)', 'code-profiler') | |
| 423 | - ); | |
| 424 | - | |
| 425 | 626 | // If this is an AJAX call, make sure it comes from an admin/superadmin. |
| 426 | 627 | if ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'codeprofiler_prepare_report') { |
| 427 | 628 | // Admin/Superadmin only |
| 428 | 629 | if (! is_super_admin() ) { |
| @@ -433,14 +634,23 @@ | ||
| 433 | 634 | } |
| 434 | 635 | } |
| 435 | 636 | |
| 436 | 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( | |
| 437 | 644 | esc_html__('Verifying security nonce', 'code-profiler') |
| 438 | 645 | ); |
| 439 | 646 | |
| 440 | 647 | // Verify the security nonce |
| 441 | - if ( empty( $_POST['cp_nonce'] ) || ! wp_verify_nonce( $_POST['cp_nonce'], 'start_profiler_nonce') ) { | |
| 442 | - $msg = esc_html__('Missing or wrong security nonce. Reload the page and try again', 'code-profiler'); | |
| 648 | + if ( empty( $_POST['cp_nonce'] ) || | |
| 649 | + ! wp_verify_nonce( $_POST['cp_nonce'], 'start_profiler_nonce') ) { | |
| 650 | + | |
| 651 | + $msg = esc_html__('Missing or wrong security nonce. Reload the page and try again', | |
| 652 | + 'code-profiler'); | |
| 443 | 653 | $response['message'] = $msg; |
| 444 | 654 | code_profiler_log_error( $msg ); |
| 445 | 655 | code_profiler_wp_send_json( $response ); |
| 446 | 656 | } |
| @@ -477,15 +687,10 @@ | ||
| 477 | 687 | $report->prepare_report(); |
| 478 | 688 | |
| 479 | 689 | // Take a 1s break so that we can spot any potential error |
| 480 | 690 | // in the backend before AJAX refresh the page |
| 481 | - usleep(1000000); | |
| 691 | + usleep( 1000000 ); | |
| 482 | 692 | |
| 483 | - // Clear hash | |
| 484 | - $cp_options = get_option('code-profiler'); | |
| 485 | - unset( $cp_options['hash'] ); | |
| 486 | - update_option('code-profiler', $cp_options ); | |
| 487 | - | |
| 488 | 693 | code_profiler_log_info( |
| 489 | 694 | esc_html__('All done, exiting profiler', 'code-profiler') |
| 490 | 695 | ); |
| 491 | 696 | $response['cp_profile'] = $microtime; |
| @@ -504,9 +709,9 @@ | ||
| 504 | 709 | return json_encode( $response ); |
| 505 | 710 | |
| 506 | 711 | } |
| 507 | 712 | |
| 508 | -// ===================================================================== | |
| 713 | +// ===================================================================== 2023-11-17 | |
| 509 | 714 | // Rename a profile. |
| 510 | 715 | |
| 511 | 716 | add_action('wp_ajax_codeprofiler_rename', 'codeprofiler_rename'); |
| 512 | 717 | |
| @@ -513,17 +718,23 @@ | ||
| 513 | 718 | function codeprofiler_rename() { |
| 514 | 719 | |
| 515 | 720 | $response = ['status' => 'error']; |
| 516 | 721 | |
| 722 | + code_profiler_hide_errors(); | |
| 723 | + | |
| 517 | 724 | // Admin/Superadmin only |
| 518 | 725 | if (! is_super_admin() ) { |
| 519 | - $response['message'] = esc_html__('You are not allowed to performed this action', 'code-profiler'); | |
| 726 | + $response['message'] = esc_html__( | |
| 727 | + 'You are not allowed to performed this action.', 'code-profiler' | |
| 728 | + ); | |
| 520 | 729 | wp_send_json( $response ); |
| 521 | 730 | } |
| 522 | 731 | |
| 523 | 732 | // Verify the security nonce |
| 524 | 733 | if ( empty( $_POST['cp_nonce'] ) || ! wp_verify_nonce( $_POST['cp_nonce'], 'rename-profile') ) { |
| 525 | - $response['message'] = esc_html__('Missing or wrong security nonce. Reload the page and try again', 'code-profiler'); | |
| 734 | + $response['message'] = esc_html__( | |
| 735 | + 'Missing or wrong security nonce. Reload the page and try again.', 'code-profiler' | |
| 736 | + ); | |
| 526 | 737 | wp_send_json( $response ); |
| 527 | 738 | } |
| 528 | 739 | |
| 529 | 740 | if ( empty( $_POST['new_name'] ) ) { |
| @@ -544,16 +755,34 @@ | ||
| 544 | 755 | wp_send_json( $response ); |
| 545 | 756 | } |
| 546 | 757 | $profile = $_POST['profile']; |
| 547 | 758 | |
| 548 | - $glob = glob( CODE_PROFILER_UPLOAD_DIR ."/$profile*" ); | |
| 759 | + $glob = code_profiler_glob( CODE_PROFILER_UPLOAD_DIR, "^$profile", true ); | |
| 760 | + | |
| 761 | + $res = false; | |
| 762 | + | |
| 549 | 763 | if ( is_array( $glob ) ) { |
| 550 | 764 | foreach( $glob as $path ) { |
| 551 | 765 | // preg_quote is needed for Windows servers because ABSPATH will contain backslashes |
| 552 | - if ( preg_match('`^'. preg_quote( CODE_PROFILER_UPLOAD_DIR ) .'/(\d{10}\.\d{4})\..+?\.([a-z]+?\.profile)$`', $path, $match ) ) { | |
| 553 | - rename( $path, CODE_PROFILER_UPLOAD_DIR . "/{$match[1]}.$new_name.{$match[2]}" ); | |
| 766 | + if ( preg_match('`^'. preg_quote( CODE_PROFILER_UPLOAD_DIR . DIRECTORY_SEPARATOR ) . | |
| 767 | + '(\d{10}\.\d{4})\..+?\.([a-z]+?\.profile)$`', $path, $match ) ) { | |
| 768 | + | |
| 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 | + } | |
| 554 | 776 | } |
| 555 | 777 | } |
| 778 | + } | |
| 779 | + | |
| 780 | + if ( $res === false ) { | |
| 781 | + $response['message'] = esc_html__( | |
| 782 | + 'The operation failed.', 'code-profiler' | |
| 783 | + ); | |
| 784 | + wp_send_json( $response ); | |
| 556 | 785 | } |
| 557 | 786 | |
| 558 | 787 | $response['status'] = 'success'; |
| 559 | 788 | $response['newname'] = $new_name; |