PluginProbe
Autoptimize / 3.1.7
Autoptimize v3.1.7
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.7, at classes/autoptimizeCriticalCSSSettingsAjax.php

557 lines 24.7 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 } else {
116 $response['string'] = 'Empty content does not need to be saved.';
117 }
118 }
119
120 // Dispatch respose.
121 echo json_encode( $response );
122
123 // Close ajax request.
124 wp_die();
125 }
126
127 public function critcss_rm_callback() {
128 // Ajax handler to delete a critical CSS from the filesystem
129 // Check referer.
130 check_ajax_referer( 'rm_critcss_nonce', 'critcss_rm_nonce' );
131
132 // Initialize error and status flags.
133 $error = true;
134 $status = false;
135
136 // Allow no file for MANUAL rules (as they may not exist just yet).
137 if ( current_user_can( 'manage_options' ) && empty( $_POST['critcssfile'] ) ) {
138 $error = false;
139 } elseif ( current_user_can( 'manage_options' ) && $this->critcss_check_filename( $_POST['critcssfile'] ) ) {
140 // Or check user permissios and filename
141 // Set file path and delete it.
142 $critcssfile = AO_CCSS_DIR . strip_tags( $_POST['critcssfile'] );
143 if ( file_exists( $critcssfile ) ) {
144 $status = unlink( $critcssfile );
145 $error = false;
146 }
147 }
148
149 // Prepare response.
150 if ( $error ) {
151 $response['code'] = '500';
152 $response['string'] = 'Error removing file ' . $critcssfile . '.';
153 } else {
154 $response['code'] = '200';
155 if ( $status ) {
156 $response['string'] = 'File ' . $critcssfile . ' removed.';
157 } else {
158 $response['string'] = 'No file to be removed.';
159 }
160 }
161
162 // Dispatch respose.
163 echo json_encode( $response );
164
165 // Close ajax request.
166 wp_die();
167 }
168
169 public function critcss_rm_all_callback() {
170 // Ajax handler to delete a critical CSS from the filesystem
171 // Check referer.
172 check_ajax_referer( 'rm_critcss_all_nonce', 'critcss_rm_all_nonce' );
173
174 // Initialize error and status flags.
175 $error = true;
176 $status = false;
177
178 // Remove all ccss files on filesystem.
179 if ( current_user_can( 'manage_options' ) ) {
180 if ( file_exists( AO_CCSS_DIR ) && is_dir( AO_CCSS_DIR ) ) {
181 array_map( 'unlink', glob( AO_CCSS_DIR . 'ccss_*.css', GLOB_BRACE ) );
182 $error = false;
183 $status = true;
184 }
185 }
186
187 // Prepare response.
188 if ( $error ) {
189 $response['code'] = '500';
190 $response['string'] = 'Error removing all critical CSS files.';
191 } else {
192 $response['code'] = '200';
193 if ( $status ) {
194 $response['string'] = 'Critical CSS Files removed.';
195 } else {
196 $response['string'] = 'No file removed.';
197 }
198 }
199
200 // Dispatch respose.
201 echo json_encode( $response );
202
203 // Close ajax request.
204 wp_die();
205 }
206
207 public function ao_ccss_export_callback() {
208 // Ajax handler export settings
209 // Check referer.
210 check_ajax_referer( 'ao_ccss_export_nonce', 'ao_ccss_export_nonce' );
211
212 if ( ! class_exists( 'ZipArchive' ) ) {
213 $response['code'] = '500';
214 $response['msg'] = 'PHP ZipArchive not present, cannot create zipfile';
215 echo json_encode( $response );
216 wp_die();
217 }
218
219 // Init array, get options and prepare the raw object.
220 $settings = array();
221
222 // CCSS settings.
223 $settings['ccss']['rules'] = get_option( 'autoptimize_ccss_rules' );
224 $settings['ccss']['additional'] = get_option( 'autoptimize_ccss_additional' );
225 $settings['ccss']['viewport'] = get_option( 'autoptimize_ccss_viewport' );
226 $settings['ccss']['finclude'] = get_option( 'autoptimize_ccss_finclude' );
227 $settings['ccss']['rtimelimit'] = get_option( 'autoptimize_ccss_rtimelimit' );
228 $settings['ccss']['noptimize'] = get_option( 'autoptimize_ccss_noptimize' );
229 $settings['ccss']['debug'] = get_option( 'autoptimize_ccss_debug' );
230 $settings['ccss']['key'] = get_option( 'autoptimize_ccss_key' );
231 $settings['ccss']['deferjquery'] = get_option( 'autoptimize_ccss_deferjquery' );
232 $settings['ccss']['domain'] = get_option( 'autoptimize_ccss_domain' );
233 $settings['ccss']['forcepath'] = get_option( 'autoptimize_ccss_forcepath' );
234 $settings['ccss']['loggedin'] = get_option( 'autoptimize_ccss_loggedin' );
235 $settings['ccss']['rlimit'] = get_option( 'autoptimize_ccss_rlimit' );
236 $settings['ccss']['unloadccss'] = get_option( 'autoptimize_ccss_unloadccss' );
237
238 // JS settings.
239 $settings['js']['root'] = get_option( 'autoptimize_js' );
240 $settings['js']['aggregate'] = get_option( 'autoptimize_js_aggregate' );
241 $settings['js']['defer_not_aggregate'] = get_option( 'autoptimize_js_defer_not_aggregate' );
242 $settings['js']['defer_inline'] = get_option( 'autoptimize_js_defer_inline' );
243 $settings['js']['exclude'] = get_option( 'autoptimize_js_exclude' );
244 $settings['js']['forcehead'] = get_option( 'autoptimize_js_forcehead' );
245 $settings['js']['justhead'] = get_option( 'autoptimize_js_justhead' );
246 $settings['js']['trycatch'] = get_option( 'autoptimize_js_trycatch' );
247 $settings['js']['include_inline'] = get_option( 'autoptimize_js_include_inline' );
248
249 // CSS settings.
250 $settings['css']['root'] = get_option( 'autoptimize_css' );
251 $settings['css']['aggregate'] = get_option( 'autoptimize_css_aggregate' );
252 $settings['css']['datauris'] = get_option( 'autoptimize_css_datauris' );
253 $settings['css']['justhead'] = get_option( 'autoptimize_css_justhead' );
254 $settings['css']['defer'] = get_option( 'autoptimize_css_defer' );
255 $settings['css']['defer_inline'] = get_option( 'autoptimize_css_defer_inline' );
256 $settings['css']['inline'] = get_option( 'autoptimize_css_inline' );
257 $settings['css']['exclude'] = get_option( 'autoptimize_css_exclude' );
258 $settings['css']['include_inline'] = get_option( 'autoptimize_css_include_inline' );
259
260 // Others.
261 $settings['other']['autoptimize_imgopt_settings'] = get_option( 'autoptimize_imgopt_settings' );
262 $settings['other']['autoptimize_extra_settings'] = get_option( 'autoptimize_extra_settings' );
263 $settings['other']['autoptimize_cache_fallback'] = get_option( 'autoptimize_cache_fallback' );
264 $settings['other']['autoptimize_cache_nogzip'] = get_option( 'autoptimize_cache_nogzip' );
265 $settings['other']['autoptimize_cdn_url'] = get_option( 'autoptimize_cdn_url' );
266 $settings['other']['autoptimize_enable_meta_ao_settings'] = get_option( 'autoptimize_enable_meta_ao_settings' );
267 $settings['other']['autoptimize_enable_site_config'] = get_option( 'autoptimize_enable_site_config' );
268 $settings['other']['autoptimize_html'] = get_option( 'autoptimize_html' );
269 $settings['other']['autoptimize_html_keepcomments'] = get_option( 'autoptimize_html_keepcomments' );
270 $settings['other']['autoptimize_minify_excluded'] = get_option( 'autoptimize_minify_excluded' );
271 $settings['other']['autoptimize_optimize_checkout'] = get_option( 'autoptimize_optimize_checkout' );
272 $settings['other']['autoptimize_optimize_logged'] = get_option( 'autoptimize_optimize_logged' );
273
274 if ( defined( 'AO_PRO_VERSION' ) ) {
275 $settings['pro']['boosters'] = get_option( 'autoptimize_pro_boosters' );
276 $settings['pro']['pagecache'] = get_option( 'autoptimize_pro_pagecache' );
277 }
278
279 // Initialize error flag.
280 $error = true;
281
282 // Check user permissions.
283 if ( current_user_can( 'manage_options' ) ) {
284 // Prepare settings file path and content.
285 $exportfile = AO_CCSS_DIR . 'settings.json';
286 $contents = json_encode( $settings );
287 $status = file_put_contents( $exportfile, $contents, LOCK_EX );
288 $error = false;
289 }
290
291 // Prepare archive.
292 $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
293 $file = pathinfo( $zipfile, PATHINFO_BASENAME );
294 $zip = new ZipArchive();
295 $ret = $zip->open( $zipfile, ZipArchive::CREATE );
296 if ( true !== $ret ) {
297 $error = true;
298 } else {
299 $zip->addFile( AO_CCSS_DIR . 'settings.json', 'settings.json' );
300 if ( file_exists( AO_CCSS_DIR . 'queue.json' ) ) {
301 $zip->addFile( AO_CCSS_DIR . 'queue.json', 'queue.json' );
302 }
303 $options = array(
304 'add_path' => './',
305 'remove_all_path' => true,
306 );
307 $zip->addGlob( AO_CCSS_DIR . '*.css', 0, $options );
308 $zip->close();
309 }
310
311 // settings.json has been added to zipfile, so can be removed now.
312 if ( file_exists( $exportfile ) ) {
313 unlink( $exportfile );
314 }
315
316 // Prepare response.
317 if ( ! $status || $error ) {
318 $response['code'] = '500';
319 $response['msg'] = 'Error saving file ' . $file . ', code: ' . $ret;
320 } else {
321 $response['code'] = '200';
322 $response['msg'] = 'File ' . $file . ' saved.';
323 $response['file'] = $file;
324 }
325
326 // Dispatch respose.
327 echo json_encode( $response );
328
329 // Close ajax request.
330 wp_die();
331 }
332
333 public function ao_ccss_import_callback() {
334 // Ajax handler import settings
335 // Check referer.
336 check_ajax_referer( 'ao_ccss_import_nonce', 'ao_ccss_import_nonce' );
337
338 // Initialize error flag.
339 $error = false;
340
341 // Process an uploaded file with no errors.
342 if ( current_user_can( 'manage_options' ) && ! $_FILES['file']['error'] && $_FILES['file']['size'] < 500001 && strpos( $_FILES['file']['name'], '.zip' ) === strlen( $_FILES['file']['name'] ) - 4 ) {
343 // create tmp dir with hard guess name in AO_CCSS_DIR.
344 $_secret_dir = wp_hash( uniqid( md5( AUTOPTIMIZE_CACHE_URL ), true ) );
345 $_import_tmp_dir = trailingslashit( AO_CCSS_DIR . $_secret_dir );
346 mkdir( $_import_tmp_dir, 0774, true );
347
348 // Save file to that tmp directory but give it our own name to prevent directory traversal risks when using original name.
349 $zipfile = $_import_tmp_dir . uniqid( 'import_settings-', true ) . '.zip';
350 move_uploaded_file( $_FILES['file']['tmp_name'], $zipfile );
351
352 // Extract archive in the tmp directory.
353 $zip = new ZipArchive;
354 if ( $zip->open( $zipfile ) === true ) {
355 // loop through all files in the zipfile.
356 for ( $i = 0; $i < $zip->numFiles; $i++ ) { // @codingStandardsIgnoreLine
357 // but only extract known good files.
358 if ( preg_match( '/^settings\.json$|^\.\/ccss_[a-z0-9]{32}\.css$/', $zip->getNameIndex( $i ) ) > 0 ) {
359 $zip->extractTo( AO_CCSS_DIR, $zip->getNameIndex( $i ) );
360 }
361 }
362 $zip->close();
363 } else {
364 $error = 'could not extract';
365 }
366
367 // and remove temp. dir with all contents (the import-zipfile).
368 $this->rrmdir( $_import_tmp_dir );
369
370 if ( ! $error ) {
371 // Archive extraction ok, continue importing settings from AO_CCSS_DIR.
372 // Settings file.
373 $importfile = AO_CCSS_DIR . 'settings.json';
374
375 if ( file_exists( $importfile ) ) {
376 // Get settings and turn them into an object.
377 $settings = json_decode( file_get_contents( $importfile ), true );
378
379 // Update options from settings, but only for known options.
380 // CCSS.
381 foreach ( array( 'rules', 'additional', 'viewport', 'finclude', 'rtimelimit', 'noptimize', 'debug', 'key', 'deferjquery', 'domain', 'forcepath', 'loggedin', 'rlimit', 'unloadccss' ) as $ccss_setting ) {
382 if ( false === array_key_exists( 'ccss', $settings ) || false === array_key_exists( $ccss_setting, $settings['ccss'] ) ) {
383 continue;
384 } else {
385 update_option( 'autoptimize_ccss_' . $ccss_setting, autoptimizeUtils::strip_tags_array( $settings['ccss'][ $ccss_setting ] ) );
386 }
387 }
388
389 // JS.
390 foreach ( array( 'root', 'aggregate', 'defer_not_aggregate', 'defer_inline', 'exclude', 'forcehead', 'trycatch', 'include_inline' ) as $js_setting ) {
391 if ( false === array_key_exists( 'js', $settings ) || false === array_key_exists( $js_setting, $settings['js'] ) ) {
392 continue;
393 } else if ( 'root' === $js_setting ) {
394 update_option( 'autoptimize_js', $settings['js']['root'] );
395 } else {
396 update_option( 'autoptimize_js_' . $js_setting, $settings['js'][ $js_setting ] );
397 }
398 }
399
400 // CSS.
401 foreach ( array( 'root', 'aggregate', 'datauris', 'justhead', 'defer', 'defer_inline', 'inline', 'exclude', 'include_inline' ) as $css_setting ) {
402 if ( false === array_key_exists( 'css', $settings ) || false === array_key_exists( $css_setting, $settings['css'] ) ) {
403 continue;
404 } else if ( 'root' === $css_setting ) {
405 update_option( 'autoptimize_css', $settings['css']['root'] );
406 } else {
407 update_option( 'autoptimize_css_' . $css_setting, $settings['css'][ $css_setting ] );
408 }
409 }
410
411 // Other.
412 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 ) {
413 if ( false === array_key_exists( 'other', $settings ) || false === array_key_exists( $other_setting, $settings['other'] ) ) {
414 continue;
415 } else {
416 update_option( $other_setting, $settings['other'][ $other_setting ] );
417 }
418 }
419
420 // AO Pro.
421 if ( defined( 'AO_PRO_VERSION' ) && array_key_exists( 'pro', $settings ) ) {
422 update_option( 'autoptimize_pro_boosters', $settings['pro']['boosters'] );
423 update_option( 'autoptimize_pro_pagecache', $settings['pro']['pagecache'] );
424 }
425
426 // settings.json has been imported, so can be removed now.
427 if ( file_exists( $importfile ) ) {
428 unlink( $importfile );
429 }
430 } else {
431 // Settings file doesn't exist, update error flag.
432 $error = 'settings file does not exist';
433 }
434 }
435 } else {
436 $error = 'file could not be saved';
437 }
438
439 // Prepare response.
440 if ( $error ) {
441 $response['code'] = '500';
442 $response['msg'] = 'Error importing settings: ' . $error;
443 } else {
444 $response['code'] = '200';
445 $response['msg'] = 'Settings imported successfully';
446 }
447
448 // Dispatch respose.
449 echo json_encode( $response );
450
451 // Close ajax request.
452 wp_die();
453 }
454
455 public function ao_ccss_queuerunner_callback() {
456 check_ajax_referer( 'ao_ccss_queuerunner_nonce', 'ao_ccss_queuerunner_nonce' );
457
458 // Process an uploaded file with no errors.
459 if ( current_user_can( 'manage_options' ) ) {
460 if ( ! file_exists( AO_CCSS_LOCK ) ) {
461 $ccss_cron = new autoptimizeCriticalCSSCron();
462 $ccss_cron->ao_ccss_queue_control();
463 $response['code'] = '200';
464 $response['msg'] = 'Queue processing done';
465 } else {
466 $response['code'] = '302';
467 $response['msg'] = 'Lock file found';
468 }
469 } else {
470 $response['code'] = '500';
471 $response['msg'] = 'Not allowed';
472 }
473
474 // Dispatch respose.
475 echo json_encode( $response );
476
477 // Close ajax request.
478 wp_die();
479 }
480
481 public function ao_ccss_saverules_callback() {
482 check_ajax_referer( 'ao_ccss_saverules_nonce', 'ao_ccss_saverules_nonce' );
483
484 // save rules over AJAX, too many users forget to press "save changes".
485 if ( current_user_can( 'manage_options' ) ) {
486 if ( array_key_exists( 'critcssrules', $_POST ) ) {
487 $rules = stripslashes( $_POST['critcssrules'] ); // ugly, but seems correct as per https://developer.wordpress.org/reference/functions/stripslashes_deep/#comment-1045 .
488 if ( ! empty( $rules ) ) {
489 $_unsafe_rules_array = json_decode( wp_strip_all_tags( $rules ), true );
490 if ( ! empty( $_unsafe_rules_array ) && is_array( $_unsafe_rules_array ) ) {
491 $_safe_rules_array = array();
492 if ( array_key_exists( 'paths', $_unsafe_rules_array ) ) {
493 $_safe_rules_array['paths'] = $_unsafe_rules_array['paths'];
494 }
495 if ( array_key_exists( 'types', $_unsafe_rules_array ) ) {
496 $_safe_rules_array['types'] = $_unsafe_rules_array['types'];
497 }
498 $_safe_rules = json_encode( $_safe_rules_array, JSON_FORCE_OBJECT );
499 if ( ! empty( $_safe_rules ) ) {
500 update_option( 'autoptimize_ccss_rules', $_safe_rules );
501 $response['code'] = '200';
502 $response['msg'] = 'Rules saved';
503 } else {
504 $_error = 'Could not auto-save rules (safe rules empty)';
505 }
506 } else {
507 $_error = 'Could not auto-save rules (rules could not be json_decoded)';
508 }
509 } else {
510 $_error = 'Could not auto-save rules (rules empty)';
511 }
512 } else {
513 $_error = 'Could not auto-save rules (rules not in $_POST)';
514 }
515 } else {
516 $_error = 'Not allowed';
517 }
518
519 if ( ! isset( $response ) && $_error ) {
520 $response['code'] = '500';
521 $response['msg'] = $_error;
522 }
523
524 // Dispatch respose.
525 echo json_encode( $response );
526
527 // Close ajax request.
528 wp_die();
529 }
530
531 public function critcss_check_filename( $filename ) {
532 // Try to avoid directory traversal when reading/writing/deleting critical CSS files.
533 if ( strpos( $filename, 'ccss_' ) !== 0 ) {
534 return false;
535 } elseif ( substr( $filename, -4, 4 ) !== '.css' ) {
536 return false;
537 } elseif ( sanitize_file_name( $filename ) !== $filename ) {
538 // Use WordPress core's sanitize_file_name to see if anything fishy is going on.
539 return false;
540 } else {
541 return true;
542 }
543 }
544
545 public function rrmdir( $path ) {
546 // recursively remove a directory as found on
547 // https://andy-carter.com/blog/recursively-remove-a-directory-in-php.
548 $files = glob( $path . '/*' );
549 foreach ( $files as $file ) {
550 is_dir( $file ) ? $this->rrmdir( $file ) : unlink( $file );
551 }
552 rmdir( $path );
553
554 return;
555 }
556 }
557