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