PluginProbe
Autoptimize / trunk
Autoptimize vtrunk
3.1.16 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 All 108 releases
← All changes | classes/autoptimizeCriticalCSSSettingsAjax.php +287 -42 2.7.6 → trunk View file →
@@ -7,16 +7,17 @@
7 7 exit;
8 8 }
9 9
10 10 class autoptimizeCriticalCSSSettingsAjax {
11 - public function __construct()
12 - {
13 - // fetch all options at once and populate them individually explicitely as globals.
14 - $all_options = autoptimizeCriticalCSSBase::fetch_options();
15 - foreach ( $all_options as $_option => $_value ) {
16 - global ${$_option};
17 - ${$_option} = $_value;
18 - }
11 + /**
12 + * Critical CSS object.
13 + *
14 + * @var object
15 + */
16 + protected $criticalcss;
17 +
18 + public function __construct() {
19 + $this->criticalcss = autoptimize()->criticalcss();
19 20 $this->run();
20 21 }
21 22
22 23 public function run() {
@@ -26,8 +27,10 @@
26 27 add_action( 'wp_ajax_rm_critcss', array( $this, 'critcss_rm_callback' ) );
27 28 add_action( 'wp_ajax_rm_critcss_all', array( $this, 'critcss_rm_all_callback' ) );
28 29 add_action( 'wp_ajax_ao_ccss_export', array( $this, 'ao_ccss_export_callback' ) );
29 30 add_action( 'wp_ajax_ao_ccss_import', array( $this, 'ao_ccss_import_callback' ) );
31 + add_action( 'wp_ajax_ao_ccss_queuerunner', array( $this, 'ao_ccss_queuerunner_callback' ) );
32 + add_action( 'wp_ajax_ao_ccss_saverules', array( $this, 'ao_ccss_saverules_callback' ) );
30 33 }
31 34
32 35 public function critcss_fetch_callback() {
33 36 // Ajax handler to obtain a critical CSS file from the filesystem.
@@ -43,9 +46,9 @@
43 46 $error = false;
44 47 } elseif ( current_user_can( 'manage_options' ) && $this->critcss_check_filename( $_POST['critcssfile'] ) ) {
45 48 // Or check user permissios and filename.
46 49 // Set file path and obtain its content.
47 - $critcssfile = AO_CCSS_DIR . strip_tags( $_POST['critcssfile'] );
50 + $critcssfile = AO_CCSS_DIR . $_POST['critcssfile'];
48 51 if ( file_exists( $critcssfile ) ) {
49 52 $content = file_get_contents( $critcssfile );
50 53 $error = false;
51 54 }
@@ -85,19 +88,21 @@
85 88 // Set critical CSS content.
86 89 $critcsscontents = stripslashes( $_POST['critcsscontents'] );
87 90
88 91 // If there is content and it's valid, write the file.
89 - if ( $critcsscontents && autoptimizeCriticalCSSCore::ao_ccss_check_contents( $critcsscontents ) ) {
92 + if ( $critcsscontents && $this->criticalcss->check_contents( $critcsscontents ) ) {
90 93 // Set file path and status.
91 - $critcssfile = AO_CCSS_DIR . strip_tags( $_POST['critcssfile'] );
94 + $critcssfile = AO_CCSS_DIR . $_POST['critcssfile'];
92 95 $status = file_put_contents( $critcssfile, $critcsscontents, LOCK_EX );
93 96 // Or set as error.
94 97 } else {
95 - $error = true;
98 + $error = true;
99 + $critcssfile = 'CCSS content not acceptable.';
96 100 }
97 101 // Or just set an error.
98 102 } else {
99 - $error = true;
103 + $error = true;
104 + $critcssfile = 'Not allowed or problem with CCSS filename.';
100 105 }
101 106
102 107 // Prepare response.
103 108 if ( ! $status || $error ) {
@@ -106,10 +111,17 @@
106 111 } else {
107 112 $response['code'] = '200';
108 113 if ( $critcssfile ) {
109 114 $response['string'] = 'File ' . $critcssfile . ' saved.';
115 +
116 + if ( true === apply_filters( 'autoptimize_filter_ccss_ajax_do_actions', true ) ) {
117 + $rule_identifiers = $this->fetch_rule_from_ccssfile( $critcssfile );
118 + if ( ! empty( $rule_identifiers ) && is_array( $rule_identifiers ) ) {
119 + do_action( 'autoptimize_action_ccss_ajax_css_changed', $rule_identifiers[0], $critcssfile, $rule_identifiers[1] );
120 + }
121 + }
110 122 } else {
111 - $response['string'] = 'Empty content do not need to be saved.';
123 + $response['string'] = 'Empty content does not need to be saved.';
112 124 }
113 125 }
114 126
115 127 // Dispatch respose.
@@ -118,9 +130,8 @@
118 130 // Close ajax request.
119 131 wp_die();
120 132 }
121 133
122 -
123 134 public function critcss_rm_callback() {
124 135 // Ajax handler to delete a critical CSS from the filesystem
125 136 // Check referer.
126 137 check_ajax_referer( 'rm_critcss_nonce', 'critcss_rm_nonce' );
@@ -134,9 +145,9 @@
134 145 $error = false;
135 146 } elseif ( current_user_can( 'manage_options' ) && $this->critcss_check_filename( $_POST['critcssfile'] ) ) {
136 147 // Or check user permissios and filename
137 148 // Set file path and delete it.
138 - $critcssfile = AO_CCSS_DIR . strip_tags( $_POST['critcssfile'] );
149 + $critcssfile = AO_CCSS_DIR . $_POST['critcssfile'];
139 150 if ( file_exists( $critcssfile ) ) {
140 151 $status = unlink( $critcssfile );
141 152 $error = false;
142 153 }
@@ -149,8 +160,15 @@
149 160 } else {
150 161 $response['code'] = '200';
151 162 if ( $status ) {
152 163 $response['string'] = 'File ' . $critcssfile . ' removed.';
164 +
165 + if ( true === apply_filters( 'autoptimize_filter_ccss_ajax_do_actions', true ) ) {
166 + $rule_identifiers = $this->fetch_rule_from_ccssfile( $critcssfile );
167 + if ( ! empty( $rule_identifiers ) && is_array( $rule_identifiers ) ) {
168 + do_action( 'autoptimize_action_ccss_ajax_css_removed', $rule_identifiers[0], $critcssfile, $rule_identifiers[1] );
169 + }
170 + }
153 171 } else {
154 172 $response['string'] = 'No file to be removed.';
155 173 }
156 174 }
@@ -176,8 +194,12 @@
176 194 if ( file_exists( AO_CCSS_DIR ) && is_dir( AO_CCSS_DIR ) ) {
177 195 array_map( 'unlink', glob( AO_CCSS_DIR . 'ccss_*.css', GLOB_BRACE ) );
178 196 $error = false;
179 197 $status = true;
198 +
199 + if ( true === apply_filters( 'autoptimize_filter_ccss_ajax_do_actions', true ) ) {
200 + do_action( 'autoptimize_action_ccss_ajax_all_css_removed' );
201 + }
180 202 }
181 203 }
182 204
183 205 // Prepare response.
@@ -212,18 +234,67 @@
212 234 wp_die();
213 235 }
214 236
215 237 // Init array, get options and prepare the raw object.
216 - $settings = array();
217 - $settings['rules'] = get_option( 'autoptimize_ccss_rules' );
218 - $settings['additional'] = get_option( 'autoptimize_ccss_additional' );
219 - $settings['viewport'] = get_option( 'autoptimize_ccss_viewport' );
220 - $settings['finclude'] = get_option( 'autoptimize_ccss_finclude' );
221 - $settings['rlimit'] = get_option( 'autoptimize_ccss_rlimit' );
222 - $settings['noptimize'] = get_option( 'autoptimize_ccss_noptimize' );
223 - $settings['debug'] = get_option( 'autoptimize_ccss_debug' );
224 - $settings['key'] = get_option( 'autoptimize_ccss_key' );
238 + $settings = array();
225 239
240 + // CCSS settings.
241 + $settings['ccss']['rules'] = get_option( 'autoptimize_ccss_rules' );
242 + $settings['ccss']['additional'] = get_option( 'autoptimize_ccss_additional' );
243 + $settings['ccss']['viewport'] = get_option( 'autoptimize_ccss_viewport' );
244 + $settings['ccss']['finclude'] = get_option( 'autoptimize_ccss_finclude' );
245 + $settings['ccss']['rtimelimit'] = get_option( 'autoptimize_ccss_rtimelimit' );
246 + $settings['ccss']['noptimize'] = get_option( 'autoptimize_ccss_noptimize' );
247 + $settings['ccss']['debug'] = get_option( 'autoptimize_ccss_debug' );
248 + $settings['ccss']['key'] = get_option( 'autoptimize_ccss_key' );
249 + $settings['ccss']['deferjquery'] = get_option( 'autoptimize_ccss_deferjquery' );
250 + $settings['ccss']['domain'] = get_option( 'autoptimize_ccss_domain' );
251 + $settings['ccss']['forcepath'] = get_option( 'autoptimize_ccss_forcepath' );
252 + $settings['ccss']['loggedin'] = get_option( 'autoptimize_ccss_loggedin' );
253 + $settings['ccss']['rlimit'] = get_option( 'autoptimize_ccss_rlimit' );
254 + $settings['ccss']['unloadccss'] = get_option( 'autoptimize_ccss_unloadccss' );
255 +
256 + // JS settings.
257 + $settings['js']['root'] = get_option( 'autoptimize_js' );
258 + $settings['js']['aggregate'] = get_option( 'autoptimize_js_aggregate' );
259 + $settings['js']['defer_not_aggregate'] = get_option( 'autoptimize_js_defer_not_aggregate' );
260 + $settings['js']['defer_inline'] = get_option( 'autoptimize_js_defer_inline' );
261 + $settings['js']['exclude'] = get_option( 'autoptimize_js_exclude' );
262 + $settings['js']['forcehead'] = get_option( 'autoptimize_js_forcehead' );
263 + $settings['js']['justhead'] = get_option( 'autoptimize_js_justhead' );
264 + $settings['js']['trycatch'] = get_option( 'autoptimize_js_trycatch' );
265 + $settings['js']['include_inline'] = get_option( 'autoptimize_js_include_inline' );
266 +
267 + // CSS settings.
268 + $settings['css']['root'] = get_option( 'autoptimize_css' );
269 + $settings['css']['aggregate'] = get_option( 'autoptimize_css_aggregate' );
270 + $settings['css']['datauris'] = get_option( 'autoptimize_css_datauris' );
271 + $settings['css']['justhead'] = get_option( 'autoptimize_css_justhead' );
272 + $settings['css']['defer'] = get_option( 'autoptimize_css_defer' );
273 + $settings['css']['defer_inline'] = get_option( 'autoptimize_css_defer_inline' );
274 + $settings['css']['inline'] = get_option( 'autoptimize_css_inline' );
275 + $settings['css']['exclude'] = get_option( 'autoptimize_css_exclude' );
276 + $settings['css']['include_inline'] = get_option( 'autoptimize_css_include_inline' );
277 +
278 + // Others.
279 + $settings['other']['autoptimize_imgopt_settings'] = get_option( 'autoptimize_imgopt_settings' );
280 + $settings['other']['autoptimize_extra_settings'] = get_option( 'autoptimize_extra_settings' );
281 + $settings['other']['autoptimize_cache_fallback'] = get_option( 'autoptimize_cache_fallback' );
282 + $settings['other']['autoptimize_cache_nogzip'] = get_option( 'autoptimize_cache_nogzip' );
283 + $settings['other']['autoptimize_cdn_url'] = get_option( 'autoptimize_cdn_url' );
284 + $settings['other']['autoptimize_enable_meta_ao_settings'] = get_option( 'autoptimize_enable_meta_ao_settings' );
285 + $settings['other']['autoptimize_enable_site_config'] = get_option( 'autoptimize_enable_site_config' );
286 + $settings['other']['autoptimize_html'] = get_option( 'autoptimize_html' );
287 + $settings['other']['autoptimize_html_keepcomments'] = get_option( 'autoptimize_html_keepcomments' );
288 + $settings['other']['autoptimize_minify_excluded'] = get_option( 'autoptimize_minify_excluded' );
289 + $settings['other']['autoptimize_optimize_checkout'] = get_option( 'autoptimize_optimize_checkout' );
290 + $settings['other']['autoptimize_optimize_logged'] = get_option( 'autoptimize_optimize_logged' );
291 +
292 + if ( defined( 'AO_PRO_VERSION' ) ) {
293 + $settings['pro']['boosters'] = get_option( 'autoptimize_pro_boosters' );
294 + $settings['pro']['pagecache'] = get_option( 'autoptimize_pro_pagecache' );
295 + }
296 +
226 297 // Initialize error flag.
227 298 $error = true;
228 299
229 300 // Check user permissions.
@@ -235,9 +306,9 @@
235 306 $error = false;
236 307 }
237 308
238 309 // Prepare archive.
239 - $zipfile = AO_CCSS_DIR . date( 'Ymd-H\hi' ) . '_ao_ccss_settings.zip';
310 + $zipfile = AO_CCSS_DIR . str_replace( array( '.', '/' ), '_', parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) ) . '_' . date( 'Ymd-H\hi' ) . '_ao_ccss_settings.zip'; // @codingStandardsIgnoreLine
240 311 $file = pathinfo( $zipfile, PATHINFO_BASENAME );
241 312 $zip = new ZipArchive();
242 313 $ret = $zip->open( $zipfile, ZipArchive::CREATE );
243 314 if ( true !== $ret ) {
@@ -254,8 +325,13 @@
254 325 $zip->addGlob( AO_CCSS_DIR . '*.css', 0, $options );
255 326 $zip->close();
256 327 }
257 328
329 + // settings.json has been added to zipfile, so can be removed now.
330 + if ( file_exists( $exportfile ) ) {
331 + unlink( $exportfile );
332 + }
333 +
258 334 // Prepare response.
259 335 if ( ! $status || $error ) {
260 336 $response['code'] = '500';
261 337 $response['msg'] = 'Error saving file ' . $file . ', code: ' . $ret;
@@ -280,24 +356,38 @@
280 356 // Initialize error flag.
281 357 $error = false;
282 358
283 359 // Process an uploaded file with no errors.
284 - if ( ! $_FILES['file']['error'] ) {
285 - // Save file to the cache directory.
286 - $zipfile = AO_CCSS_DIR . $_FILES['file']['name'];
360 + if ( current_user_can( 'manage_options' ) && ! $_FILES['file']['error'] && $_FILES['file']['size'] < 500001 && strpos( $_FILES['file']['name'], '.zip' ) === strlen( $_FILES['file']['name'] ) - 4 ) {
361 + // create tmp dir with hard guess name in AO_CCSS_DIR.
362 + $_secret_dir = wp_hash( uniqid( md5( AUTOPTIMIZE_CACHE_URL ), true ) );
363 + $_import_tmp_dir = trailingslashit( AO_CCSS_DIR . $_secret_dir );
364 + mkdir( $_import_tmp_dir, 0774, true );
365 +
366 + // Save file to that tmp directory but give it our own name to prevent directory traversal risks when using original name.
367 + $zipfile = $_import_tmp_dir . uniqid( 'import_settings-', true ) . '.zip';
287 368 move_uploaded_file( $_FILES['file']['tmp_name'], $zipfile );
288 369
289 - // Extract archive.
370 + // Extract archive in the tmp directory.
290 371 $zip = new ZipArchive;
291 372 if ( $zip->open( $zipfile ) === true ) {
292 - $zip->extractTo( AO_CCSS_DIR );
373 + // loop through all files in the zipfile.
374 + for ( $i = 0; $i < $zip->numFiles; $i++ ) { // @codingStandardsIgnoreLine
375 + // but only extract known good files.
376 + if ( preg_match( '/^settings\.json$|^\.\/ccss_[a-z0-9]{32}\.css$/', $zip->getNameIndex( $i ) ) > 0 ) {
377 + $zip->extractTo( AO_CCSS_DIR, $zip->getNameIndex( $i ) );
378 + }
379 + }
293 380 $zip->close();
294 381 } else {
295 - $error = 'extracting';
382 + $error = 'could not extract';
296 383 }
297 384
385 + // and remove temp. dir with all contents (the import-zipfile).
386 + $this->rrmdir( $_import_tmp_dir );
387 +
298 388 if ( ! $error ) {
299 - // Archive extraction ok, continue settings importing
389 + // Archive extraction ok, continue importing settings from AO_CCSS_DIR.
300 390 // Settings file.
301 391 $importfile = AO_CCSS_DIR . 'settings.json';
302 392
303 393 if ( file_exists( $importfile ) ) {
@@ -303,22 +393,66 @@
303 393 if ( file_exists( $importfile ) ) {
304 394 // Get settings and turn them into an object.
305 395 $settings = json_decode( file_get_contents( $importfile ), true );
306 396
307 - // Update options.
308 - update_option( 'autoptimize_ccss_rules', $settings['rules'] );
309 - update_option( 'autoptimize_ccss_additional', $settings['additional'] );
310 - update_option( 'autoptimize_ccss_viewport', $settings['viewport'] );
311 - update_option( 'autoptimize_ccss_finclude', $settings['finclude'] );
312 - update_option( 'autoptimize_ccss_rlimit', $settings['rlimit'] );
313 - update_option( 'autoptimize_ccss_noptimize', $settings['noptimize'] );
314 - update_option( 'autoptimize_ccss_debug', $settings['debug'] );
315 - update_option( 'autoptimize_ccss_key', $settings['key'] );
397 + // Update options from settings, but only for known options.
398 + // CCSS.
399 + foreach ( array( 'rules', 'additional', 'viewport', 'finclude', 'rtimelimit', 'noptimize', 'debug', 'key', 'deferjquery', 'domain', 'forcepath', 'loggedin', 'rlimit', 'unloadccss' ) as $ccss_setting ) {
400 + if ( false === array_key_exists( 'ccss', $settings ) || false === array_key_exists( $ccss_setting, $settings['ccss'] ) ) {
401 + continue;
402 + } else {
403 + update_option( 'autoptimize_ccss_' . $ccss_setting, autoptimizeUtils::strip_tags_array( $settings['ccss'][ $ccss_setting ] ) );
404 + }
405 + }
406 +
407 + // JS.
408 + foreach ( array( 'root', 'aggregate', 'defer_not_aggregate', 'defer_inline', 'exclude', 'forcehead', 'trycatch', 'include_inline' ) as $js_setting ) {
409 + if ( false === array_key_exists( 'js', $settings ) || false === array_key_exists( $js_setting, $settings['js'] ) ) {
410 + continue;
411 + } else if ( 'root' === $js_setting ) {
412 + update_option( 'autoptimize_js', $settings['js']['root'] );
413 + } else {
414 + update_option( 'autoptimize_js_' . $js_setting, $settings['js'][ $js_setting ] );
415 + }
416 + }
417 +
418 + // CSS.
419 + foreach ( array( 'root', 'aggregate', 'datauris', 'justhead', 'defer', 'defer_inline', 'inline', 'exclude', 'include_inline' ) as $css_setting ) {
420 + if ( false === array_key_exists( 'css', $settings ) || false === array_key_exists( $css_setting, $settings['css'] ) ) {
421 + continue;
422 + } else if ( 'root' === $css_setting ) {
423 + update_option( 'autoptimize_css', $settings['css']['root'] );
424 + } else {
425 + update_option( 'autoptimize_css_' . $css_setting, $settings['css'][ $css_setting ] );
426 + }
427 + }
428 +
429 + // Other.
430 + foreach ( array( 'autoptimize_imgopt_settings', 'autoptimize_extra_settings', 'autoptimize_cache_fallback', 'autoptimize_cache_nogzip', 'autoptimize_cdn_url', 'autoptimize_enable_meta_ao_settings', 'autoptimize_enable_site_config', 'autoptimize_html', 'autoptimize_html_keepcomments', 'autoptimize_minify_excluded', 'autoptimize_optimize_checkout', 'autoptimize_optimize_logged' ) as $other_setting ) {
431 + if ( false === array_key_exists( 'other', $settings ) || false === array_key_exists( $other_setting, $settings['other'] ) ) {
432 + continue;
433 + } else {
434 + update_option( $other_setting, $settings['other'][ $other_setting ] );
435 + }
436 + }
437 +
438 + // AO Pro.
439 + if ( defined( 'AO_PRO_VERSION' ) && array_key_exists( 'pro', $settings ) ) {
440 + update_option( 'autoptimize_pro_boosters', $settings['pro']['boosters'] );
441 + update_option( 'autoptimize_pro_pagecache', $settings['pro']['pagecache'] );
442 + }
443 +
444 + // settings.json has been imported, so can be removed now.
445 + if ( file_exists( $importfile ) ) {
446 + unlink( $importfile );
447 + }
316 448 } else {
317 449 // Settings file doesn't exist, update error flag.
318 450 $error = 'settings file does not exist';
319 451 }
320 452 }
453 + } else {
454 + $error = 'file could not be saved';
321 455 }
322 456
323 457 // Prepare response.
324 458 if ( $error ) {
@@ -335,8 +469,84 @@
335 469 // Close ajax request.
336 470 wp_die();
337 471 }
338 472
473 + public function ao_ccss_queuerunner_callback() {
474 + check_ajax_referer( 'ao_ccss_queuerunner_nonce', 'ao_ccss_queuerunner_nonce' );
475 +
476 + // Process an uploaded file with no errors.
477 + if ( current_user_can( 'manage_options' ) ) {
478 + if ( ! file_exists( AO_CCSS_LOCK ) ) {
479 + $ccss_cron = new autoptimizeCriticalCSSCron();
480 + $ccss_cron->ao_ccss_queue_control();
481 + $response['code'] = '200';
482 + $response['msg'] = 'Queue processing done';
483 + } else {
484 + $response['code'] = '302';
485 + $response['msg'] = 'Lock file found';
486 + }
487 + } else {
488 + $response['code'] = '500';
489 + $response['msg'] = 'Not allowed';
490 + }
491 +
492 + // Dispatch respose.
493 + echo json_encode( $response );
494 +
495 + // Close ajax request.
496 + wp_die();
497 + }
498 +
499 + public function ao_ccss_saverules_callback() {
500 + check_ajax_referer( 'ao_ccss_saverules_nonce', 'ao_ccss_saverules_nonce' );
501 +
502 + // save rules over AJAX, too many users forget to press "save changes".
503 + if ( current_user_can( 'manage_options' ) ) {
504 + if ( array_key_exists( 'critcssrules', $_POST ) ) {
505 + $rules = stripslashes( $_POST['critcssrules'] ); // ugly, but seems correct as per https://developer.wordpress.org/reference/functions/stripslashes_deep/#comment-1045 .
506 + if ( ! empty( $rules ) ) {
507 + $_unsafe_rules_array = json_decode( wp_strip_all_tags( $rules ), true );
508 + if ( ! empty( $_unsafe_rules_array ) && is_array( $_unsafe_rules_array ) ) {
509 + $_safe_rules_array = array();
510 + if ( array_key_exists( 'paths', $_unsafe_rules_array ) ) {
511 + $_safe_rules_array['paths'] = $_unsafe_rules_array['paths'];
512 + }
513 + if ( array_key_exists( 'types', $_unsafe_rules_array ) ) {
514 + $_safe_rules_array['types'] = $_unsafe_rules_array['types'];
515 + }
516 + $_safe_rules = json_encode( $_safe_rules_array, JSON_FORCE_OBJECT );
517 + if ( ! empty( $_safe_rules ) ) {
518 + update_option( 'autoptimize_ccss_rules', $_safe_rules );
519 + $response['code'] = '200';
520 + $response['msg'] = 'Rules saved';
521 + } else {
522 + $_error = 'Could not auto-save rules (safe rules empty)';
523 + }
524 + } else {
525 + $_error = 'Could not auto-save rules (rules could not be json_decoded)';
526 + }
527 + } else {
528 + $_error = 'Could not auto-save rules (rules empty)';
529 + }
530 + } else {
531 + $_error = 'Could not auto-save rules (rules not in $_POST)';
532 + }
533 + } else {
534 + $_error = 'Not allowed';
535 + }
536 +
537 + if ( ! isset( $response ) && $_error ) {
538 + $response['code'] = '500';
539 + $response['msg'] = $_error;
540 + }
541 +
542 + // Dispatch respose.
543 + echo json_encode( $response );
544 +
545 + // Close ajax request.
546 + wp_die();
547 + }
548 +
339 549 public function critcss_check_filename( $filename ) {
340 550 // Try to avoid directory traversal when reading/writing/deleting critical CSS files.
341 551 if ( strpos( $filename, 'ccss_' ) !== 0 ) {
342 552 return false;
@@ -347,6 +557,41 @@
347 557 return false;
348 558 } else {
349 559 return true;
350 560 }
561 + }
562 +
563 + public function rrmdir( $path ) {
564 + // recursively remove a directory as found on
565 + // https://andy-carter.com/blog/recursively-remove-a-directory-in-php.
566 + $files = glob( $path . '/*' );
567 + foreach ( $files as $file ) {
568 + is_dir( $file ) ? $this->rrmdir( $file ) : unlink( $file );
569 + }
570 + rmdir( $path );
571 +
572 + return;
573 + }
574 +
575 + public function fetch_rule_from_ccssfile( $ccss_file = '' ) {
576 + if ( empty( $ccss_file ) ) {
577 + return false;
578 + }
579 +
580 + $ccss_file = str_replace( AO_CCSS_DIR, '', $ccss_file );
581 +
582 + static $rules = null;
583 + if ( null === $rules ) {
584 + $rules = $this->criticalcss->get_option( 'rules' );
585 + }
586 +
587 + foreach ( $rules as $ruletype => $rulechilds ) {
588 + foreach ( $rulechilds as $identifier => $properties ) {
589 + if ( $properties['file'] === $ccss_file ) {
590 + return array( $ruletype, $identifier );
591 + }
592 + }
593 + }
594 +
595 + return false;
351 596 }
352 597 }