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