Issues (280)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

classes/autoptimizeCriticalCSSSettings.php (1 issue)

Upgrade to new PHP Analysis Engine

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 Options page.
4
 */
5
6
if ( ! defined( 'ABSPATH' ) ) {
7
    exit;
8
}
9
10
class autoptimizeCriticalCSSSettings {
11
    /**
12
     * Options.
13
     *
14
     * @var bool
15
     */
16
    private $settings_screen_do_remote_http = true;
17
18
    public function __construct()
19
    {
20
        $this->settings_screen_do_remote_http = apply_filters( 'autoptimize_settingsscreen_remotehttp', $this->settings_screen_do_remote_http );
21
        $this->run();
22
    }
23
24
    protected function enabled()
25
    {
26
        return apply_filters( 'autoptimize_filter_show_criticalcss_tabs', true );
27
    }
28
29
    public function run()
30
    {
31
        if ( $this->enabled() ) {
32
            add_filter( 'autoptimize_filter_settingsscreen_tabs', array( $this, 'add_critcss_tabs' ), 10, 1 );
33
            add_action( 'admin_enqueue_scripts', array( $this, 'admin_assets' ) );
34
35
            if ( $this->is_multisite_network_admin() && autoptimizeOptionWrapper::is_ao_active_for_network() ) {
36
                add_action( 'network_admin_menu', array( $this, 'add_critcss_admin_menu' ) );
37
            } else {
38
                add_action( 'admin_menu', array( $this, 'add_critcss_admin_menu' ) );
39
            }
40
41
            $criticalcss_ajax = new autoptimizeCriticalCSSSettingsAjax();
0 ignored issues
show
$criticalcss_ajax is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
42
        }
43
    }
44
45
    public function add_critcss_tabs( $in )
46
    {
47
        $in = array_merge( $in, array( 'ao_critcss' => 'âš¡ ' . __( 'Critical CSS', 'autoptimize' ) ) );
48
49
        return $in;
50
    }
51
52
    public function add_critcss_admin_menu()
53
    {
54
        // Register settings.
55
        register_setting( 'ao_ccss_options_group', 'autoptimize_css_defer_inline' );
56
        register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_rules' );
57
        register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_additional' );
58
        register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_queue' );
59
        register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_viewport' );
60
        register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_finclude' );
61
        register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_rtimelimit' );
62
        register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_noptimize' );
63
        register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_debug' );
64
        register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_key' );
65
        register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_keyst' );
66
        register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_loggedin' );
67
        register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_forcepath' );
68
        register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_deferjquery' );
69
        register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_domain' );
70
        register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_unloadccss' );
71
72
        // And add submenu-page.
73
        add_submenu_page( null, 'Critical CSS', 'Critical CSS', 'manage_options', 'ao_critcss', array( $this, 'ao_criticalcsssettings_page' ) );
74
    }
75
76
    public function admin_assets( $hook ) {
77
        // Return if plugin is not hooked.
78
        if ( 'settings_page_ao_critcss' != $hook && 'admin_page_ao_critcss' != $hook ) {
79
            return;
80
        }
81
82
        // Stylesheets to add.
83
        wp_enqueue_style( 'wp-jquery-ui-dialog' );
84
        wp_enqueue_style( 'ao-tablesorter', plugins_url( 'critcss-inc/css/ao-tablesorter/style.css', __FILE__ ) );
85
        wp_enqueue_style( 'ao-ccss-admin-css', plugins_url( 'critcss-inc/css/admin_styles.css', __FILE__ ) );
86
87
        // Scripts to add.
88
        wp_enqueue_script( 'jquery-ui-dialog', array( 'jquery' ) );
89
        wp_enqueue_script( 'md5', plugins_url( 'critcss-inc/js/md5.min.js', __FILE__ ), null, null, true );
90
        wp_enqueue_script( 'tablesorter', plugins_url( 'critcss-inc/js/jquery.tablesorter.min.js', __FILE__ ), array( 'jquery' ), null, true );
91
        wp_enqueue_script( 'ao-ccss-admin-license', plugins_url( 'critcss-inc/js/admin_settings.js', __FILE__ ), array( 'jquery' ), null, true );
92
    }
93
94
    public function ao_criticalcsssettings_page()
95
    {
96
        // these are not OO yet, simply require for now.
97
        require_once( 'critcss-inc/admin_settings_rules.php' );
98
        require_once( 'critcss-inc/admin_settings_queue.php' );
99
        require_once( 'critcss-inc/admin_settings_key.php' );
100
        require_once( 'critcss-inc/admin_settings_adv.php' );
101
        require_once( 'critcss-inc/admin_settings_explain.php' );
102
103
        // fetch all options at once and populate them individually explicitely as globals.
104
        $all_options = autoptimizeCriticalCSSBase::fetch_options();
105
        foreach ( $all_options as $_option => $_value ) {
106
            global ${$_option};
107
            ${$_option} = $_value;
108
        }
109
        ?>
110
        <script>document.title = "Autoptimize: <?php _e( 'Critical CSS', 'autoptimize' ); ?> " + document.title;</script>
111
        <div class="wrap">
112
            <div id="autoptimize_main">
113
                <div id="ao_title_and_button">
114
                    <h1><?php _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
115
                </div>
116
117
                <?php
118
                // Print AO settings tabs.
119
                echo autoptimizeConfig::ao_admin_tabs();
120
121
                // Make sure dir to write ao_ccss exists and is writable.
122
                if ( ! is_dir( AO_CCSS_DIR ) ) {
123
                    $mkdirresp = @mkdir( AO_CCSS_DIR, 0775, true ); // @codingStandardsIgnoreLine
124
                } else {
125
                    $mkdirresp = true;
126
                }
127
128
                // Make sure our index.html is there.
129
                if ( ! is_file( AO_CCSS_DIR . 'index.html' ) ) {
130
                    $fileresp = file_put_contents( AO_CCSS_DIR . 'index.html', '<html><head><meta name="robots" content="noindex, nofollow"></head><body>Generated by <a href="http://wordpress.org/extend/plugins/autoptimize/" rel="nofollow">Autoptimize</a></body></html>' );
131
                } else {
132
                    $fileresp = true;
133
                }
134
135
                // Warn if we could not create those files.
136
                if ( ( ! $mkdirresp ) || ( ! $fileresp ) ) {
137
                    ?>
138
                    <div class="notice-error notice"><p>
139
                    <?php
140
                    _e( 'Could not create the required directory. Make sure the webserver can write to the wp-content directory.', 'autoptimize' );
141
                    ?>
142
                    </p></div>
143
                    <?php
144
                }
145
146
                // Check for "inline & defer CSS" being active in Autoptimize.
147
                if ( ! empty( $ao_ccss_key ) && ! $ao_css_defer ) {
148
                    if ( empty( $ao_ccss_keyst ) ) {
149
                        // no keystate so likely in activation-process of CCSS, let's enable "inline & defer CSS" immediately to make things easier!
150
                        autoptimizeOptionWrapper::update_option( 'autoptimize_css_defer', 'on' );
151
                        ?>
152
                        <div class="notice-info notice"><p>
153
                        <?php
154
                        _e( "The \"Inline and Defer CSS\" option was activated to allow critical CSS to be used.", 'autoptimize' );
155
                        ?>
156
                        </p></div>
157
                        <?php
158
                    } else {
159
                        // we have keystate, so "inline & defer CSS" was probably disable for troubleshooting, warn but let users continue.
160
                        ?>
161
                        <div class="notice-warning notice"><p>
162
                        <?php
163
                        _e( "Oops! Please <strong>activate the \"Inline and Defer CSS\" option</strong> on Autoptimize's main settings page to ensure critical CSS is used on the front-end.", 'autoptimize' );
164
                        ?>
165
                        </p></div>
166
                        <?php
167
                    }
168
                }
169
170
                // check if WordPress cron is disabled and warn if so.
171
                if ( ! empty( $ao_ccss_key ) && defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON && PAnD::is_admin_notice_active( 'i-know-about-disable-cron-forever' ) ) {
172
                    ?>
173
                    <div data-dismissible="i-know-about-disable-cron-forever" class="notice-warning notice is-dismissible"><p>
174
                    <?php
175
                    _e( 'WordPress cron (for task scheduling) seems to be disabled. Have a look at <a href="https://wordpress.org/plugins/autoptimize-criticalcss/faq/" target="_blank">the FAQ</a> or the info in the Job Queue instructions if all jobs remain in "N" status and no rules are created.', 'autoptimize' );
176
                    ?>
177
                    </p></div>
178
                    <?php
179
                }
180
181
                // warn if it looks as though the queue processing job looks isn't running
182
                // but store result in transient as to not to have to go through 2 arrays each and every time.
183
                $_warn_cron = get_transient( 'ao_ccss_cronwarning' );
184
                if ( ! empty( $ao_ccss_key ) && false === $_warn_cron ) {
185
                    $_jobs_all_new         = true;
186
                    $_oldest_job_timestamp = microtime( true ); // now.
187
                    $_jobs_too_old         = true;
188
189
                    // go over queue array.
190
                    if ( empty( $ao_ccss_queue ) ) {
191
                        // no jobs, then no warning.
192
                        $_jobs_all_new = false;
193
                    } else {
194
                        foreach ( $ao_ccss_queue as $job ) {
195
                            if ( $job['jctime'] < $_oldest_job_timestamp ) {
196
                                // we need to catch the oldest job's timestamp.
197
                                $_oldest_job_timestamp = $job['jctime'];
198
                            }
199
200
                            if ( 'NEW' !== $job['jqstat'] && 'firstrun' !== $job['ljid'] ) {
201
                                // we have a non-"NEW" job which is not our pending firstrun job either, break the loop.
202
                                $_jobs_all_new = false;
203
                                break;
204
                            }
205
                        }
206
                    }
207
208
                    // is the oldest job too old (4h)?
209
                    if ( $_oldest_job_timestamp > microtime( true ) - 60 * 60 * 4 ) {
210
                        $_jobs_too_old = false;
211
                    }
212
213
                    if ( $_jobs_all_new && ! $this->ao_ccss_has_autorules() && $_jobs_too_old ) {
214
                        $_warn_cron            = 'on';
215
                        $_transient_multiplier = 1; // store for 1 hour.
216
                    } else {
217
                        $_warn_cron            = 'off';
218
                        $_transient_multiplier = 4; // store for 4 hours.
219
                    }
220
                    // and set transient.
221
                    set_transient( 'ao_ccss_cronwarning', $_warn_cron, $_transient_multiplier * HOUR_IN_SECONDS );
222
                }
223
224
                if ( ! empty( $ao_ccss_key ) && 'on' == $_warn_cron && PAnD::is_admin_notice_active( 'i-know-about-cron-1' ) ) {
225
                    ?>
226
                    <div data-dismissible="i-know-about-cron-1" class="notice-warning notice is-dismissible"><p>
227
                    <?php
228
                    _e( 'It looks like there might be a problem with WordPress cron (task scheduling). Have a look at <a href="https://wordpress.org/plugins/autoptimize-criticalcss/faq/" target="_blank">the FAQ</a> or the info in the Job Queue instructions if all jobs remain in "N" status and no rules are created.', 'autoptimize' );
229
                    ?>
230
                    </p></div>
231
                    <?php
232
                } elseif ( ! empty( $ao_ccss_key ) && '2' == $ao_ccss_keyst && 'on' != $_warn_cron && ! $this->ao_ccss_has_autorules() ) {
233
                    ?>
234
                    <div class="notice-success notice"><p>
235
                    <?php
236
                    _e( 'Great, Autoptimize will now automatically start creating new critical CSS rules, you should see those appearing below in the next couple of hours.', 'autoptimize' );
237
                    echo ' ';
238
                    _e( 'In the meantime you might want to <strong>edit default rule CSS now</strong>, to avoid all CSS being inlined when no (applicable) rules are found.', 'autoptimize' );
239
                    ?>
240
                    </p></div>
241
                    <?php
242
                }
243
244
                // warn if service is down.
245
                if ( ! empty( $ao_ccss_key ) && ! empty( $ao_ccss_servicestatus ) && is_array( $ao_ccss_servicestatus ) && 'down' === $ao_ccss_servicestatus['critcss']['status'] ) {
246
                    ?>
247
                    <div class="notice-warning notice"><p>
248
                    <?php
249
                    _e( 'The critical CSS service has been reported to be down. Although no new rules will be created for now, this does not prevent existing rules from being applied.', 'autoptimize' );
250
                    ?>
251
                    </p></div>
252
                    <?php
253
                }
254
255
                // warn if too many rules (based on length of ao_ccss_rules option) as that might cause issues at e.g. wpengine
256
                // see https://wpengine.com/support/database-optimization-best-practices/#Autoloaded_Data
257
                $_raw_rules_length = strlen( get_option( 'autoptimize_ccss_rules', '') );
258
                if ( $_raw_rules_length > apply_filters( 'autoptimize_ccss_rules_length_warning', 500000 ) ) {
259
                    ?>
260
                    <div class="notice-warning notice"><p>
261
                    <?php
262
                    _e( 'It looks like the amount of Critical CSS rules is very high, it is recommended to reconfigure Autoptimize (e.g. by manually creating broader rules) to ensure less rules are created.', 'autoptimize' );
263
                    ?>
264
                    </p></div>
265
                    <?php
266
                }
267
268
                // Settings Form.
269
                ?>
270
                <form id="settings" method="post" action="options.php">
271
                    <?php
272
                    settings_fields( 'ao_ccss_options_group' );
273
274
                    // Get API key status.
275
                    $key = autoptimizeCriticalCSSCore::ao_ccss_key_status( true );
276
277
                    if ( $this->is_multisite_network_admin() ) {
278
                        ?>
279
                        <ul id="key-panel">
280
                            <li class="itemDetail">
281
                            <?php
282
                                // translators: the placesholder is for a line of code in wp-config.php.
283
                                echo sprintf( __( '<p>Critical CSS settings cannot be set at network level as critical CSS is specific to each sub-site.</p><p>You can however provide the critical CSS API key for use by all sites by adding this your wp-config.php as %s</p>', 'autoptimize' ), '<br/><code>define(\'AUTOPTIMIZE_CRITICALCSS_API_KEY\', \'eyJhbGmorestringsherexHa7MkOQFtDFkZgLmBLe-LpcHx4\');</code>' );
284
                            ?>
285
                            </li>
286
                        </ul>
287
                        <?php
288
                    } else {
289
                        if ( 'valid' == $key['status'] ) {
290
                            // If key status is valid, render other panels.
291
                            // Render rules section.
292
                            ao_ccss_render_rules();
293
                            // Render queue section.
294
                            ao_ccss_render_queue();
295
                            // Render advanced panel.
296
                            ao_ccss_render_adv();
297
                        } else {
298
                            // But if key is other than valid, add hidden fields to persist settings when submitting form
299
                            // Show explanation of why and how to get a API key.
300
                            ao_ccss_render_explain();
301
302
                            // Get viewport size.
303
                            $viewport = autoptimizeCriticalCSSCore::ao_ccss_viewport();
304
305
                            // Add hidden fields.
306
                            echo "<input class='hidden' name='autoptimize_ccss_rules' value='" . $ao_ccss_rules_raw . "'>";
307
                            echo "<input class='hidden' name='autoptimize_ccss_queue' value='" . $ao_ccss_queue_raw . "'>";
308
                            echo '<input class="hidden" name="autoptimize_ccss_viewport[w]" value="' . $viewport['w'] . '">';
309
                            echo '<input class="hidden" name="autoptimize_ccss_viewport[h]" value="' . $viewport['h'] . '">';
310
                            echo '<input class="hidden" name="autoptimize_ccss_finclude" value="' . esc_attr( $ao_ccss_finclude ) . '">';
311
                            echo '<input class="hidden" name="autoptimize_ccss_rtimelimit" value="' . $ao_ccss_rtimelimit . '">';
312
                            echo '<input class="hidden" name="autoptimize_ccss_debug" value="' . $ao_ccss_debug . '">';
313
                            echo '<input class="hidden" name="autoptimize_ccss_noptimize" value="' . $ao_ccss_noptimize . '">';
314
                            echo '<input class="hidden" name="autoptimize_css_defer_inline" value="' . esc_attr( $ao_css_defer_inline ) . '">';
315
                            echo '<input class="hidden" name="autoptimize_ccss_loggedin" value="' . $ao_ccss_loggedin . '">';
316
                            echo '<input class="hidden" name="autoptimize_ccss_forcepath" value="' . $ao_ccss_forcepath . '">';
317
                        }
318
                        // Render key panel unconditionally.
319
                        ao_ccss_render_key( $ao_ccss_key, $key['status'], $key['stmsg'], $key['msg'], $key['color'] );
320
                        ?>
321
                        <p class="submit left">
322
                            <input type="submit" class="button-primary" value="<?php _e( 'Save Changes', 'autoptimize' ); ?>" />
323
                        </p>
324
                        <?php
325
                    }
326
                    ?>
327
                </form>
328
                <script>
329
                jQuery("form#settings").submit(function(){
330
                    var input = jQuery("#autoptimize_ccss_domain");
331
                    input.val(rot(input.val(), 13));
332
                });
333
                // rot JS from http://stackoverflow.com/a/617685/987044 .
334
                function rot(domainstring, itype) {
335
                    return domainstring.toString().replace(/[a-zA-Z]/g, function (letter) {
336
                        return String.fromCharCode((letter <= 'Z' ? 90 : 122) >= (letter = letter.charCodeAt(0) + itype) ? letter : letter   - 26);
337
                    });
338
                }
339
                </script>
340
                <form id="importSettingsForm"<?php if ( $this->is_multisite_network_admin() ) { echo ' class="hidden"'; } ?>>
341
                    <span id="exportSettings" class="button-secondary"><?php _e( 'Export Settings', 'autoptimize' ); ?></span>
342
                    <input class="button-secondary" id="importSettings" type="button" value="<?php _e( 'Import Settings', 'autoptimize' ); ?>" onclick="upload();return false;" />
343
                    <input class="button-secondary" id="settingsfile" name="settingsfile" type="file" />
344
                </form>
345
                <div id="importdialog"></div>
346
            </div><!-- /#autoptimize_main -->
347
        </div><!-- /#wrap -->
348
        <?php
349
        if ( ! $this->is_multisite_network_admin() ) {
350
            // Include debug panel if debug mode is enable.
351
            if ( $ao_ccss_debug ) {
352
            ?>
353
                <div id="debug">
354
                    <?php
355
                    // Include debug panel.
356
                    include( 'critcss-inc/admin_settings_debug.php' );
357
                    ?>
358
                </div><!-- /#debug -->
359
            <?php
360
            }
361
            echo '<script>';
362
            include( 'critcss-inc/admin_settings_rules.js.php' );
363
            include( 'critcss-inc/admin_settings_queue.js.php' );
364
            include( 'critcss-inc/admin_settings_impexp.js.php' );
365
            echo '</script>';
366
        }
367
    }
368
369
    public static function ao_ccss_has_autorules() {
370
        static $_has_auto_rules = null;
371
372
        if ( null === $_has_auto_rules ) {
373
            global $ao_ccss_rules;
374
            $_has_auto_rules = false;
375
            if ( ! empty( $ao_ccss_rules ) ) {
376
                foreach ( array( 'types', 'paths' ) as $_typat ) {
377
                    foreach ( $ao_ccss_rules[ $_typat ] as $rule ) {
378
                        if ( ! empty( $rule['hash'] ) ) {
379
                            // we have at least one AUTO job, so all is fine.
380
                            $_has_auto_rules = true;
381
                            break;
382
                        }
383
                    }
384
                    if ( $_has_auto_rules ) {
385
                        break;
386
                    }
387
                }
388
            }
389
        }
390
391
        return $_has_auto_rules;
392
    }
393
394
    public function is_multisite_network_admin() {
395
        static $_multisite_network_admin = null;
396
397
        if ( null === $_multisite_network_admin ) {
398
            if ( is_multisite() && is_network_admin() ) {
399
                $_multisite_network_admin = true;
400
            } else {
401
                $_multisite_network_admin = false;
402
            }
403
        }
404
405
        return $_multisite_network_admin;
406
    }
407
}
408