PluginProbe
Autoptimize / 3.1.11
Autoptimize v3.1.11
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 2.7.8 All 107 releases
autoptimize / classes / autoptimizeCriticalCSSSettingsAjax.php

autoptimizeCriticalCSSSettingsAjax.php in Autoptimize 3.1.11, at classes/autoptimizeCriticalCSSSettingsAjax.php

598 lines 26.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Critical CSS settings AJAX logic.
4 */
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit;
8 }
9
10 class autoptimizeCriticalCSSSettingsAjax {
11 /**
12 * Critical CSS object.
13 *
14 * @var object
15 */
16 protected $criticalcss;
17
18 public function __construct() {
19 $this->criticalcss = autoptimize()->criticalcss();
20 $this->run();
21 }
22
23 public function run() {
24 // add filters.
25 add_action( 'wp_ajax_fetch_critcss', array( $this, 'critcss_fetch_callback' ) );
26 add_action( 'wp_ajax_save_critcss', array( $this, 'critcss_save_callback' ) );
27 add_action( 'wp_ajax_rm_critcss', array( $this, 'critcss_rm_callback' ) );
28 add_action( 'wp_ajax_rm_critcss_all', array( $this, 'critcss_rm_all_callback' ) );
29 add_action( 'wp_ajax_ao_ccss_export', array( $this, 'ao_ccss_export_callback' ) );
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' ) );
33 }
34
35 public function critcss_fetch_callback() {
36 // Ajax handler to obtain a critical CSS file from the filesystem.
37 // Check referer.
38 check_ajax_referer( 'fetch_critcss_nonce', 'critcss_fetch_nonce' );
39
40 // Initialize error flag.
41 $error = true;
42
43 // Allow no content for MANUAL rules (as they may not exist just yet).
44 if ( current_user_can( 'manage_options' ) && empty( $_POST['critcssfile'] ) ) {
45 $content = '';
46 $error = false;
47 } elseif ( current_user_can( 'manage_options' ) && $this->critcss_check_filename( $_POST['critcssfile'] ) ) {
48 // Or check user permissios and filename.
49 // Set file path and obtain its content.
50 $critcssfile = AO_CCSS_DIR . strip_tags( $_POST['critcssfile'] );
51 if ( file_exists( $critcssfile ) ) {
52 $content = file_get_contents( $critcssfile );
53 $error = false;
54 }
55 }
56
57 // Prepare response.
58 if ( $error ) {
59 $response['code'] = '500';
60 $response['string'] = 'Error reading file ' . $critcssfile . '.';
61 } else {
62 $response['code'] = '200';
63 $response['string'] = $content;
64 }
65
66 // Dispatch respose.
67 echo json_encode( $response );
68
69 // Close ajax request.
70 wp_die();
71 }
72
73 public function critcss_save_callback() {
74 $error = false;
75 $status = false;
76 $response = array();
77
78 // Ajax handler to write a critical CSS to the filesystem
79 // Check referer.
80 check_ajax_referer( 'save_critcss_nonce', 'critcss_save_nonce' );
81
82 // Allow empty contents for MANUAL rules (as they are fetched later).
83 if ( current_user_can( 'manage_options' ) && empty( $_POST['critcssfile'] ) ) {
84 $critcssfile = false;
85 $status = true;
86 } elseif ( current_user_can( 'manage_options' ) && $this->critcss_check_filename( $_POST['critcssfile'] ) ) {
87 // Or check user permissios and filename
88 // Set critical CSS content.
89 $critcsscontents = stripslashes( $_POST['critcsscontents'] );
90
91 // If there is content and it's valid, write the file.
92 if ( $critcsscontents && $this->criticalcss->check_contents( $critcsscontents ) ) {
93 // Set file path and status.
94 $critcssfile = AO_CCSS_DIR . strip_tags( $_POST['critcssfile'] );
95 $status = file_put_contents( $critcssfile, $critcsscontents, LOCK_EX );
96 // Or set as error.
97 } else {
98 $error = true;
99 $critcssfile = 'CCSS content not acceptable.';
100 }
101 // Or just set an error.
102 } else {
103 $error = true;
104 $critcssfile = 'Not allowed or problem with CCSS filename.';
105 }
106
107 // Prepare response.
108 if ( ! $status || $error ) {
109 $response['code'] = '500';
110 $response['string'] = 'Error saving file ' . $critcssfile . '.';
111 } else {
112 $response['code'] = '200';
113 if ( $critcssfile ) {
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 }
122 } else {
123 $response['string'] = 'Empty content does not need to be saved.';
124 }
125 }
126
127 // Dispatch respose.
128 echo json_encode( $response );
129
130 // Close ajax request.
131 wp_die();
132 }
133
134 public function critcss_rm_callback() {
135 // Ajax handler to delete a critical CSS from the filesystem
136 // Check referer.
137 check_ajax_referer( 'rm_critcss_nonce', 'critcss_rm_nonce' );
138
139 // Initialize error and status flags.
140 $error = true;
141 $status = false;
142
143 // Allow no file for MANUAL rules (as they may not exist just yet).
144 if ( current_user_can( 'manage_options' ) && empty( $_POST['critcssfile'] ) ) {
145 $error = false;
146 } elseif ( current_user_can( 'manage_options' ) && $this->critcss_check_filename( $_POST['critcssfile'] ) ) {
147 // Or check user permissios and filename
148 // Set file path and delete it.
149 $critcssfile = AO_CCSS_DIR . strip_tags( $_POST['critcssfile'] );
150 if ( file_exists( $critcssfile ) ) {
151 $status = unlink( $critcssfile );
152 $error = false;
153 }
154 }
155
156 // Prepare response.
157 if ( $error ) {
158 $response['code'] = '500';
159 $response['string'] = 'Error removing file ' . $critcssfile . '.';
160 } else {
161 $response['code'] = '200';
162 if ( $status ) {
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 }
171 } else {
172 $response['string'] = 'No file to be removed.';
173 }
174 }
175
176 // Dispatch respose.
177 echo json_encode( $response );
178
179 // Close ajax request.
180 wp_die();
181 }
182
183 public function critcss_rm_all_callback() {
184 // Ajax handler to delete a critical CSS from the filesystem
185 // Check referer.
186 check_ajax_referer( 'rm_critcss_all_nonce', 'critcss_rm_all_nonce' );
187
188 // Initialize error and status flags.
189 $error = true;
190 $status = false;
191
192 // Remove all ccss files on filesystem.
193 if ( current_user_can( 'manage_options' ) ) {
194 if ( file_exists( AO_CCSS_DIR ) && is_dir( AO_CCSS_DIR ) ) {
195 array_map( 'unlink', glob( AO_CCSS_DIR . 'ccss_*.css', GLOB_BRACE ) );
196 $error = false;
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 }
202 }
203 }
204
205 // Prepare response.
206 if ( $error ) {
207 $response['code'] = '500';
208 $response['string'] = 'Error removing all critical CSS files.';
209 } else {
210 $response['code'] = '200';
211 if ( $status ) {
212 $response['string'] = 'Critical CSS Files removed.';
213 } else {
214 $response['string'] = 'No file removed.';
215 }
216 }
217
218 // Dispatch respose.
219 echo json_encode( $response );
220
221 // Close ajax request.
222 wp_die();
223 }
224
225 public function ao_ccss_export_callback() {
226 // Ajax handler export settings
227 // Check referer.
228 check_ajax_referer( 'ao_ccss_export_nonce', 'ao_ccss_export_nonce' );
229
230 if ( ! class_exists( 'ZipArchive' ) ) {
231 $response['code'] = '500';
232 $response['msg'] = 'PHP ZipArchive not present, cannot create zipfile';
233 echo json_encode( $response );
234 wp_die();
235 }
236
237 // Init array, get options and prepare the raw object.
238 $settings = array();
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
297 // Initialize error flag.
298 $error = true;
299
300 // Check user permissions.
301 if ( current_user_can( 'manage_options' ) ) {
302 // Prepare settings file path and content.
303 $exportfile = AO_CCSS_DIR . 'settings.json';
304 $contents = json_encode( $settings );
305 $status = file_put_contents( $exportfile, $contents, LOCK_EX );
306 $error = false;
307 }
308
309 // Prepare archive.
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
311 $file = pathinfo( $zipfile, PATHINFO_BASENAME );
312 $zip = new ZipArchive();
313 $ret = $zip->open( $zipfile, ZipArchive::CREATE );
314 if ( true !== $ret ) {
315 $error = true;
316 } else {
317 $zip->addFile( AO_CCSS_DIR . 'settings.json', 'settings.json' );
318 if ( file_exists( AO_CCSS_DIR . 'queue.json' ) ) {
319 $zip->addFile( AO_CCSS_DIR . 'queue.json', 'queue.json' );
320 }
321 $options = array(
322 'add_path' => './',
323 'remove_all_path' => true,
324 );
325 $zip->addGlob( AO_CCSS_DIR . '*.css', 0, $options );
326 $zip->close();
327 }
328
329 // settings.json has been added to zipfile, so can be removed now.
330 if ( file_exists( $exportfile ) ) {
331 unlink( $exportfile );
332 }
333
334 // Prepare response.
335 if ( ! $status || $error ) {
336 $response['code'] = '500';
337 $response['msg'] = 'Error saving file ' . $file . ', code: ' . $ret;
338 } else {
339 $response['code'] = '200';
340 $response['msg'] = 'File ' . $file . ' saved.';
341 $response['file'] = $file;
342 }
343
344 // Dispatch respose.
345 echo json_encode( $response );
346
347 // Close ajax request.
348 wp_die();
349 }
350
351 public function ao_ccss_import_callback() {
352 // Ajax handler import settings
353 // Check referer.
354 check_ajax_referer( 'ao_ccss_import_nonce', 'ao_ccss_import_nonce' );
355
356 // Initialize error flag.
357 $error = false;
358
359 // Process an uploaded file with no errors.
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';
368 move_uploaded_file( $_FILES['file']['tmp_name'], $zipfile );
369
370 // Extract archive in the tmp directory.
371 $zip = new ZipArchive;
372 if ( $zip->open( $zipfile ) === true ) {
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 }
380 $zip->close();
381 } else {
382 $error = 'could not extract';
383 }
384
385 // and remove temp. dir with all contents (the import-zipfile).
386 $this->rrmdir( $_import_tmp_dir );
387
388 if ( ! $error ) {
389 // Archive extraction ok, continue importing settings from AO_CCSS_DIR.
390 // Settings file.
391 $importfile = AO_CCSS_DIR . 'settings.json';
392
393 if ( file_exists( $importfile ) ) {
394 // Get settings and turn them into an object.
395 $settings = json_decode( file_get_contents( $importfile ), true );
396
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 }
448 } else {
449 // Settings file doesn't exist, update error flag.
450 $error = 'settings file does not exist';
451 }
452 }
453 } else {
454 $error = 'file could not be saved';
455 }
456
457 // Prepare response.
458 if ( $error ) {
459 $response['code'] = '500';
460 $response['msg'] = 'Error importing settings: ' . $error;
461 } else {
462 $response['code'] = '200';
463 $response['msg'] = 'Settings imported successfully';
464 }
465
466 // Dispatch respose.
467 echo json_encode( $response );
468
469 // Close ajax request.
470 wp_die();
471 }
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
549 public function critcss_check_filename( $filename ) {
550 // Try to avoid directory traversal when reading/writing/deleting critical CSS files.
551 if ( strpos( $filename, 'ccss_' ) !== 0 ) {
552 return false;
553 } elseif ( substr( $filename, -4, 4 ) !== '.css' ) {
554 return false;
555 } elseif ( sanitize_file_name( $filename ) !== $filename ) {
556 // Use WordPress core's sanitize_file_name to see if anything fishy is going on.
557 return false;
558 } else {
559 return true;
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;
596 }
597 }
598