PluginProbe
Autoptimize / 2.7.3
Autoptimize v2.7.3
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 2.7.3, at classes/autoptimizeCriticalCSSSettingsAjax.php

353 lines 12.9 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 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 }
19 $this->run();
20 }
21
22 public function run() {
23 // add filters.
24 add_action( 'wp_ajax_fetch_critcss', array( $this, 'critcss_fetch_callback' ) );
25 add_action( 'wp_ajax_save_critcss', array( $this, 'critcss_save_callback' ) );
26 add_action( 'wp_ajax_rm_critcss', array( $this, 'critcss_rm_callback' ) );
27 add_action( 'wp_ajax_rm_critcss_all', array( $this, 'critcss_rm_all_callback' ) );
28 add_action( 'wp_ajax_ao_ccss_export', array( $this, 'ao_ccss_export_callback' ) );
29 add_action( 'wp_ajax_ao_ccss_import', array( $this, 'ao_ccss_import_callback' ) );
30 }
31
32 public function critcss_fetch_callback() {
33 // Ajax handler to obtain a critical CSS file from the filesystem.
34 // Check referer.
35 check_ajax_referer( 'fetch_critcss_nonce', 'critcss_fetch_nonce' );
36
37 // Initialize error flag.
38 $error = true;
39
40 // Allow no content for MANUAL rules (as they may not exist just yet).
41 if ( current_user_can( 'manage_options' ) && empty( $_POST['critcssfile'] ) ) {
42 $content = '';
43 $error = false;
44 } elseif ( current_user_can( 'manage_options' ) && $this->critcss_check_filename( $_POST['critcssfile'] ) ) {
45 // Or check user permissios and filename.
46 // Set file path and obtain its content.
47 $critcssfile = AO_CCSS_DIR . strip_tags( $_POST['critcssfile'] );
48 if ( file_exists( $critcssfile ) ) {
49 $content = file_get_contents( $critcssfile );
50 $error = false;
51 }
52 }
53
54 // Prepare response.
55 if ( $error ) {
56 $response['code'] = '500';
57 $response['string'] = 'Error reading file ' . $critcssfile . '.';
58 } else {
59 $response['code'] = '200';
60 $response['string'] = $content;
61 }
62
63 // Dispatch respose.
64 echo json_encode( $response );
65
66 // Close ajax request.
67 wp_die();
68 }
69
70 public function critcss_save_callback() {
71 $error = false;
72 $status = false;
73 $response = array();
74
75 // Ajax handler to write a critical CSS to the filesystem
76 // Check referer.
77 check_ajax_referer( 'save_critcss_nonce', 'critcss_save_nonce' );
78
79 // Allow empty contents for MANUAL rules (as they are fetched later).
80 if ( current_user_can( 'manage_options' ) && empty( $_POST['critcssfile'] ) ) {
81 $critcssfile = false;
82 $status = true;
83 } elseif ( current_user_can( 'manage_options' ) && $this->critcss_check_filename( $_POST['critcssfile'] ) ) {
84 // Or check user permissios and filename
85 // Set critical CSS content.
86 $critcsscontents = stripslashes( $_POST['critcsscontents'] );
87
88 // If there is content and it's valid, write the file.
89 if ( $critcsscontents && autoptimizeCriticalCSSCore::ao_ccss_check_contents( $critcsscontents ) ) {
90 // Set file path and status.
91 $critcssfile = AO_CCSS_DIR . strip_tags( $_POST['critcssfile'] );
92 $status = file_put_contents( $critcssfile, $critcsscontents, LOCK_EX );
93 // Or set as error.
94 } else {
95 $error = true;
96 }
97 // Or just set an error.
98 } else {
99 $error = true;
100 }
101
102 // Prepare response.
103 if ( ! $status || $error ) {
104 $response['code'] = '500';
105 $response['string'] = 'Error saving file ' . $critcssfile . '.';
106 } else {
107 $response['code'] = '200';
108 if ( $critcssfile ) {
109 $response['string'] = 'File ' . $critcssfile . ' saved.';
110 } else {
111 $response['string'] = 'Empty content do not need to be saved.';
112 }
113 }
114
115 // Dispatch respose.
116 echo json_encode( $response );
117
118 // Close ajax request.
119 wp_die();
120 }
121
122
123 public function critcss_rm_callback() {
124 // Ajax handler to delete a critical CSS from the filesystem
125 // Check referer.
126 check_ajax_referer( 'rm_critcss_nonce', 'critcss_rm_nonce' );
127
128 // Initialize error and status flags.
129 $error = true;
130 $status = false;
131
132 // Allow no file for MANUAL rules (as they may not exist just yet).
133 if ( current_user_can( 'manage_options' ) && empty( $_POST['critcssfile'] ) ) {
134 $error = false;
135 } elseif ( current_user_can( 'manage_options' ) && $this->critcss_check_filename( $_POST['critcssfile'] ) ) {
136 // Or check user permissios and filename
137 // Set file path and delete it.
138 $critcssfile = AO_CCSS_DIR . strip_tags( $_POST['critcssfile'] );
139 if ( file_exists( $critcssfile ) ) {
140 $status = unlink( $critcssfile );
141 $error = false;
142 }
143 }
144
145 // Prepare response.
146 if ( $error ) {
147 $response['code'] = '500';
148 $response['string'] = 'Error removing file ' . $critcssfile . '.';
149 } else {
150 $response['code'] = '200';
151 if ( $status ) {
152 $response['string'] = 'File ' . $critcssfile . ' removed.';
153 } else {
154 $response['string'] = 'No file to be removed.';
155 }
156 }
157
158 // Dispatch respose.
159 echo json_encode( $response );
160
161 // Close ajax request.
162 wp_die();
163 }
164
165 public function critcss_rm_all_callback() {
166 // Ajax handler to delete a critical CSS from the filesystem
167 // Check referer.
168 check_ajax_referer( 'rm_critcss_all_nonce', 'critcss_rm_all_nonce' );
169
170 // Initialize error and status flags.
171 $error = true;
172 $status = false;
173
174 // Remove all ccss files on filesystem.
175 if ( current_user_can( 'manage_options' ) ) {
176 if ( file_exists( AO_CCSS_DIR ) && is_dir( AO_CCSS_DIR ) ) {
177 array_map( 'unlink', glob( AO_CCSS_DIR . 'ccss_*.css', GLOB_BRACE ) );
178 $error = false;
179 $status = true;
180 }
181 }
182
183 // Prepare response.
184 if ( $error ) {
185 $response['code'] = '500';
186 $response['string'] = 'Error removing all critical CSS files.';
187 } else {
188 $response['code'] = '200';
189 if ( $status ) {
190 $response['string'] = 'Critical CSS Files removed.';
191 } else {
192 $response['string'] = 'No file removed.';
193 }
194 }
195
196 // Dispatch respose.
197 echo json_encode( $response );
198
199 // Close ajax request.
200 wp_die();
201 }
202
203 public function ao_ccss_export_callback() {
204 // Ajax handler export settings
205 // Check referer.
206 check_ajax_referer( 'ao_ccss_export_nonce', 'ao_ccss_export_nonce' );
207
208 if ( ! class_exists( 'ZipArchive' ) ) {
209 $response['code'] = '500';
210 $response['msg'] = 'PHP ZipArchive not present, cannot create zipfile';
211 echo json_encode( $response );
212 wp_die();
213 }
214
215 // 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' );
225
226 // Initialize error flag.
227 $error = true;
228
229 // Check user permissions.
230 if ( current_user_can( 'manage_options' ) ) {
231 // Prepare settings file path and content.
232 $exportfile = AO_CCSS_DIR . 'settings.json';
233 $contents = json_encode( $settings );
234 $status = file_put_contents( $exportfile, $contents, LOCK_EX );
235 $error = false;
236 }
237
238 // Prepare archive.
239 $zipfile = AO_CCSS_DIR . date( 'Ymd-H\hi' ) . '_ao_ccss_settings.zip';
240 $file = pathinfo( $zipfile, PATHINFO_BASENAME );
241 $zip = new ZipArchive();
242 $ret = $zip->open( $zipfile, ZipArchive::CREATE );
243 if ( true !== $ret ) {
244 $error = true;
245 } else {
246 $zip->addFile( AO_CCSS_DIR . 'settings.json', 'settings.json' );
247 if ( file_exists( AO_CCSS_DIR . 'queue.json' ) ) {
248 $zip->addFile( AO_CCSS_DIR . 'queue.json', 'queue.json' );
249 }
250 $options = array(
251 'add_path' => './',
252 'remove_all_path' => true,
253 );
254 $zip->addGlob( AO_CCSS_DIR . '*.css', 0, $options );
255 $zip->close();
256 }
257
258 // Prepare response.
259 if ( ! $status || $error ) {
260 $response['code'] = '500';
261 $response['msg'] = 'Error saving file ' . $file . ', code: ' . $ret;
262 } else {
263 $response['code'] = '200';
264 $response['msg'] = 'File ' . $file . ' saved.';
265 $response['file'] = $file;
266 }
267
268 // Dispatch respose.
269 echo json_encode( $response );
270
271 // Close ajax request.
272 wp_die();
273 }
274
275 public function ao_ccss_import_callback() {
276 // Ajax handler import settings
277 // Check referer.
278 check_ajax_referer( 'ao_ccss_import_nonce', 'ao_ccss_import_nonce' );
279
280 // Initialize error flag.
281 $error = false;
282
283 // 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'];
287 move_uploaded_file( $_FILES['file']['tmp_name'], $zipfile );
288
289 // Extract archive.
290 $zip = new ZipArchive;
291 if ( $zip->open( $zipfile ) === true ) {
292 $zip->extractTo( AO_CCSS_DIR );
293 $zip->close();
294 } else {
295 $error = 'extracting';
296 }
297
298 if ( ! $error ) {
299 // Archive extraction ok, continue settings importing
300 // Settings file.
301 $importfile = AO_CCSS_DIR . 'settings.json';
302
303 if ( file_exists( $importfile ) ) {
304 // Get settings and turn them into an object.
305 $settings = json_decode( file_get_contents( $importfile ), true );
306
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'] );
316 } else {
317 // Settings file doesn't exist, update error flag.
318 $error = 'settings file does not exist';
319 }
320 }
321 }
322
323 // Prepare response.
324 if ( $error ) {
325 $response['code'] = '500';
326 $response['msg'] = 'Error importing settings: ' . $error;
327 } else {
328 $response['code'] = '200';
329 $response['msg'] = 'Settings imported successfully';
330 }
331
332 // Dispatch respose.
333 echo json_encode( $response );
334
335 // Close ajax request.
336 wp_die();
337 }
338
339 public function critcss_check_filename( $filename ) {
340 // Try to avoid directory traversal when reading/writing/deleting critical CSS files.
341 if ( strpos( $filename, 'ccss_' ) !== 0 ) {
342 return false;
343 } elseif ( substr( $filename, -4, 4 ) !== '.css' ) {
344 return false;
345 } elseif ( sanitize_file_name( $filename ) !== $filename ) {
346 // Use WordPress core's sanitize_file_name to see if anything fishy is going on.
347 return false;
348 } else {
349 return true;
350 }
351 }
352 }
353