PluginProbe
Code Profiler – WordPress Performance Profiling and Debugging Made Easy / 1.9.3
Code Profiler – WordPress Performance Profiling and Debugging Made Easy v1.9.3
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-troubleshooter.php

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

433 lines 11.6 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 +=====================================================================+ 2024-08-14
12 */
13
14 if (! defined('ABSPATH') ) {
15 die('Forbidden');
16 }
17
18 // =====================================================================
19
20 class CP_Troubleshooter {
21
22 /**
23 * Array to handle all results
24 */
25 private $buffer = [];
26
27 /**
28 * Initialize.
29 */
30 public function __construct() {
31
32 $this->get_system_info('sysinfo');
33 $this->test_admin_ajax('admin-ajax');
34 $this->cp_info('code-profiler');
35 $this->function_exists('code-profiler');
36 $this->check_wpdb('wpdb');
37 $this->check_cache('cache');
38 $this->check_proxy('proxy');
39 $this->is_multisite('multisite');
40 $this->get_all_plugins('plugins');
41 $this->get_theme('themes');
42 $this->get_cp_config();
43
44 echo esc_textarea( print_r( $this->buffer, true ) );
45 }
46
47 /**
48 * Retrieve system info:
49 * * PHP version
50 * * PHP SAPI
51 * * HTTP server
52 * * Opcode cache
53 * * PHP directives (time limit, memory available, temp dir etc)
54 * * PHP last error
55 * * WordPress
56 */
57 private function get_system_info( $key ) {
58
59 $this->buffer[ $key ]['OS'] = php_uname();
60
61 if (! empty( $_SERVER['SERVER_NAME'] ) ) {
62 $this->buffer[ $key ]['SERVER_NAME'] = $_SERVER['SERVER_NAME'];
63 } else {
64 $this->buffer[ $key ]['SERVER_NAME'] = 'N/A';
65 }
66
67 if (! empty( $_SERVER['SERVER_SOFTWARE'] ) ) {
68 $this->buffer[ $key ]['HTTP server'] = $_SERVER['SERVER_SOFTWARE'];
69 } else {
70 $this->buffer[ $key ]['HTTP server'] = 'N/A';
71 }
72
73 $this->buffer[ $key ]['PHP'] = strtoupper( PHP_SAPI ) .' '. PHP_VERSION;
74
75 if ( extension_loaded('Zend OPcache') ) {
76 $this->buffer[ $key ]['Opcode cache'] = sprintf(
77 'Zend OPcache (%s)', ini_get('opcache.enable') ? 'enabled':'disabled'
78 );
79 } elseif ( extension_loaded('wincache') ) {
80 $this->buffer[ $key ]['Opcode cache'] = sprintf(
81 'wincache (%s)', ini_get('wincache.fcenabled') ? 'enabled':'disabled'
82 );
83 }
84
85 $this->buffer[ $key ]['Memory limit'] = ini_get('memory_limit');
86 $this->buffer[ $key ]['Peak limit'] = number_format( memory_get_peak_usage() );
87 $this->buffer[ $key ]['Max execution time'] = ini_get('max_execution_time') .'s';
88 $this->buffer[ $key ]['Disabled functions'] = ini_get('disable_functions');
89 $this->buffer[ $key ]['Display errors'] = ini_get('display_errors');
90
91 $tmp = ini_get('sys_temp_dir');
92 if (! empty( $tmp ) ) {
93 if ( is_writable( $tmp ) ) {
94 $tmp .= ' (writable)';
95 } else {
96 $tmp .= ' (not writable!)' .' ⚠️';
97 }
98 }
99 $tmp = $this->shorten_path( $tmp );
100 $this->buffer[ $key ]['Temp directory'] = $tmp;
101 $this->buffer[ $key ]['Log errors'] = ini_get('log_errors');
102
103 $error_log = ini_get('error_log');
104 $filesize = 0;
105 if ( is_file( $error_log ) ) {
106 $filesize = filesize( $error_log );
107 }
108 $this->buffer[ $key ]['Error log'] = "$error_log (". number_format( $filesize ) ." bytes)";
109
110 $this->buffer[ $key ]['Last error'] = error_get_last();
111 if ( isset( $this->buffer[ $key ]['Last error']['file'] ) ) {
112 $this->buffer[ $key ]['Last error']['file'] = $this->shorten_path( $this->buffer[ $key ]['Last error']['file'] );
113 }
114
115 // WordPress
116 if ( defined('WP_MEMORY_LIMIT') ) {
117 $this->buffer[ $key ]['WordPress']['WP_MEMORY_LIMIT'] = WP_MEMORY_LIMIT;
118 } else {
119 $this->buffer[ $key ]['WordPress']['WP_MEMORY_LIMIT'] = 'N/A';
120 }
121 if ( defined('WP_MAX_MEMORY_LIMIT') ) {
122 $this->buffer[ $key ]['WordPress']['WP_MAX_MEMORY_LIMIT'] = WP_MAX_MEMORY_LIMIT;
123 } else {
124 $this->buffer[ $key ]['WordPress']['WP_MAX_MEMORY_LIMIT'] = 'N/A';
125 }
126 global $wp_version;
127 $this->buffer[ $key ]['WordPress']['version'] = $wp_version;
128 $wp_debug = '';
129 if ( defined('WP_DEBUG') ) {
130 $wp_debug = WP_DEBUG;
131 }
132 $this->buffer[ $key ]['WordPress']['WP_DEBUG'] = $wp_debug;
133 $wp_debug = '';
134 $filesize = 0;
135 if ( defined('WP_DEBUG_LOG') ) {
136 $wp_debug = WP_DEBUG_LOG;
137 }
138 if ( is_file( $wp_debug ) ) {
139 $filesize = filesize( $error_log );
140 $wp_debug = $this->shorten_path( $wp_debug ) ." (". number_format( $filesize ) ." bytes)";
141 }
142 $this->buffer[ $key ]['WordPress']['WP_DEBUG_LOG'] = $wp_debug;
143
144 /**
145 * WPMU plugins directory.
146 */
147 $this->buffer[ $key ]['WordPress']['WPMU_PLUGIN_DIR']['DIR'] =
148 $this->shorten_path( WPMU_PLUGIN_DIR );
149 $this->buffer[ $key ]['WordPress']['WPMU_PLUGIN_DIR']['writable'] =
150 is_writable( WPMU_PLUGIN_DIR );
151
152 /**
153 * SAVEQUERIES: make sure it is not set to false.
154 */
155 if ( defined('SAVEQUERIES') ) {
156 if ( SAVEQUERIES === false ) {
157 $this->buffer[ $key ]['WordPress']['SAVEQUERIES'] = 'FALSE' .' ⚠️';
158 } else {
159 $this->buffer[ $key ]['WordPress']['SAVEQUERIES'] = SAVEQUERIES;
160 }
161 } else {
162 $this->buffer[ $key ]['WordPress']['SAVEQUERIES'] = 'N/A';
163 }
164
165 /**
166 * xdebug.
167 */
168 if ( extension_loaded('xdebug') ) {
169 $this->buffer[ $key ]['Xdebug'] = esc_html__('Extension is loaded', 'code-profiler') .' ⚠️';
170 } else {
171 $this->buffer[ $key ]['Xdebug'] = '0';
172 }
173 }
174
175
176 /**
177 * Verify if some important PHP functions are available.
178 */
179 private function function_exists( $key ) {
180
181 $required_functions = [
182 'register_shutdown_function' => 'shutdown',
183 'register_tick_function' => 'tick',
184 'stream_wrapper_unregister' => 'unregister',
185 'stream_wrapper_register' => 'register',
186 'stream_wrapper_restore' => 'restore',
187 'hrtime' => 'hrtime'
188 ];
189
190 foreach ( $required_functions as $function => $value ) {
191 $this->buffer[ $key ]['function'][ $value ] = function_exists( $function );
192 }
193
194 $required_methods = [
195 'PhpToken' => 'tokenize'
196 ];
197 foreach ( $required_methods as $class => $value ) {
198 $this->buffer[ $key ]['method'][ $value ] = method_exists( $class, $value );
199 }
200 }
201
202
203 /**
204 * Return the version and type (free/pro) of Code Profiler.
205 */
206 private function cp_info( $key ) {
207
208 if ( defined('CODE_PROFILER_PRO_VERSION') ) {
209 $this->buffer[ $key ]['slug'] = 'code-profiler-pro';
210 $this->buffer[ $key ]['version'] = CODE_PROFILER_PRO_VERSION;
211
212 } elseif ( defined('CODE_PROFILER_VERSION') ) {
213 $this->buffer[ $key ]['slug'] = 'code-profiler';
214 $this->buffer[ $key ]['version'] = CODE_PROFILER_VERSION;
215
216 } else {
217 exit('Error: Code Profiler is not active. Please activate it and run this script again.');
218
219 }
220
221 // Data folder must be writable
222 $upload_dir = wp_upload_dir();
223 $dir = $upload_dir['basedir'] .'/'. $this->buffer[ $key ]['slug'];
224
225 $this->buffer[ $key ]['data_dir']['path'] = $this->shorten_path( $dir );
226 $this->buffer[ $key ]['data_dir']['exists'] = file_exists( $dir );
227 $this->buffer[ $key ]['data_dir']['writable'] = is_writable( $dir );
228 }
229
230
231 /**
232 * Check if there are subclasses of the wpdb class and
233 * look for wp-content/db.php
234 */
235 function check_wpdb( $key ) {
236
237 foreach( get_declared_classes() as $class ) {
238 $reflected = new ReflectionClass( $class );
239 if ( $reflected->isSubclassOf('wpdb') ) {
240 $script = $reflected->getFileName();
241 $this->buffer[ $key ]['extends'][$class] = $this->shorten_path( $script );
242 }
243 }
244 $db_php = $this->shorten_path( WP_CONTENT_DIR .'/db.php');
245 $this->buffer[ $key ][ $db_php ] = file_exists( WP_CONTENT_DIR .'/db.php');
246 }
247
248
249 /**
250 * Check for advanced cache
251 */
252 private function check_cache( $key ) {
253
254 $this->buffer[ $key ] = [];
255 if ( defined('WP_CACHE') && file_exists( WP_CONTENT_DIR . '/advanced-cache.php') ) {
256 $this->buffer[ $key ][ $this->shorten_path( WP_CONTENT_DIR . '/advanced-cache.php') ] = 1;
257 }
258 }
259
260
261 /**
262 * Check for reverse proxy or CDN
263 */
264 private function check_proxy( $key ) {
265
266 $this->buffer[ $key ] = [];
267 $proxies = [
268 'HTTP_X_FORWARDED_FOR',
269 'HTTP_CF_CONNECTING_IP',
270 'HTTP_INCAP_CLIENT_IP'
271 ];
272
273 foreach( $proxies as $proxy ) {
274 if (! empty( $_SERVER[ $proxy ] ) ) {
275 $this->buffer[ $key ][ $proxy ] = 1;
276 }
277 }
278
279 }
280
281
282 /**
283 * Check if that is a multisite installation.
284 */
285 private function is_multisite( $key ) {
286
287 if ( is_multisite() ) {
288 global $current_blog;
289 $this->buffer[ $key ] = "site: {$current_blog->site_id}, blog: {$current_blog->blog_id}";
290 return;
291 }
292
293 $this->buffer[ $key ] = 0;
294 }
295
296
297 /**
298 * Retrieve the list of all plugins and sort them
299 * (active or disabled).
300 */
301 private function get_all_plugins( $key ) {
302
303 if (! function_exists('get_plugins') ) {
304 require_once ABSPATH .'wp-admin/includes/plugin.php';
305 }
306 $plugins = get_plugins();
307 foreach( $plugins as $k => $v ) {
308 if ( $slug = substr( $k, 0, strpos( $k, '/') ) ) {
309 $name = 'N/A'; $version = 'N/A'; $uri = 'N/A';
310 if (! empty( $v['Name'] ) ) {
311 $name = $v['Name'];
312 }
313 if (! empty( $v['Version'] ) ) {
314 $version = $v['Version'];
315 }
316 if (! empty( $v['PluginURI'] ) ) {
317 $uri = $v['PluginURI'];
318 }
319 if ( is_plugin_active( $k ) ) {
320 $this->buffer[ $key ]['active'][ $slug ] = "$name - $version - $uri";
321
322 } else {
323 $this->buffer[ $key ]['inactive'][ $slug ] = "$name - $version - $uri";
324 }
325 }
326 }
327
328 $mu_plugins = get_mu_plugins();
329 foreach( $mu_plugins as $k => $v ) {
330 $name = 'N/A'; $version = 'N/A'; $uri = 'N/A';
331 if (! empty( $v['Name'] ) ) {
332 $name = $v['Name'];
333 }
334 if (! empty( $v['Version'] ) ) {
335 $version = $v['Version'];
336 }
337 if (! empty( $v['PluginURI'] ) ) {
338 $uri = $v['PluginURI'];
339 }
340 $this->buffer[ $key ]['mu-plugins'][ $k ] = "$name - $version - $uri";
341 }
342
343 }
344
345
346 /**
347 * Retrieve the active theme.
348 */
349 private function get_theme( $key ) {
350
351 $themes = wp_get_themes();
352 $active = get_option('template');
353 foreach( $themes as $k => $v ) {
354 $name = 'N/A'; $version = 'N/A';
355 if ( $v->Name ) {
356 $name = $v->Name;
357 }
358 if ( $v->Version ) {
359 $version = $v->Version;
360 }
361 if ( $k == $active ) {
362 $this->buffer[ $key ]['active'][ $k ] = "$name - $version";
363 } else {
364 $this->buffer[ $key ]['inactive'][ $k ] = "$name - $version";
365 }
366 }
367 }
368
369
370 /**
371 * Retrieve Code Profiler's configuration
372 */
373 private function get_cp_config() {
374
375 $cp_options = get_option('code-profiler');
376
377 $list = [
378 'hide_empty_value',
379 'enable_wpcli',
380 'disable_wpcron',
381 // 'disable_db-php',
382 'http_response',
383 // 'backtrace_limit',
384 'accuracy',
385 'buffer',
386 'exclusions'
387 ];
388 foreach( $list as $element ) {
389 $this->buffer['options'][ $element ] = isset( $cp_options[ $element ] )? $cp_options[ $element ]:0;
390 }
391 }
392
393 /**
394 * Remove the ABSPATH from a path
395 */
396 private function shorten_path( $path ) {
397
398 return str_replace( ABSPATH, '', $path );
399 }
400
401
402 /**
403 * Test if admin-ajax is accessible.
404 */
405 private function test_admin_ajax( $key ) {
406
407 $headers = [
408 // Devs must be allowed to use it on localhost over TLS too
409 'sslverify' => apply_filters('https_local_ssl_verify', false )
410 ];
411 $res = wp_safe_remote_get( admin_url('admin-ajax.php?action=generate-password'), $headers );
412
413 /* Translators: Error message */
414 $error = __('Error: %s', 'code-profiler');
415
416 // Connection error
417 if ( is_wp_error( $res ) ) {
418 $msg = sprintf( $error, $res->get_error_message() );
419
420 } elseif ( $res['response']['code'] != 200 ) {
421 $msg = sprintf( $error, $res['response']['code'] ." ". $res['response']['message'] );
422
423 } else {
424 $msg = "OK";
425 }
426 $this->buffer[ $key ]['access'] = $msg;
427 }
428
429 }
430
431 // =====================================================================
432 // EOF
433