%s

' ); define('CODE_PROFILER_ERROR_NOTICE', '

%s

' ); define('CODE_PROFILER_UPDATE_URI', 'https://code-profiler.com/update/' ); global $wp_version; if (! defined('CODE_PROFILER_UA') ) { // UA signatures can be user-defined in the wp-config.php define ('CODE_PROFILER_UA', [ esc_html__('Desktop', 'code-profiler') => [ 'Firefox' => 'Mozilla/5.0 (Linux x86_64; rv:100.0) Gecko/20100101 Firefox/100.0', 'Chrome' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)'. ' Chrome/102.0.5005.63 Safari/537.36', 'Edge' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,'. ' like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/100.0.1185.39' ], esc_html__('Mobile', 'code-profiler') => [ 'Android Phone' => 'Mozilla/5.0 (Android 12; Mobile; rv:68.0) Gecko/68.0 Firefox/100.0', 'Android Tablet' => 'Mozilla/5.0 (Linux; Android 12.0; SAMSUNG-SM-T377A Build/NMF26X)'. ' AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.58 Mobile Safari/537.36', 'iPhone' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_5 like Mac OS X) AppleWebKit/605.1.15'. ' (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1', 'iPad' => 'Mozilla/5.0 (iPad; CPU OS 15_5 like Mac OS X) AppleWebKit/605.1.15'. ' (KHTML, like Gecko) GSA/213.0.449417121 Mobile/15E148 Safari/604.1' ], esc_html__('Bot', 'code-profiler') => [ 'Google Bot' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', 'WordPress' => 'Mozilla/5.0 (compatible; CodeProfiler for WordPress/'. $wp_version . '; https://code-profiler.com/)' ] ] ); } if (! defined('CODE_PROFILER_MUPLUGIN') ) { define('CODE_PROFILER_MUPLUGIN', '0----code-profiler.php'); } // ===================================================================== // Update version in the DB and check if options must be updated. function code_profiler_init_update() { $cp_options = get_option( 'code-profiler' ); if ( empty( $cp_options['version'] ) || version_compare( $cp_options['version'], CODE_PROFILER_VERSION, '<' ) ) { $cp_options['version'] = CODE_PROFILER_VERSION; // Version 1.1 if (! isset( $cp_options['enable_wpcli'] ) ) { $cp_options['enable_wpcli'] = 1; } // Version 1.2 if (! isset( $cp_options['disable_wpcron'] ) ) { $cp_options['disable_wpcron'] = 1; } // Version 1.3.1 if (! isset( $cp_options['http_response'] ) ) { $cp_options['http_response'] = '^(?:3|4|5)\d{2}$'; } // Update version in the DB update_option( 'code-profiler', $cp_options ); } } add_action('admin_init', 'code_profiler_init_update' ); // ===================================================================== // Verify or create our storage folder in the uploads directory. // Call during activation and access to the plugin. function code_profiler_check_uploadsdir() { if (! file_exists( CODE_PROFILER_UPLOAD_DIR ) ) { mkdir( CODE_PROFILER_UPLOAD_DIR, 0755 ); } if (! file_exists( CODE_PROFILER_UPLOAD_DIR .'/index.html' ) ) { touch( CODE_PROFILER_UPLOAD_DIR .'/index.html' ); } // For Apache & Litespeed if (! file_exists( CODE_PROFILER_UPLOAD_DIR .'/.htaccess' ) ) { file_put_contents( CODE_PROFILER_UPLOAD_DIR .'/.htaccess', 'Require all denied' ); } // Make sure there's a MU plugin directory if (! is_dir( WPMU_PLUGIN_DIR ) ) { wp_mkdir_p( WPMU_PLUGIN_DIR ); } if (! file_exists( WPMU_PLUGIN_DIR .'/'. CODE_PROFILER_MUPLUGIN ) ) { if (! file_exists( __DIR__ .'/mu.plugin' ) ) { code_profiler_log_error( sprintf( esc_html__('Cannot find the MU plugin: %s', 'code-profiler'), __DIR__ .'/mu.plugin' )); } else { $res = copy( __DIR__ .'/mu.plugin', WPMU_PLUGIN_DIR .'/'. CODE_PROFILER_MUPLUGIN ); if ( $res === false ) { code_profiler_log_error( sprintf( esc_html__('Cannot copy the MU plugin to %s', 'code-profiler'), WPMU_PLUGIN_DIR )); } } } else { // Update MU plugin it if needed if ( md5_file( WPMU_PLUGIN_DIR .'/'. CODE_PROFILER_MUPLUGIN ) !== md5_file( __DIR__ .'/mu.plugin' ) ) { copy( __DIR__ .'/mu.plugin', WPMU_PLUGIN_DIR .'/'. CODE_PROFILER_MUPLUGIN ); } } // Log file if (! file_exists( CODE_PROFILER_LOG ) ) { file_put_contents( CODE_PROFILER_LOG, "\n" ); } } // ===================================================================== // Create the default options. function code_profiler_default_options() { $cp_options = [ 'show_paths' => 'relative', 'display_name' => 'full', 'truncate_name' => 30, 'chart_type' => 'x', 'chart_max_plugins' => 25, 'hide_empty_value' => 1, 'table_max_rows' => 30, 'warn_composer' => 1, 'enable_wpcli' => 1, 'disable_wpcron' => 1, 'http_response' => '^(?:3|4|5)\d{2}$' ]; update_option( 'code-profiler', $cp_options ); } // ===================================================================== // Create a profile name. function code_profiler_profile_name() { return date('Y-m-d_') . substr( time(), 4 ); } // ===================================================================== // Disable opcode cache. function code_profiler_disable_opcode() { try { if (extension_loaded('Zend OPcache')) { ini_set('opcache.enable', 0); } elseif ( extension_loaded('wincache') ) { ini_set('wincache.fcenabled', 0); } set_time_limit(0); } catch ( Exception $e ) { } $cp_options = get_option( 'code-profiler' ); if (! empty( $cp_options['disable_wpcron'] ) ) { if (! defined( 'DISABLE_WP_CRON' ) ) { define('DISABLE_WP_CRON', true ); } } } // ===================================================================== // Verify the security key when running the profile. function code_profiler_verify_key() { $response = [ 'status' => 'error', 'message' => __('Security keys do not match. Reload the page and try again (%s)', 'code-profiler' ) ]; $cp_options = get_option( 'code-profiler' ); if ( empty( $cp_options['hash'] ) ) { $response['message'] = sprintf( $response['message'], '#1' ); } else { if ( empty( $_REQUEST['profiler_key'] ) ) { $response['message'] = sprintf( $response['message'], '#2' ); } else { if ( $cp_options['hash'] == sha1( $_REQUEST['profiler_key'] ) ) { return; } else { $response['message'] = sprintf( $response['message'], '#3' ); } } } wp_send_json( $response ); } // ===================================================================== // Write message to the log. // Log level can be a combination of INFO (1), WARN (2) and ERROR (4). function code_profiler_write2log( $message, $level = 1 ) { file_put_contents( CODE_PROFILER_LOG, time() ."~~$level~~$message\n", FILE_APPEND ); } function code_profiler_log_info( $string ) { code_profiler_write2log( $string, 1 ); } function code_profiler_log_warn( $string ) { code_profiler_write2log( $string, 2 ); } function code_profiler_log_error( $string ) { code_profiler_write2log( $string, 4 ); } // ===================================================================== // Verify if a profile exists and return its full path. function code_profiler_get_profile_path( $id, $type = 'slugs' ) { $return = false; if (! empty( $id ) && preg_match('/^\d{10}\.\d+$/', $id ) ) { $glob = glob( CODE_PROFILER_UPLOAD_DIR ."/$id.*.$type.profile" ); if ( is_array( $glob ) && ! empty( $glob[0] ) ) { if ( preg_match( "`/$id\.(.+?).$type.profile$`", $glob[0], $match ) ) { return CODE_PROFILER_UPLOAD_DIR. "/$id.{$match[1]}"; } } } return false; } // ===================================================================== // Open, parse and return the content of a profile file. function code_profiler_get_profile_data( $file, $type = 'slugs' ) { $buffer = []; $fh = fopen( "$file.$type.profile", 'rb' ); if ( $fh === false ) { $err = sprintf( CODE_PROFILER_ERROR_NOTICE, sprintf( esc_html__('Unable to open profile file: %s.', 'code-profiler' ), esc_html( "$file.$type.profile" ) ) ); $buffer['error'] = $err; return $buffer; } while (! feof( $fh ) ) { $buffer[] = fgetcsv( $fh, 1000, "\t" ); } fclose( $fh ); if ( empty( $buffer ) ) { $err = sprintf( CODE_PROFILER_ERROR_NOTICE, sprintf( esc_html__('Profile file is empty or corrupted: %s.', 'code-profiler' ), esc_html( "$file.$type.profile" ) ) ); $buffer['error'] = $err; return $buffer; } // Get rid of the empty field created by fgetcsv return array_filter( $buffer ); } // ===================================================================== // Exit with a json-encoded error message except if we're running // from WP CLI function code_profiler_wp_send_json( $response ) { if ( defined( 'WP_CLI' ) && WP_CLI ) { WP_CLI::error( $response['message'] ); } wp_send_json( $response ); } // ===================================================================== // Retrieve the summary stats for a given profile. function code_profiler_getsummarystats( $profile_path, $type = 'html' ) { if ( $type == 'html' ) { $open = ''; } else { // WP-CLI $open = " \u{27A4} "; $div = "\n \u{27A4} "; $close = "\n\n"; } if (! file_exists( "$profile_path.summary.profile" ) ) { return false; } $decode = json_decode( file_get_contents( "$profile_path.summary.profile" ) ); $string = $open; if ( empty( $decode->items ) ) { return false; } $decode->items--; $string .= sprintf( __('%s plugins and 1 theme', 'code-profiler'), (int) $decode->items ); $string .= $div; if ( empty( $decode->time ) ) { return false; } $string .= sprintf( __('Execution time: %ss', 'code-profiler'), number_format( $decode->time, 4 ) ); $string .= $div; if ( empty( $decode->memory ) ) { return false; } $string .= sprintf( __('Peak memory: %s MB', 'code-profiler'), number_format( $decode->memory, 2) ); $string .= $div; if ( empty( $decode->io ) ) { return false; } $string .= sprintf( __('File I/O operations: %s', 'code-profiler'), number_format( $decode->io ) ); $string .= $div; if ( empty( $decode->queries ) ) { return false; } $string .= sprintf( __('SQL queries: %s', 'code-profiler'), number_format( $decode->queries ) ); $string .= $close; return $string; } // ===================================================================== // Remove *tmp files left after an HTTP error (4xx or 5xx). function code_profiler_cleantmpfiles() { $glob = glob( CODE_PROFILER_UPLOAD_DIR .'/*.tmp' ); if ( is_array( $glob ) ) { $count = 0; foreach( $glob as $file ) { $count++; unlink( $file ); } if ( $count ) { code_profiler_log_info( sprintf( __('Deleting %s temporary files found in the profiles folder', 'code-profiler' ), (int) $count ) ); } } } // ===================================================================== // Check and inform if there's an update. function code_profiler_check_update( $transient ) { if ( empty( $transient->checked['code-profiler/index.php'] ) ) { $version = CODE_PROFILER_VERSION; } else { $version = $transient->checked['code-profiler/index.php']; } $args = [ 'slug' => 'code-profiler', 'version' => $version ]; $domain = strtolower( parse_url( network_home_url(), PHP_URL_HOST ) ); global $wp_version; $request_string = array( 'body' => array( 'action' => 'version', 'request' => serialize( $args ), 'version' => CODE_PROFILER_VERSION, ), 'user-agent' => "WordPress/$wp_version;$domain; ". CODE_PROFILER_VERSION .'; version' ); $res = wp_remote_post( CODE_PROFILER_UPDATE_URI, $request_string); if (! is_wp_error( $res ) && $res['response']['code'] == 200 ) { $response = unserialize( $res['body'] ); } if ( ! empty( $response ) && is_object( $response ) ) { $transient->response['code-profiler/index.php'] = $response; } else { // No update $item = (object) array( 'id' => 'code-profiler/index.php', 'slug' => 'code-profiler', 'plugin' => 'code-profiler/index.php', 'new_version' => CODE_PROFILER_VERSION, 'url' => '', 'package' => '', 'icons' => array(), 'banners' => array(), 'banners_rtl' => array(), 'tested' => '', 'requires_php' => '', 'compatibility' => new stdClass(), ); // Needed for the enable/disable auto-updates link. $transient->no_update['code-profiler/index.php'] = $item; } return $transient; } add_filter('pre_set_site_transient_update_plugins', 'code_profiler_check_update'); // ===================================================================== // We return the new version's changelog. function code_profiler_check_plugin_info( $def, $action, $args ) { if (! isset($args->slug) || $args->slug != 'code-profiler' || $action != 'plugin_information' ) { return $def; } $plugin_info = get_site_transient('update_plugins'); if ( isset( $plugin_info->checked['code-profiler/index.php'] ) ) { $current_version = $plugin_info->checked['code-profiler/index.php']; } else { $current_version = CODE_PROFILER_VERSION; } $args->version = $current_version; $domain = strtolower( parse_url( network_home_url(), PHP_URL_HOST ) ); global $wp_version; $request_string = array( 'body' => array( 'action' => 'plugin_information', 'request' => serialize( $args ), 'version' => CODE_PROFILER_VERSION ), 'user-agent' => "WordPress/$wp_version;$domain; ". CODE_PROFILER_VERSION .'; plugin_information' ); $res = wp_remote_post( CODE_PROFILER_UPDATE_URI, $request_string ); if (! is_wp_error( $res ) && $res['response']['code'] == 200 ) { // Server can return either serialized data or a json-encoded error if ( is_serialized( $res['body'] ) ) { return unserialize( $res['body'] ); } } return false; } add_filter('plugins_api', 'code_profiler_check_plugin_info', 10, 3); // ===================================================================== // We don't want to be bothered by other themes/plugins' admin notices. add_action('admin_head', 'code_profiler_hide_admin_notices'); function code_profiler_hide_admin_notices() { if ( isset( $_GET['page'] ) && $_GET['page'] == 'code-profiler' ) { remove_all_actions('admin_notices'); remove_all_actions('all_admin_notices'); } } // ===================================================================== // EOF