PluginProbe
Code Profiler – WordPress Performance Profiling and Debugging Made Easy / 1.7.2
Code Profiler – WordPress Performance Profiling and Debugging Made Easy v1.7.2
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.7.2, at lib/class-cli.php

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