PluginProbe
Code Profiler – WordPress Performance Profiling and Debugging Made Easy / 1.8
Code Profiler – WordPress Performance Profiling and Debugging Made Easy v1.8
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
code-profiler / lib / class-cli.php

class-cli.php in Code Profiler – WordPress Performance Profiling and Debugging Made Easy 1.8, at lib/class-cli.php

300 lines 8.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 +=====================================================================+
4 | ____ _ ____ __ _ _ |
5 | / ___|___ __| | ___ | _ \ _ __ ___ / _(_) | ___ _ __ |
6 | | | / _ \ / _` |/ _ \ | |_) | '__/ _ \| |_| | |/ _ \ '__| |
7 | | |__| (_) | (_| | __/ | __/| | | (_) | _| | | __/ | |
8 | \____\___/ \__,_|\___| |_| |_| \___/|_| |_|_|\___|_| |
9 | |
10 | (c) Jerome Bruandet ~ https://nintechnet.com/codeprofiler/ |
11 +=====================================================================+
12 */
13
14 if (! defined('ABSPATH') ) { die('Forbidden'); }
15
16 // =====================================================================
17
18 class CodeProfiler_CLI extends WP_CLI_Command {
19
20 private $file;
21 private $cmd_view = 'wp code-profiler view';
22 private $cmd_run = 'wp code-profiler run';
23
24 /**
25 * Run the profiler.
26 *
27 */
28 public function run( $args, $assoc_args ) {
29
30 $this->is_enabled();
31
32 $_POST['cp_nonce'] = wp_create_nonce('start_profiler_nonce');
33
34 $_POST['post'] = home_url( '/' );
35 // Mark the connection as 'HTTPS' if needed.
36 if ( strtolower( parse_url( $_POST['post'], PHP_URL_SCHEME ) ) == 'https') {
37 $_SERVER['HTTPS'] = 'on';
38 }
39
40 $_POST['x_end'] = 'frontend';
41 // Detect if we're authenticated or not
42 if ( is_user_logged_in() === true ) {
43 $_POST['x_auth'] = 'authenticated';
44 } else {
45 $_POST['x_auth'] = 'unauthenticated';
46 }
47 $_POST['profile'] = 'WP-CLI_' . time();
48 $_POST['user_agent'] = 'Firefox';
49
50 if (! empty( $assoc_args['dest'] ) ) {
51 $message = sprintf(
52 __('The "%s" option is only available in the pro version of Code Profiler.', 'code-profiler'),
53 '--dest'
54 );
55 WP_CLI::error( $message );
56 exit;
57 }
58
59 // HTTP basic authentication
60 if (! empty( $assoc_args['u'] ) ) {
61 _e('Enter your HTTP basic authentication password:', 'code-profiler');
62 echo ' ';
63 echo "\033[30;40m";
64 $password = trim( stream_get_line( STDIN, 255, PHP_EOL) );
65 echo "\033[0m";
66 $_POST['Authorization'] = 'Basic '. base64_encode( "{$assoc_args['u']}:{$password}" );
67 }
68
69 WP_CLI::log( sprintf(
70 __('Starting Code Profiler v%s (profile: %s)', 'code-profiler'),
71 CODE_PROFILER_VERSION, $_POST['profile'] ) . "\n"
72 );
73
74 $progress = \WP_CLI\Utils\make_progress_bar( '', 3 );
75 $progress->tick();
76
77 // Run the profiler
78 $response = json_decode( codeprofiler_start_profiler(), true );
79 if ( $response === false ) {
80 $message = __('Unknown error returned by AJAX', 'code-profiler');
81 WP_CLI::error( $message );
82 exit;
83 }
84 if ( $response['status'] == 'error' ) {
85 WP_CLI::error( $response['message'] );
86 exit;
87 }
88
89 $progress->tick();
90
91 // All good, run the parser
92 $_POST['microtime'] = $response['microtime'];
93 $response = json_decode( codeprofiler_prepare_report(), true );
94 if ( $response === false ) {
95 $message = __('Unknown error returned by AJAX', 'code-profiler');
96 WP_CLI::error( $message );
97 exit;
98 }
99 if ( $response['status'] == 'error' ) {
100 WP_CLI::error( $response['message'] );
101 exit;
102 }
103
104 $progress->tick();
105 $progress->finish();
106
107 // Run the parser and show the results
108 $this->view( $response['cp_profile'] );
109
110 exit;
111 }
112
113
114 /**
115 * Display last created profile.
116 *
117 */
118 public function view( $profile = '') {
119
120 $this->is_enabled();
121
122 // The profile was just created (`wp code-profiler run`)...
123 if (! empty( $profile ) ) {
124 $this->file = code_profiler_get_profile_path( $profile );
125 if ( $this->file === false ) {
126 $message = __('Cannot find the profile file', 'code-profiler');
127 WP_CLI::error( $message );
128 exit;
129 }
130 $this->file .= '.slugs.profile';
131
132 // ... or we show last created one (`wp code-profiler view`)
133 } else {
134 $this->file = $this->find_last_profile();
135 if ( $this->file === false ) {
136 $message = sprintf(
137 __('No profile found. Run the profiler at least once to create a profile: %s', 'code-profiler'),
138 $this->cmd_run
139 );
140 WP_CLI::error( $message );
141 exit;
142 }
143 }
144
145 // Fetch and display the profile's name only
146 preg_match(
147 '`'. CODE_PROFILER_UPLOAD_DIR .'/\d{10}\.\d+\.(.+?)\.slugs\.profile$`',
148 $this->file,
149 $match
150 );
151 $message = sprintf( __('Viewing: %s', 'code-profiler'), $match[1] );
152 $date = date('Y/m/d \@ H:i:s', filemtime( $this->file ) );
153 echo WP_CLI::colorize("\n%Y$message ~ $date%n\n\n");
154
155 // Display stats
156 $summary_file = str_replace('.slugs.profile', '', $this->file );
157 echo code_profiler_getsummarystats( $summary_file, 'text');
158
159 $slugs = $this->read_profile();
160
161 $cp_options = get_option('code-profiler');
162
163 // Get the total time and the slowest item
164 $total_time = 0;
165 foreach( $slugs as $k => $v ) {
166 $total_time += $v[1];
167 }
168
169 $coeff = number_format( $slugs[0][1] / $total_time * 100 );
170
171 foreach( $slugs as $k => $v ) {
172
173 // Display name, time and %
174 if ( isset( $cp_options['display_name'] ) && $cp_options['display_name'] == 'slug' ) {
175 $name = $v[0];
176 } else {
177 $name = $v[2];
178 }
179 // Inform if it's the theme or a mu-plugin
180 if ( $v[3] == 'theme') {
181 $name .= ' (theme)';
182 } elseif ( $v[3] == 'mu-plugin') {
183 $name .= ' (mu-plugin)';
184 }
185
186 $time = number_format( $v[1], 3 );
187 $percent = number_format( $v[1] / $total_time * 100 );
188 $chars = number_format( $percent * 80 / $coeff );
189 // We use `echo` instead of `WP_CLI::log` because the layout could
190 // be all messed-up when some caching plugins such as LiteSpeed Cache
191 // are activated.
192 echo " $name | {$time}s | {$percent}%\n";
193 if (! $percent ) {
194 echo " \u{258C}\n\n";
195 } else {
196 $bar = '';
197 for ( $i = 0; $i < $chars; $i++ ) {
198 $bar .= ' ';
199 }
200 echo WP_CLI::colorize(" %8$bar%n\n\n");
201 }
202 }
203 exit;
204 }
205
206
207 /**
208 * Retrieve the full path/name to the last created profile
209 *
210 */
211 private function find_last_profile() {
212
213 $profiles = code_profiler_glob( CODE_PROFILER_UPLOAD_DIR, '\.slugs\.profile$', true );
214
215 array_multisort(
216 array_map('filectime', $profiles ),
217 SORT_NUMERIC,
218 SORT_DESC,
219 $profiles
220 );
221
222 if (! empty( $profiles[0] ) ) {
223 return $profiles[0];
224 }
225
226 return false;
227 }
228
229
230 /**
231 * Parse and return the profile's data
232 *
233 */
234 private function read_profile() {
235
236 $profile = str_replace('.slugs.profile', '', $this->file );
237
238 $res = code_profiler_get_profile_data( $profile );
239 if ( isset( $res['error'] ) ) {
240 WP_CLI::error( $res['error'] );
241 exit;
242 }
243
244 // Sort data (slowest plugin/theme first)
245 usort( $res, function( $a, $b ) {
246 return $b[1] <=> $a[1];
247 } );
248
249 return $res;
250 }
251
252
253 /**
254 * Verify wether WP CLI integration is enabled or not
255 *
256 */
257 private function is_enabled() {
258
259 $cp_options = get_option('code-profiler');
260 if ( empty( $cp_options['enable_wpcli'] ) ) {
261 $message = __('WP-CLI integration is disabled. To enable it, log in to your admin dashboard and go to the Code Profiler settings page.', 'code-profiler');
262 WP_CLI::error( $message );
263 exit;
264 }
265 }
266
267
268 /**
269 * Display help screen and quit.
270 *
271 */
272 public function help() {
273
274 $this->is_enabled();
275
276 WP_CLI::log("\nCode Profiler v". CODE_PROFILER_VERSION .
277 " (c)". date('Y') ." Jerome Bruandet & NinTechNet Limited ~ https://nintechnet.com/codeprofiler/\n\n".
278 " {$this->cmd_view} ". __('View last created profile', 'code-profiler') ."\n".
279 " {$this->cmd_run} ". __('Run the profiler in the frontend', 'code-profiler') ."\n\n".
280 __('GLOBAL PARAMETERS', 'code-profiler') ."\n\n".
281 " --dest=<URL to profile> **". __('Pro version only', 'code-profiler') ."**\n".
282 " ". __('Path to the WordPress page or post to profile. If missing, profile the frontend.', 'code-profiler') ."\n\n".
283 " --user=<id|login|email>\n".
284 " ". __('Run the profiler as the corresponding WordPress user. If missing, run as an unauthenticated user.', 'code-profiler') ."\n\n".
285 " --u=<username>\n".
286 " ". __('HTTP Basic authentication username. You will be prompted to enter your password.', 'code-profiler') ."\n\n");
287 exit;
288 }
289
290 }
291
292 WP_CLI::add_command(
293 'code-profiler',
294 'CodeProfiler_CLI',
295 ['shortdesc' => 'Profile your blog with Code Profiler.']
296 );
297
298 // =====================================================================
299 // EOF
300