PluginProbe
Code Profiler – WordPress Performance Profiling and Debugging Made Easy / 1.9.6
Code Profiler – WordPress Performance Profiling and Debugging Made Easy v1.9.6
1.9.6 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 All 41 releases
← All changes | lib/class-table-profiles.php +157 -69 1.5.11.9.6 View file →
@@ -1,6 +1,6 @@
1 1 <?php
2 -/*
2 +/**
3 3 +=====================================================================+
4 4 | ____ _ ____ __ _ _ |
5 5 | / ___|___ __| | ___ | _ \ _ __ ___ / _(_) | ___ _ __ |
6 6 | | | / _ \ / _` |/ _ \ | |_) | '__/ _ \| |_| | |/ _ \ '__| |
@@ -6,13 +6,15 @@
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 // =====================================================================
17 19
18 20 class CodeProfiler_Table_Profiles extends WP_List_Table {
@@ -24,43 +26,56 @@
24 26 'slugs',
25 27 'summary',
26 28 'composer'
27 29 ];
30 + private $optional_files = [
31 + 'summary',
32 + 'composer'
33 + ];
28 34 private $abspath;
35 + private $row_count = 0;
29 36
37 +
38 + /**
39 + * Initialize
40 + */
30 41 function __construct() {
31 42
32 - $this->abspath = rtrim( ABSPATH, '/\\' );
43 + $this->abspath = rtrim( ABSPATH, '/\\');
33 44
34 - parent::__construct( array(
35 - 'singular' => esc_html__( 'profile', 'code-profiler' ),
36 - 'plural' => esc_html__( 'profiles', 'code-profiler' ),
45 + parent::__construct( [
46 + 'singular' => esc_html__('profile', 'code-profiler'),
47 + 'plural' => esc_html__('profiles', 'code-profiler'),
37 48 'ajax' => false
38 - ));
49 + ] );
39 50 }
40 51
41 - /*
52 +
53 + /**
42 54 * Empty list
43 55 */
44 56 function no_items() {
45 - esc_html_e( 'No profile found.', 'code-profiler' );
57 + esc_html_e('No profile found.', 'code-profiler');
46 58 }
47 59
48 - /*
60 +
61 + /**
49 62 * Default
50 63 */
51 64 function column_default( $item, $column_name ) {
52 65
53 - if ( $item[ $column_name ] == '-' ) {
66 + if ( $item[ $column_name ] == '-') {
54 67 // Old profiles (CP <=1.2) must not call number_format()
55 68 return $item[ $column_name ];
56 69 }
57 70 switch( $column_name ) {
58 - case 'profile':
59 - return $item[ $column_name ];
60 - break;
61 71 case 'date':
62 - return date('Y/m/d \@ H:i', $item[ $column_name ] );
72 + return sprintf(
73 + /* translators: This is already translated in WordPress core */
74 + __('%1$s at %2$s'),
75 + date('Y/m/d', $item[ $column_name ] ) .'<br />',
76 + date('g:i a', $item[ $column_name ] )
77 + );
63 78 break;
64 79 case 'time':
65 80 return $item[ $column_name ] .' s';
66 81 break;
@@ -76,40 +91,43 @@
76 91 return '';
77 92 }
78 93 }
79 94
80 - /*
95 +
96 + /**
81 97 * Sortable columns
82 98 */
83 99 function get_sortable_columns() {
84 - return array(
85 - 'profile' => array( 'profile', true ),
86 - 'date' => array( 'date', true ),
87 - 'items' => array( 'items', true ),
88 - 'time' => array( 'time', true ),
89 - 'mem' => array( 'mem', true ),
90 - 'io' => array( 'io', true ),
91 - 'queries' => array( 'queries', true )
92 - );
100 + return [
101 + 'profile' => ['profile', true ],
102 + 'date' => ['date', true ],
103 + 'items' => ['items', true ],
104 + 'time' => ['time', true ],
105 + 'mem' => ['mem', true ],
106 + 'io' => ['io', true ],
107 + 'queries' => ['queries', true ]
108 + ];
93 109 }
94 110
95 - /*
111 +
112 + /**
96 113 * Columns
97 114 */
98 115 function get_columns(){
99 - return array(
116 + return [
100 117 'cb' => '<input type="checkbox" />',
101 - 'profile' => esc_html__( 'Profile', 'code-profiler' ),
102 - 'date' => esc_html__( 'Date', 'code-profiler' ),
103 - 'items' => esc_html__( 'Items', 'code-profiler' ),
104 - 'time' => esc_html__( 'Time', 'code-profiler' ),
105 - 'mem' => esc_html__( 'Memory', 'code-profiler' ),
106 - 'io' => esc_html__( 'File I/O', 'code-profiler' ),
107 - 'queries' => esc_html__( 'SQL', 'code-profiler' )
108 - );
118 + 'profile' => esc_html__('Profile', 'code-profiler'),
119 + 'date' => esc_html__('Date', 'code-profiler'),
120 + 'items' => esc_html__('Items', 'code-profiler'),
121 + 'time' => esc_html__('Time', 'code-profiler'),
122 + 'mem' => esc_html__('Memory', 'code-profiler'),
123 + 'io' => esc_html__('File I/O', 'code-profiler'),
124 + 'queries' => esc_html__('SQL', 'code-profiler')
125 + ];
109 126 }
110 127
111 - /*
128 +
129 + /**
112 130 * Sorting
113 131 */
114 132 function usort_reorder( $a, $b ) {
115 133 // Sort by date by default
@@ -115,12 +133,13 @@
115 133 // Sort by date by default
116 134 $orderby = (! empty( $_GET['orderby'] ) ) ? sanitize_key( $_GET['orderby'] ) : 'ID';
117 135 $order = (! empty( $_GET['order'] ) ) ? sanitize_key( $_GET['order'] ) : 'asc';
118 136 $result = $this->cmp_num_or_string( $a[$orderby], $b[$orderby] );
119 - return ( $order === 'asc' ) ? $result : -$result;
137 + return ( $order === 'asc') ? $result : -$result;
120 138 }
121 139
122 - /*
140 +
141 + /**
123 142 * Sort string and numeric values differently
124 143 */
125 144 function cmp_num_or_string( $a, $b ) {
126 145 if ( is_numeric( $a ) && is_numeric( $b ) ) {
@@ -130,42 +149,96 @@
130 149 }
131 150 }
132 151
133 152
134 - /*
153 + /**
135 154 * Row action links
136 155 */
137 156 function column_profile( $item ) {
138 157
158 + $this->row_count++;
159 +
139 160 // Keep sorting order for the "delete" action link
140 161 $orderby = (! empty( $_GET['orderby'] ) ) ? sanitize_key( $_GET['orderby'] ) : 'ID';
141 162 $order = (! empty( $_GET['order'] ) ) ? sanitize_key( $_GET['order'] ) : 'asc';
142 163
164 + /**
165 + * The option to re-run a profile is only available with profiles created with v1.8.
166 + */
167 + if (! empty( $item['rerun'] ) ) {
168 + $rerun = sprintf(
169 + '<a href="?page=code-profiler&cptab=profiler&action=rerun&profiles[]=%1$s" title="'.
170 + esc_attr__('Re-run the profile with the same options and parameters.', 'code-profiler') .
171 + '">%2$s</a>',
172 + esc_attr( $item['ID'] ),
173 + esc_html__('Re-run', 'code-profiler')
174 + );
175 + } else {
176 + $rerun = '<font style="cursor:not-allowed" title="'.
177 + esc_attr__('This feature is only available with profiles created with Code Profiler v1.8+',
178 + 'code-profiler') .'">'. esc_html__('Re-run', 'code-profiler') .'</font>';
179 + }
180 +
143 181 $actions = array(
144 182 'view' => sprintf(
145 183 '<a href="?page=code-profiler&cptab=profiles_list&action=%s&id=%s&section=1">%s</a>',
146 - 'view_profile', esc_attr( $item['ID'] ), esc_attr__('View')
184 + 'view_profile',
185 + esc_attr( $item['ID'] ),
186 + esc_html__('View')
147 187 ),
188 + 'edit' => sprintf(
189 + '<a style="cursor:pointer" onClick="cpjs_toggle_name(\'%s\')">%s</a>',
190 + esc_attr( $this->row_count ),
191 + esc_html__('Quick Edit')
192 + ),
193 + 'rerun' => $rerun,
148 194 'delete' => sprintf(
149 - '<a href="?page=code-profiler&cptab=profiles_list&action=%s&profiles[]=%s&_wpnonce=%s&orderby=%s&order=%s" '.
150 - 'onclick="return cpjs_delete_profile();">%s</a>',
151 - 'delete_profiles', esc_attr( $item['ID'] ),
152 - wp_create_nonce( 'bulk-'. $this->_args['plural'] ), $orderby, $order, esc_attr__('Delete')
195 + '<a href="?page=code-profiler&cptab=profiles_list&action=%s&profiles[]=%s'.
196 + '&_wpnonce=%s&orderby=%s&order=%s" onclick="return cpjs_delete_profile();">%s</a>',
197 + 'delete_profiles',
198 + esc_attr( $item['ID'] ),
199 + wp_create_nonce('bulk-'. $this->_args['plural'] ),
200 + $orderby,
201 + $order,
202 + esc_html__('Delete')
153 203 )
154 204 );
155 - return sprintf( '%1$s %2$s', $item['profile'], $this->row_actions( $actions ) );
205 +
206 + $profile_name = sprintf(
207 + '<div id="profile_name_%1$s">%2$s</div>'.
208 + '<div id="profile_div_%1$s" style="display:none">'.
209 + '<input type="text" id="edit-%1$s" name="edit_%3$s" value="" maxlength="100" />'.
210 + '<p>'.
211 + '<input type="button" class="button button-primary button-small" value="%4$s" onClick="cpjs_edit_name(\'%3$s\', \'%1$s\', \'%6$s\', \'%1$s\')"/>'.
212 + '&nbsp;'.
213 + '<input type="button" class="button button-secondary button-small" value="%5$s" onClick="cpjs_toggle_name(\'%1$s\')"/>'.
214 + '&nbsp;'.
215 + '<span id="profile_spinner_%1$s" class="spinner" style="float:none"></span>'.
216 + '</p>'.
217 + '</div>',
218 + esc_attr( $this->row_count ),
219 + esc_html( $item['profile'] ),
220 + esc_attr( $item['ID'] ),
221 + esc_attr__('Update'),
222 + esc_attr__('Cancel'),
223 + wp_create_nonce('rename-profile')
224 + );
225 +
226 + return sprintf('%1$s %2$s', $profile_name, $this->row_actions( $actions ) );
156 227 }
157 228
158 - /*
229 +
230 + /**
159 231 * Bulk action menu (delete)
160 232 */
161 233 function get_bulk_actions() {
162 - return array(
234 + return [
163 235 'delete_profiles' => esc_html__('Delete')
164 - );
236 + ];
165 237 }
166 238
167 - /*
239 +
240 + /**
168 241 * Checkboxes
169 242 */
170 243 function column_cb($item) {
171 244 return sprintf(
@@ -173,9 +246,10 @@
173 246 esc_attr( $item['ID'] )
174 247 );
175 248 }
176 249
177 - /*
250 +
251 + /**
178 252 * Prepare to display profiles
179 253 */
180 254 function prepare_items() {
181 255 $columns = $this->get_columns();
@@ -184,14 +258,14 @@
184 258 $this->_column_headers = array( $columns, $hidden, $sortable );
185 259
186 260 // Fetch our data
187 261 $profile = $this->fetch_profiles();
188 - usort( $profile, array( &$this, 'usort_reorder' ) );
262 + usort( $profile, array( &$this, 'usort_reorder') );
189 263
190 264 $per_page = 30;
191 265
192 266 // If we just delete some profiles, we go back to page #1:
193 - if ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'delete_profiles' ) {
267 + if ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'delete_profiles') {
194 268 $current_page = 1;
195 269 } else {
196 270 $current_page = $this->get_pagenum();
197 271 }
@@ -204,28 +278,33 @@
204 278 'per_page' => $per_page
205 279 ));
206 280 }
207 281
208 - /*
282 +
283 + /**
209 284 * Retrieve all profiles
210 285 */
211 286 function fetch_profiles() {
212 287
213 288 $profiles = [];
214 - $glob = glob( CODE_PROFILER_UPLOAD_DIR .'/*.slugs.profile' );
289 + $glob = code_profiler_glob( CODE_PROFILER_UPLOAD_DIR, '\.slugs\.profile$', true );
215 290
216 291 if ( is_array( $glob ) ) {
217 292 $count = 0;
218 293 foreach( $glob as $path ) {
219 294 $file = basename( $path );
220 - if ( preg_match( '`^(\d{10}\.\d+)\.(.+?)\.(?:slugs)\.profile$`', $file, $match ) ) {
295 + if ( preg_match('`^(\d{10}\.\d+)\.(.+?)\.(?:slugs)\.profile$`', $file, $match ) ) {
221 296
222 297 $error = 0; $fsize = 0;
223 298 // Make sure we have all profile files
224 299 foreach( $this->default_files as $pname ) {
225 - // Ignore these ones, there aren't mandatory
226 - if ( in_array( $pname, [ 'composer', 'summary' ] ) ) { continue; }
227 - if ( file_exists( CODE_PROFILER_UPLOAD_DIR ."/{$match[1]}.{$match[2]}.$pname.profile" ) ) {
300 + /**
301 + * Ignore these ones, there aren't mandatory.
302 + */
303 + if ( in_array( $pname, $this->optional_files ) ) {
304 + continue;
305 + }
306 + if ( is_file( CODE_PROFILER_UPLOAD_DIR ."/{$match[1]}.{$match[2]}.$pname.profile" ) ) {
228 307 $fsize += filesize( CODE_PROFILER_UPLOAD_DIR ."/{$match[1]}.{$match[2]}.$pname.profile" );
229 308 } else {
230 309 $error = 1;
231 310 break;
@@ -233,9 +312,9 @@
233 312 }
234 313 // Delete if incomplete
235 314 if ( $error ) {
236 315 foreach( $this->default_files as $pname ) {
237 - if ( file_exists( CODE_PROFILER_UPLOAD_DIR ."/{$match[1]}.{$match[2]}.$pname.profile" ) ) {
316 + if ( is_file( CODE_PROFILER_UPLOAD_DIR ."/{$match[1]}.{$match[2]}.$pname.profile" ) ) {
238 317 unlink( CODE_PROFILER_UPLOAD_DIR ."/{$match[1]}.{$match[2]}.$pname.profile" );
239 318 }
240 319 }
241 320 continue;
@@ -244,10 +323,14 @@
244 323 // Search query
245 324 $search = false;
246 325 if (! empty( $_REQUEST['s'] ) ) {
247 326 foreach( $this->default_files as $pname ) {
248 - // Ignore these ones, there aren't mandatory
249 - if ( in_array( $pname, [ 'composer', 'summary' ] ) ) { continue; }
327 + /**
328 + * Ignore these ones, there aren't mandatory.
329 + */
330 + if ( in_array( $pname, $this->optional_files ) ) {
331 + continue;
332 + }
250 333 $search = $this->search_profile_file(
251 334 CODE_PROFILER_UPLOAD_DIR ."/{$match[1]}.{$match[2]}.$pname.profile",
252 335 sanitize_text_field( $_REQUEST['s'] )
253 336 );
@@ -271,8 +354,14 @@
271 354 if ( empty( $summary['time'] ) ) { $summary['time'] = '-'; }
272 355 if ( empty( $summary['items'] ) ) { $summary['items'] = '-'; }
273 356 if ( empty( $summary['io'] ) ) { $summary['io'] = '-'; }
274 357
358 + /**
359 + * Check if we can re-run the profile (v1.8+).
360 + */
361 + if (! empty( $summary['rerun'] ) ) {
362 + $profiles[$count]['rerun'] = true;
363 + }
275 364 $fsize += filesize( $path );
276 365 $profiles[$count]['ID'] = $match[1];
277 366 $profiles[$count]['profile'] = esc_html( $match[2] );
278 367 $profiles[$count]['date'] = filemtime( $path );
@@ -288,10 +377,9 @@
288 377 return $profiles;
289 378 }
290 379
291 380
292 -
293 - /*
381 + /**
294 382 * Search a profile file for a string.
295 383 */
296 384 private function search_profile_file( $file, $string ) {
297 385
@@ -299,9 +387,9 @@
299 387 if ( stripos( $file, $string ) !== false ) {
300 388 return true;
301 389 }
302 390
303 - $fh = fopen( $file, 'rb' );
391 + $fh = fopen( $file, 'rb');
304 392 if ( $fh === false ) {
305 393 return false;
306 394 }
307 395 while(! feof( $fh ) ) {
@@ -306,9 +394,9 @@
306 394 }
307 395 while(! feof( $fh ) ) {
308 396 $line = fgets( $fh );
309 397 // Remove the ABSPATH, we don't include it in the search
310 - $line = ltrim( str_replace( $this->abspath, '', $line ), '\\/' );
398 + $line = ltrim( str_replace( $this->abspath, '', $line ), '\\/');
311 399 if ( stripos( $line, $string ) !== false ) {
312 400 fclose( $fh );
313 401 return true;
314 402 }
@@ -318,9 +406,9 @@
318 406 return false;
319 407 }
320 408
321 409
322 - /*
410 + /**
323 411 * Delete one or more profiles.
324 412 */
325 413 public function delete_profiles( $profiles ) {
326 414
@@ -331,10 +419,10 @@
331 419 $error = true;
332 420 continue;
333 421 }
334 422 foreach( $this->default_files as $pname ) {
335 - if ( file_exists( "$profile_name.$pname.profile" ) ) {
336 - unlink( "$profile_name.$pname.profile" );
423 + if ( is_file( "$profile_name.$pname.profile") ) {
424 + unlink( "$profile_name.$pname.profile");
337 425 }
338 426 }
339 427 }
340 428 return $error;