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/autoptimizeCriticalCSSEnqueue.php (4 issues)

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 job enqueue logic.
4
 */
5
6
if ( ! defined( 'ABSPATH' ) ) {
7
    exit;
8
}
9
10
class autoptimizeCriticalCSSEnqueue {
11
    public function __construct()
12
    {
13
        // fetch all options at once and populate them individually explicitely as globals.
14
        $all_options = autoptimizeCriticalCSSBase::fetch_options();
0 ignored issues
show
Are you sure the assignment to $all_options is correct as \autoptimizeCriticalCSSBase::fetch_options() (which targets autoptimizeCriticalCSSBase::fetch_options()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
15
        foreach ( $all_options as $_option => $_value ) {
0 ignored issues
show
The expression $all_options of type null is not traversable.
Loading history...
16
            global ${$_option};
17
            ${$_option} = $_value;
18
        }
19
    }
20
21
    public static function ao_ccss_enqueue( $hash ) {
22
        $self = new self();
23
        // Get key status.
24
        $key = autoptimizeCriticalCSSCore::ao_ccss_key_status( false );
25
26
        // Queue is available to anyone...
27
        $enqueue = true;
28
29
        // ... which are not the ones below.
30
        if ( is_user_logged_in() || is_feed() || is_404() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) || $self->ao_ccss_ua() || 'nokey' == $key['status'] || 'invalid' == $key['status'] || false === apply_filters( 'autoptimize_filter_ccss_enqueue_should_enqueue', true ) ) {
31
            $enqueue = false;
32
            autoptimizeCriticalCSSCore::ao_ccss_log( "Job queuing is not available for WordPress's logged in users, feeds, error pages, ajax calls, to criticalcss.com itself or when a valid API key is not found", 3 );
33
        }
34
35
        if ( $enqueue ) {
36
            // Continue if queue is available
37
            // Attach required arrays/ vars.
38
            global $ao_ccss_rules;
39
            global $ao_ccss_queue_raw;
40
            global $ao_ccss_queue;
41
            global $ao_ccss_forcepath;
42
43
            // Get request path and page type, and initialize the queue update flag.
44
            $req_orig        = $_SERVER['REQUEST_URI'];
45
            $req_path        = strtok( $req_orig, '?' );
46
47
            // Check if we have a lang param. we need to keep as WPML can switch languages based on that
48
            // and that includes RTL -> LTR so diff. structure, so rules would be RTL vs LTR
49
            // but this needs changes in the structur of the rule object so off by default for now
50
            // as now this will simply result in conditional rules being overwritten.
51
            if ( apply_filters( 'autoptimize_filter_ccss_coreenqueue_honor_lang', false ) && strpos( $req_orig, 'lang=' ) !== false ) {
52
                $req_params = strtok( '?' );
53
                parse_str( $req_params, $req_params_arr );
54
                if ( array_key_exists( 'lang', $req_params_arr ) && !empty( $req_params_arr['lang'] ) ) {
55
                    $req_path .= '?lang=' . $req_params_arr['lang'];
56
                }
57
            }
58
59
            $req_type        = $self->ao_ccss_get_type();
60
            $job_qualify     = false;
61
            $target_rule     = false;
62
            $rule_properties = false;
63
            $queue_update    = false;
64
65
            // Match for paths in rules.
66
            foreach ( $ao_ccss_rules['paths'] as $path => $props ) {
67
68
                // Prepare rule target and log.
69
                $target_rule = 'paths|' . $path;
70
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Qualifying path <' . $req_path . '> for job submission by rule <' . $target_rule . '>', 3 );
71
72
                // Path match
73
                // -> exact match needed for AUTO rules
74
                // -> partial match OK for MANUAL rules (which have empty hash and a file with CCSS).
75
                if ( $path === $req_path || ( false == $props['hash'] && false != $props['file'] && preg_match( '|' . $path . '|', $req_path ) ) ) {
76
77
                    // There's a path match in the rule, so job QUALIFIES with a path rule match.
78
                    $job_qualify     = true;
79
                    $rule_properties = $props;
80
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'Path <' . $req_path . '> QUALIFIED for job submission by rule <' . $target_rule . '>', 3 );
81
82
                    // Stop processing other path rules.
83
                    break;
84
                }
85
            }
86
87
            // Match for types in rules if no path rule matches and if we're not enforcing paths.
88
            if ( ! $job_qualify && ( ! $ao_ccss_forcepath || ! in_array( $req_type, apply_filters( 'autoptimize_filter_ccss_coreenqueue_forcepathfortype', array( 'is_page' ) ) ) || ! apply_filters( 'autoptimize_filter_ccss_coreenqueue_ignorealltypes', false ) ) ) {
89
                foreach ( $ao_ccss_rules['types'] as $type => $props ) {
90
91
                    // Prepare rule target and log.
92
                    $target_rule = 'types|' . $type;
93
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'Qualifying page type <' . $req_type . '> on path <' . $req_path . '> for job submission by rule <' . $target_rule . '>', 3 );
94
95
                    if ( $req_type == $type ) {
96
                        // Type match.
97
                        // There's a type match in the rule, so job QUALIFIES with a type rule match.
98
                        $job_qualify     = true;
99
                        $rule_properties = $props;
100
                        autoptimizeCriticalCSSCore::ao_ccss_log( 'Page type <' . $req_type . '> on path <' . $req_path . '> QUALIFIED for job submission by rule <' . $target_rule . '>', 3 );
101
102
                        // Stop processing other type rules.
103
                        break;
104
                    }
105
                }
106
            }
107
108
            if ( $job_qualify && ( ( false == $rule_properties['hash'] && false != $rule_properties['file'] ) || strpos( $req_type, 'template_' ) !== false ) ) {
109
                // If job qualifies but rule hash is false and file isn't false (MANUAL rule) or if template, job does not qualify despite what previous evaluations says.
110
                $job_qualify = false;
111
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Job submission DISQUALIFIED by MANUAL rule <' . $target_rule . '> with hash <' . $rule_properties['hash'] . '> and file <' . $rule_properties['file'] . '>', 3 );
112
            } elseif ( ! $job_qualify && empty( $rule_properties ) ) {
113
                // But if job does not qualify and rule properties are set, job qualifies as there is no matching rule for it yet
114
                // Fill-in the new target rule.
115
                $job_qualify = true;
116
117
                // Should we switch to path-base AUTO-rules? Conditions:
118
                // 1. forcepath option has to be enabled (off by default)
119
                // 2. request type should be (by default, but filterable) one of is_page (removed for now: woo_is_product or woo_is_product_category).
120
                if ( ( $ao_ccss_forcepath && in_array( $req_type, apply_filters( 'autoptimize_filter_ccss_coreenqueue_forcepathfortype', array( 'is_page' ) ) ) ) || apply_filters( 'autoptimize_filter_ccss_coreenqueue_ignorealltypes', false ) ) {
121
                    if ( '/' !== $req_path ) {
122
                        $target_rule = 'paths|' . $req_path;
123
                    } else {
124
                        // Exception; we don't want a path-based rule for "/" as that messes things up, hard-switch this to a type-based is_front_page rule.
125
                        $target_rule = 'types|' . 'is_front_page';
126
                    }
127
                } else {
128
                    $target_rule = 'types|' . $req_type;
129
                }
130
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Job submission QUALIFIED by MISSING rule for page type <' . $req_type . '> on path <' . $req_path . '>, new rule target is <' . $target_rule . '>', 3 );
131
            } else {
132
                // Or just log a job qualified by a matching rule.
133
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Job submission QUALIFIED by AUTO rule <' . $target_rule . '> with hash <' . $rule_properties['hash'] . '> and file <' . $rule_properties['file'] . '>', 3 );
134
            }
135
136
            // Submit job.
137
            if ( $job_qualify ) {
138
                if ( ! array_key_exists( $req_path, $ao_ccss_queue ) ) {
139
                    // This is a NEW job
140
                    // Merge job into the queue.
141
                    $ao_ccss_queue[ $req_path ] = $self->ao_ccss_define_job(
142
                        $req_path,
143
                        $target_rule,
144
                        $req_type,
145
                        $hash,
146
                        null,
147
                        null,
148
                        null,
149
                        null,
150
                        true
151
                    );
152
                    // Set update flag.
153
                    $queue_update = true;
154
                } else {
155
                    // This is an existing job
156
                    // The job is still NEW, most likely this is extra CSS file for the same page that needs a hash.
157
                    if ( 'NEW' == $ao_ccss_queue[ $req_path ]['jqstat'] ) {
158
                        // Add hash if it's not already in the job.
159
                        if ( ! in_array( $hash, $ao_ccss_queue[ $req_path ]['hashes'] ) ) {
160
                            // Push new hash to its array and update flag.
161
                            $queue_update = array_push( $ao_ccss_queue[ $req_path ]['hashes'], $hash );
0 ignored issues
show
$queue_update 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...
162
163
                            // Log job update.
164
                            autoptimizeCriticalCSSCore::ao_ccss_log( 'Hashes UPDATED on local job id <' . $ao_ccss_queue[ $req_path ]['ljid'] . '>, job status NEW, target rule <' . $ao_ccss_queue[ $req_path ]['rtarget'] . '>, hash added: ' . $hash, 3 );
165
166
                            // Return from here as the hash array is already updated.
167
                            return true;
168
                        }
169
                    } elseif ( 'NEW' != $ao_ccss_queue[ $req_path ]['jqstat'] && 'JOB_QUEUED' != $ao_ccss_queue[ $req_path ]['jqstat'] && 'JOB_ONGOING' != $ao_ccss_queue[ $req_path ]['jqstat'] ) {
170
                        // Allow requeuing jobs that are not NEW, JOB_QUEUED or JOB_ONGOING
171
                        // Merge new job keeping some previous job values.
172
                        $ao_ccss_queue[ $req_path ] = $self->ao_ccss_define_job(
173
                            $req_path,
174
                            $target_rule,
175
                            $req_type,
176
                            $hash,
177
                            $ao_ccss_queue[ $req_path ]['file'],
178
                            $ao_ccss_queue[ $req_path ]['jid'],
179
                            $ao_ccss_queue[ $req_path ]['jrstat'],
180
                            $ao_ccss_queue[ $req_path ]['jvstat'],
181
                            false
182
                        );
183
                        // Set update flag.
184
                        $queue_update = true;
185
                    }
186
                }
187
188
                if ( $queue_update ) {
189
                    // Persist the job to the queue and return.
190
                    $ao_ccss_queue_raw = json_encode( $ao_ccss_queue );
191
                    update_option( 'autoptimize_ccss_queue', $ao_ccss_queue_raw, false );
192
                    return true;
193
                } else {
194
                    // Or just return false if no job was added.
195
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'A job for path <' . $req_path . '> already exist with NEW or PENDING status, skipping job creation', 3 );
196
                    return false;
197
                }
198
            }
199
        }
200
    }
201
202
    public function ao_ccss_get_type() {
203
        // Get the type of a page
204
        // Attach the conditional tags array.
205
        global $ao_ccss_types;
206
        global $ao_ccss_forcepath;
207
208
        // By default, a page type is false.
209
        $page_type = false;
210
211
        // Iterates over the array to match a type.
212
        foreach ( $ao_ccss_types as $type ) {
213
            if ( is_404() ) {
214
                $page_type = 'is_404';
215
                break;
216
            } elseif ( is_front_page() ) {
217
                // identify frontpage immediately to avoid it also matching a CPT or template.
218
                $page_type = 'is_front_page';
219
                break;
220
            } elseif ( strpos( $type, 'custom_post_' ) !== false && ( ! $ao_ccss_forcepath || ! is_page() ) ) {
221
                // Match custom post types and not page or page not forced to path-based.
222
                if ( get_post_type( get_the_ID() ) === substr( $type, 12 ) ) {
223
                    $page_type = $type;
224
                    break;
225
                }
226
            } elseif ( strpos( $type, 'template_' ) !== false && ( ! $ao_ccss_forcepath || ! is_page() ) ) {
227
                // Match templates if not page or if page is not forced to path-based.
228
                if ( is_page_template( substr( $type, 9 ) ) ) {
229
                    $page_type = $type;
230
                    break;
231
                }
232
            } else {
233
                // Match all other existing types
234
                // but remove prefix to be able to check if the function exists & returns true.
235
                $_type = str_replace( array( 'woo_', 'bp_', 'bbp_', 'edd_' ), '', $type );
236
                if ( function_exists( $_type ) && call_user_func( $_type ) ) {
237
                    // Make sure we only return for one page, not for the "paged pages" (/page/2 ..).
238
                    if ( ! is_page() || ! is_paged() ) {
239
                        $page_type = $type;
240
                        break;
241
                    }
242
                }
243
            }
244
        }
245
246
        // Return the page type.
247
        return $page_type;
248
    }
249
250
    public function ao_ccss_define_job( $path, $target, $type, $hash, $file, $jid, $jrstat, $jvstat, $create ) {
0 ignored issues
show
The parameter $path is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
251
        // Define a job entry to be created or updated
252
        // Define commom job properties.
253
        $path            = array();
254
        $path['ljid']    = $this->ao_ccss_job_id();
255
        $path['rtarget'] = $target;
256
        $path['ptype']   = $type;
257
        $path['hashes']  = array( $hash );
258
        $path['hash']    = $hash;
259
        $path['file']    = $file;
260
        $path['jid']     = $jid;
261
        $path['jqstat']  = 'NEW';
262
        $path['jrstat']  = $jrstat;
263
        $path['jvstat']  = $jvstat;
264
        $path['jctime']  = microtime( true );
265
        $path['jftime']  = null;
266
267
        // Set operation requested.
268
        if ( $create ) {
269
            $operation = 'CREATED';
270
        } else {
271
            $operation = 'UPDATED';
272
        }
273
274
        // Log job creation.
275
        autoptimizeCriticalCSSCore::ao_ccss_log( 'Job ' . $operation . ' with local job id <' . $path['ljid'] . '> for target rule <' . $target . '>', 3 );
276
277
        return $path;
278
    }
279
280
    public function ao_ccss_job_id( $length = 6 ) {
281
        // Generate random strings for the local job ID
282
        // Based on https://stackoverflow.com/a/4356295 .
283
        $characters        = '0123456789abcdefghijklmnopqrstuvwxyz';
284
        $characters_length = strlen( $characters );
285
        $random_string     = 'j-';
286
        for ( $i = 0; $i < $length; $i++ ) {
287
            $random_string .= $characters[ rand( 0, $characters_length - 1 ) ];
288
        }
289
        return $random_string;
290
    }
291
292
    public function ao_ccss_ua() {
293
        // Check for criticalcss.com user agent.
294
        $agent = '';
295
        if ( isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
296
            $agent = $_SERVER['HTTP_USER_AGENT'];
297
        }
298
299
        // Check for UA and return TRUE when criticalcss.com is the detected UA, false when not.
300
        $rtn = strpos( $agent, AO_CCSS_URL );
301
        if ( 0 === $rtn ) {
302
            $rtn = true;
303
        } else {
304
            $rtn = false;
305
        }
306
        return ( $rtn );
307
    }
308
}
309