This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Critical CSS settings AJAX logic. |
||
4 | */ |
||
5 | |||
6 | if ( ! defined( 'ABSPATH' ) ) { |
||
7 | exit; |
||
8 | } |
||
9 | |||
10 | class autoptimizeCriticalCSSSettingsAjax { |
||
11 | View Code Duplication | 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 | View Code Duplication | 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'; |
||
0 ignored issues
–
show
|
|||
57 | $response['string'] = 'Error reading file ' . $critcssfile . '.'; |
||
58 | } else { |
||
59 | $response['code'] = '200'; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$response was never initialized. Although not strictly required by PHP, it is generally a good practice to add $response = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
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 | View Code Duplication | 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 | View Code Duplication | 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 | View Code Duplication | if ( $error ) { |
|
147 | $response['code'] = '500'; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$response was never initialized. Although not strictly required by PHP, it is generally a good practice to add $response = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
148 | $response['string'] = 'Error removing file ' . $critcssfile . '.'; |
||
149 | } else { |
||
150 | $response['code'] = '200'; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$response was never initialized. Although not strictly required by PHP, it is generally a good practice to add $response = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
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'; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$response was never initialized. Although not strictly required by PHP, it is generally a good practice to add $response = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
186 | $response['string'] = 'Error removing all critical CSS files.'; |
||
187 | } else { |
||
188 | $response['code'] = '200'; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$response was never initialized. Although not strictly required by PHP, it is generally a good practice to add $response = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
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'; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$response was never initialized. Although not strictly required by PHP, it is generally a good practice to add $response = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
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['rtimelimit'] = get_option( 'autoptimize_ccss_rtimelimit' ); |
||
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 | View Code Duplication | 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 ( current_user_can( 'manage_options' ) && ! $_FILES['file']['error'] && $_FILES['file']['size'] < 500001 && strpos( $_FILES['file']['name'], '.zip' ) === strlen( $_FILES['file']['name'] ) - 4 ) { |
||
285 | // create tmp dir with hard guess name in AO_CCSS_DIR. |
||
286 | $_secret_dir = wp_hash( uniqid( md5( AUTOPTIMIZE_CACHE_URL ), true ) ); |
||
287 | $_import_tmp_dir = trailingslashit( AO_CCSS_DIR . $_secret_dir ); |
||
288 | mkdir( $_import_tmp_dir ); |
||
289 | |||
290 | // Save file to that tmp directory but give it our own name to prevent directory traversal risks when using original name. |
||
291 | $zipfile = $_import_tmp_dir . uniqid( 'import_settings-', true ) . '.zip'; |
||
292 | move_uploaded_file( $_FILES['file']['tmp_name'], $zipfile ); |
||
293 | |||
294 | // Extract archive in the tmp directory. |
||
295 | $zip = new ZipArchive; |
||
296 | if ( $zip->open( $zipfile ) === true ) { |
||
297 | // loop through all files in the zipfile. |
||
298 | for ($i = 0; $i < $zip->numFiles; $i++) { |
||
299 | // but only extract known good files. |
||
300 | if ( preg_match('/^settings\.json$|^ccss_[a-z0-9]{32}\.css$/', $zip->getNameIndex( $i ) ) > 0 ) { |
||
301 | $zip->extractTo( AO_CCSS_DIR, $zip->getNameIndex( $i ) ); |
||
302 | } |
||
303 | } |
||
304 | $zip->close(); |
||
305 | } else { |
||
306 | $error = 'could not extract'; |
||
307 | } |
||
308 | |||
309 | // and remove temp. dir with all contents (the import-zipfile). |
||
310 | $this->rrmdir( $_import_tmp_dir ); |
||
311 | |||
312 | if ( ! $error ) { |
||
313 | // Archive extraction ok, continue importing settings from AO_CCSS_DIR. |
||
314 | // Settings file. |
||
315 | $importfile = AO_CCSS_DIR . 'settings.json'; |
||
316 | |||
317 | if ( file_exists( $importfile ) ) { |
||
318 | // Get settings and turn them into an object. |
||
319 | $settings = json_decode( file_get_contents( $importfile ), true ); |
||
320 | |||
321 | // Update options. |
||
322 | update_option( 'autoptimize_ccss_rules', $settings['rules'] ); |
||
323 | update_option( 'autoptimize_ccss_additional', $settings['additional'] ); |
||
324 | update_option( 'autoptimize_ccss_viewport', $settings['viewport'] ); |
||
325 | update_option( 'autoptimize_ccss_finclude', $settings['finclude'] ); |
||
326 | update_option( 'autoptimize_ccss_rtimelimit', $settings['rtimelimit'] ); |
||
327 | update_option( 'autoptimize_ccss_noptimize', $settings['noptimize'] ); |
||
328 | update_option( 'autoptimize_ccss_debug', $settings['debug'] ); |
||
329 | update_option( 'autoptimize_ccss_key', $settings['key'] ); |
||
330 | } else { |
||
331 | // Settings file doesn't exist, update error flag. |
||
332 | $error = 'settings file does not exist'; |
||
333 | } |
||
334 | } |
||
335 | } else { |
||
336 | $error = 'file could not be saved'; |
||
337 | } |
||
338 | |||
339 | // Prepare response. |
||
340 | if ( $error ) { |
||
341 | $response['code'] = '500'; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$response was never initialized. Although not strictly required by PHP, it is generally a good practice to add $response = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
342 | $response['msg'] = 'Error importing settings: ' . $error; |
||
343 | } else { |
||
344 | $response['code'] = '200'; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$response was never initialized. Although not strictly required by PHP, it is generally a good practice to add $response = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
345 | $response['msg'] = 'Settings imported successfully'; |
||
346 | } |
||
347 | |||
348 | // Dispatch respose. |
||
349 | echo json_encode( $response ); |
||
350 | |||
351 | // Close ajax request. |
||
352 | wp_die(); |
||
353 | } |
||
354 | |||
355 | public function critcss_check_filename( $filename ) { |
||
356 | // Try to avoid directory traversal when reading/writing/deleting critical CSS files. |
||
357 | if ( strpos( $filename, 'ccss_' ) !== 0 ) { |
||
358 | return false; |
||
359 | } elseif ( substr( $filename, -4, 4 ) !== '.css' ) { |
||
360 | return false; |
||
361 | } elseif ( sanitize_file_name( $filename ) !== $filename ) { |
||
362 | // Use WordPress core's sanitize_file_name to see if anything fishy is going on. |
||
363 | return false; |
||
364 | } else { |
||
365 | return true; |
||
366 | } |
||
367 | } |
||
368 | |||
369 | public function rrmdir( $path ) { |
||
370 | // recursively remove a directory as found on |
||
371 | // https://andy-carter.com/blog/recursively-remove-a-directory-in-php. |
||
372 | $files = glob($path . '/*'); |
||
373 | foreach ( $files as $file ) { |
||
374 | is_dir( $file ) ? $this->rrmdir( $file ) : unlink( $file ); |
||
375 | } |
||
376 | rmdir( $path ); |
||
377 | |||
378 | return; |
||
379 | } |
||
380 | } |
||
381 |
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.
Let’s take a look at an example:
As you can see in this example, the array
$myArray
is initialized the first time when the foreach loop is entered. You can also see that the value of thebar
key is only written conditionally; thus, its value might result from a previous iteration.This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.