Completed
Push — master ( 8538b3...935035 )
by frank
02:00
created

autoptimizeCriticalCSSCron::ao_ccss_cleaning()   D

Complexity

Conditions 13
Paths 288

Size

Total Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
nc 288
nop 0
dl 0
loc 53
rs 4.6833
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Critical CSS Cron logic:
4
 * processes the queue, submitting jobs to criticalcss.com and retrieving generated CSS from criticalcss.com and saving rules.
5
 */
6
7
if ( ! defined( 'ABSPATH' ) ) {
8
    exit;
9
}
10
11
class autoptimizeCriticalCSSCron {
12
    public function __construct()
13
    {
14
        // fetch all options at once and populate them individually explicitely as globals.
15
        $all_options = autoptimizeCriticalCSSBase::fetch_options();
0 ignored issues
show
Bug introduced by
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...
16
        foreach ( $all_options as $_option => $_value ) {
0 ignored issues
show
Bug introduced by
The expression $all_options of type null is not traversable.
Loading history...
17
            global ${$_option};
18
            ${$_option} = $_value;
19
        }
20
21
        // Add queue control to a registered event.
22
        add_action( 'ao_ccss_queue', array( $this, 'ao_ccss_queue_control' ) );
23
        // Add cleaning job to a registered event.
24
        add_action( 'ao_ccss_maintenance', array( $this, 'ao_ccss_cleaning' ) );
25
    }
26
27
    public function ao_ccss_queue_control() {
28
        // The queue execution backend.
29
        global $ao_ccss_key;
30
        if ( ! isset( $ao_ccss_key ) || empty( $ao_ccss_key ) ) {
31
            // no key set, not processing the queue!
32
            autoptimizeCriticalCSSCore::ao_ccss_log( 'No key set, so not processing queue.', 3 );
33
            return;
34
        }
35
36
        /**
37
         * Provide a debug facility for the queue
38
         *    This debug facility provides a way to easily force some queue behaviors useful for development and testing.
39
         *    To enable this feature, create the file AO_CCSS_DIR . 'queue.json' with a JSON object like the one bellow:
40
         *
41
         *    {"enable":bool,"htcode":int,"status":0|"str","resultStatus ":0|"str","validationStatus":0|"str"}
42
         *
43
         *    Where values are:
44
         *    - enable                    : 0 or 1, enable or disable this debug facility straight from the file
45
         *    - htcode                    : 0 or any HTTP reponse code (e.g. 2xx, 4xx, 5xx) to force API responses
46
         *    - status                    : 0 or a valid value for 'status' (see 'Generating critical css - Job Status Types' in spec docs)
47
         *    - resultStatus        : 0 or a valid value for 'resultStatus' (see 'Appendix - Result status types' in the spec docs)
48
         *    - validationStatus: 0 or a valid value for 'validationStatus' (see 'Appendix - Validation status types' in the spec docs)
49
         *
50
         *    When properly set, queue will always finish a job with the declared settings above regardless of the real API responses.
51
         */
52
        $queue_debug = false;
53
        if ( file_exists( AO_CCSS_DEBUG ) ) {
54
            $qdobj_raw = file_get_contents( AO_CCSS_DEBUG );
55
            $qdobj     = json_decode( $qdobj_raw, true );
56
            if ( $qdobj ) {
57
                if ( 1 === $qdobj['enable'] ) {
58
                    $queue_debug = true;
59
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue operating in debug mode with the following settings: <' . $qdobj_raw . '>', 3 );
60
                }
61
            }
62
        }
63
64
        // Set some default values for $qdobj to avoid function call warnings.
65
        if ( ! $queue_debug ) {
66
            $qdobj['htcode'] = false;
0 ignored issues
show
Bug introduced by
The variable $qdobj does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
67
        }
68
69
        // Check if queue is already running.
70
        $queue_lock = false;
71
        if ( file_exists( AO_CCSS_LOCK ) ) {
72
            $queue_lock = true;
73
        }
74
75
        // Proceed with the queue if it's not already running.
76
        if ( ! $queue_lock ) {
77
78
            // Log queue start and create the lock file.
79
            autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue control started', 3 );
80
            if ( touch( AO_CCSS_LOCK ) ) {
81
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue control locked', 3 );
82
            }
83
84
            // Attach required variables.
85
            global $ao_ccss_queue;
86
            global $ao_ccss_rtimelimit;
87
88
            // Initialize counters.
89
            if ( $ao_ccss_rtimelimit == 0 ) {
90
                // no time limit set, let's go with 1000 seconds.
91
                $ao_ccss_rtimelimit = 1000;
92
            }
93
            $mt = time() + $ao_ccss_rtimelimit; // maxtime queue processing can run.
94
            $jc = 1; // job count number.
95
            $jr = 1; // jobs requests number.
96
            $jt = count( $ao_ccss_queue ); // number of jobs in queue.
97
98
            // Sort queue by ascending job status (e.g. ERROR, JOB_ONGOING, JOB_QUEUED, NEW...).
99
            array_multisort( array_column( $ao_ccss_queue, 'jqstat' ), $ao_ccss_queue ); // @codingStandardsIgnoreLine
0 ignored issues
show
Bug introduced by
array_column($ao_ccss_queue, 'jqstat') cannot be passed to array_multisort() as the parameter $arr expects a reference.
Loading history...
100
101
            // Iterates over the entire queue.
102
            foreach ( $ao_ccss_queue as $path => $jprops ) {
103
                // Prepare flags and target rule.
104
                $update      = false;
105
                $deljob      = false;
106
                $rule_update = false;
107
                $oldccssfile = false;
0 ignored issues
show
Unused Code introduced by
$oldccssfile 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...
108
                $trule       = explode( '|', $jprops['rtarget'] );
109
110
                // Log job count.
111
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Processing job ' . $jc . ' of ' . $jt . ' with id <' . $jprops['ljid'] . '> and status <' . $jprops['jqstat'] . '>', 3 );
112
113
                // Process NEW jobs.
114
                if ( 'NEW' == $jprops['jqstat'] ) {
115
116
                    // Log the new job.
117
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'Found NEW job with local ID <' . $jprops['ljid'] . '>, starting its queue processing', 3 );
118
119
                    // Compare job and rule hashes (if any).
120
                    $hash = $this->ao_ccss_diff_hashes( $jprops['ljid'], $jprops['hash'], $jprops['hashes'], $jprops['rtarget'] );
121
122
                    // If job hash is new or different of a previous one.
123
                    if ( $hash ) {
124
                        if ( $jr > 2 ) {
125
                            // we already posted 2 jobs to criticalcss.com, don't post more this run
126
                            // but we can keep on processing the queue to keep it tidy.
127
                            autoptimizeCriticalCSSCore::ao_ccss_log( 'Holding off on generating request for job with local ID <' . $jprops['ljid'] . '>, maximum number of POSTS reached.', 3 );
128
                            continue;
129
                        }
130
131
                        // Set job hash.
132
                        $jprops['hash'] = $hash;
133
134
                        // Dispatch the job generate request and increment request count.
135
                        $apireq = $this->ao_ccss_api_generate( $path, $queue_debug, $qdobj['htcode'] );
136
                        $jr++;
137
138
                        // NOTE: All the following conditions maps to the ones in admin_settings_queue.js.php.
139
                        if ( 'JOB_QUEUED' == $apireq['job']['status'] || 'JOB_ONGOING' == $apireq['job']['status'] ) {
140
                            // SUCCESS: request has a valid result.
141
                            // Update job properties.
142
                            $jprops['jid']    = $apireq['job']['id'];
143
                            $jprops['jqstat'] = $apireq['job']['status'];
144
                            autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> generate request successful, remote id <' . $jprops['jid'] . '>, status now is <' . $jprops['jqstat'] . '>', 3 );
145 View Code Duplication
                        } elseif ( 'STATUS_JOB_BAD' == $apireq['job']['status'] ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
146
                            // ERROR: concurrent requests
147
                            // Update job properties.
148
                            $jprops['jid']    = $apireq['job']['id'];
149
                            $jprops['jqstat'] = $apireq['job']['status'];
150
                            if ( $apireq['job']['error'] ) {
151
                                $jprops['jrstat'] = $apireq['job']['error'];
152
                            } else {
153
                                $jprops['jrstat'] = 'Baby did a bad bad thing';
154
                            }
155
                            $jprops['jvstat'] = 'NONE';
156
                            $jprops['jftime'] = microtime( true );
157
                            autoptimizeCriticalCSSCore::ao_ccss_log( 'Concurrent requests when processing job id <' . $jprops['ljid'] . '>, job status is now <' . $jprops['jqstat'] . '>', 3 );
158
                        } elseif ( 'INVALID_JWT_TOKEN' == $apireq['errorCode'] ) {
159
                            // ERROR: key validation
160
                            // Update job properties.
161
                            $jprops['jqstat'] = $apireq['errorCode'];
162
                            $jprops['jrstat'] = $apireq['error'];
163
                            $jprops['jvstat'] = 'NONE';
164
                            $jprops['jftime'] = microtime( true );
165
                            autoptimizeCriticalCSSCore::ao_ccss_log( 'API key validation error when processing job id <' . $jprops['ljid'] . '>, job status is now <' . $jprops['jqstat'] . '>', 3 );
166
                        } elseif ( empty( $apireq ) ) {
167
                            // ERROR: no response
168
                            // Update job properties.
169
                            $jprops['jqstat'] = 'NO_RESPONSE';
170
                            $jprops['jrstat'] = 'NONE';
171
                            $jprops['jvstat'] = 'NONE';
172
                            $jprops['jftime'] = microtime( true );
173
                            autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> request has no response, status now is <' . $jprops['jqstat'] . '>', 3 );
174
                        } else {
175
                            // UNKNOWN: unhandled generate exception
176
                            // Update job properties.
177
                            $jprops['jqstat'] = 'JOB_UNKNOWN';
178
                            $jprops['jrstat'] = 'NONE';
179
                            $jprops['jvstat'] = 'NONE';
180
                            $jprops['jftime'] = microtime( true );
181
                            autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> generate request has an UNKNOWN condition, status now is <' . $jprops['jqstat'] . '>, check log messages above for more information', 2 );
182
                            autoptimizeCriticalCSSCore::ao_ccss_log( 'Job response was: ' . json_encode( $apireq ), 3 );
183
                        }
184
                    } else {
185
                        // SUCCESS: Job hash is equal to a previous one, so it's done
186
                        // Update job status and finish time.
187
                        $jprops['jqstat'] = 'JOB_DONE';
188
                        $jprops['jftime'] = microtime( true );
189
                        autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> requires no further processing, status now is <' . $jprops['jqstat'] . '>', 3 );
190
                    }
191
192
                    // Set queue update flag.
193
                    $update = true;
194
195
                } elseif ( 'JOB_QUEUED' == $jprops['jqstat'] || 'JOB_ONGOING' == $jprops['jqstat'] ) {
196
                    // Process QUEUED and ONGOING jobs
197
                    // Log the pending job.
198
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'Found PENDING job with local ID <' . $jprops['ljid'] . '>, continuing its queue processing', 3 );
199
200
                    // Dispatch the job result request and increment request count.
201
                    $apireq = $this->ao_ccss_api_results( $jprops['jid'], $queue_debug, $qdobj['htcode'] );
202
203
                    // NOTE: All the following condigitons maps to the ones in admin_settings_queue.js.php
204
                    // Replace API response values if queue debugging is enabled and some value is set.
205
                    if ( $queue_debug ) {
206
                        if ( $qdobj['status'] ) {
207
                            $apireq['status'] = $qdobj['status'];
208
                        }
209
                        if ( $qdobj['resultStatus'] ) {
210
                            $apireq['resultStatus'] = $qdobj['resultStatus'];
211
                        }
212
                        if ( $qdobj['validationStatus'] ) {
213
                            $apireq['validationStatus'] = $qdobj['validationStatus'];
214
                        }
215
                    }
216
217
                    if ( 'JOB_QUEUED' == $apireq['status'] || 'JOB_ONGOING' == $apireq['status'] ) {
218
                        // SUCCESS: request has a valid result
219
                        // Process a PENDING job
220
                        // Update job properties.
221
                        $jprops['jqstat'] = $apireq['status'];
222
                        autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . '> unchanged', 3 );
223
                    } elseif ( 'JOB_DONE' == $apireq['status'] ) {
224
                        // Process a DONE job
225
                        // New resultStatus from ccss.com "HTML_404", consider as "GOOD" for now.
226
                        if ( 'HTML_404' == $apireq['resultStatus'] ) {
227
                            $apireq['resultStatus'] = 'GOOD';
228
                        }
229
230
                        if ( 'GOOD' == $apireq['resultStatus'] && ( 'GOOD' == $apireq['validationStatus'] || 'WARN' == $apireq['validationStatus'] ) ) {
231
                            // SUCCESS: GOOD job with GOOD or WARN validation
232
                            // Update job properties.
233
                            $jprops['file']   = $this->ao_ccss_save_file( $apireq['css'], $trule, false );
234
                            $jprops['jqstat'] = $apireq['status'];
235
                            $jprops['jrstat'] = $apireq['resultStatus'];
236
                            $jprops['jvstat'] = $apireq['validationStatus'];
237
                            $jprops['jftime'] = microtime( true );
238
                            $rule_update      = true;
239
                            autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . '>, file saved <' . $jprops['file'] . '>', 3 );
240
                        } elseif ( 'GOOD' == $apireq['resultStatus'] && ( 'BAD' == $apireq['validationStatus'] || 'SCREENSHOT_WARN_BLANK' == $apireq['validationStatus'] ) ) {
241
                            // SUCCESS: GOOD job with BAD or SCREENSHOT_WARN_BLANK validation
242
                            // Update job properties.
243
                            $jprops['jqstat'] = $apireq['status'];
244
                            $jprops['jrstat'] = $apireq['resultStatus'];
245
                            $jprops['jvstat'] = $apireq['validationStatus'];
246
                            $jprops['jftime'] = microtime( true );
247
                            if ( apply_filters( 'autoptimize_filter_ccss_save_review_rules', true ) ) {
248
                                $jprops['file']   = $this->ao_ccss_save_file( $apireq['css'], $trule, true );
249
                                $rule_update      = true;
250
                                autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . ', file saved <' . $jprops['file'] . '> but requires REVIEW', 3 );
251
                            } else {
252
                                autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . ', file not saved because it required REVIEW.', 3 );
253
                            }
254
                        } elseif ( 'GOOD' != $apireq['resultStatus'] && ( 'GOOD' != $apireq['validationStatus'] || 'WARN' != $apireq['validationStatus'] || 'BAD' != $apireq['validationStatus'] || 'SCREENSHOT_WARN_BLANK' != $apireq['validationStatus'] ) ) {
255
                            // ERROR: no GOOD, WARN or BAD results
256
                            // Update job properties.
257
                            $jprops['jqstat'] = $apireq['status'];
258
                            $jprops['jrstat'] = $apireq['resultStatus'];
259
                            $jprops['jvstat'] = $apireq['validationStatus'];
260
                            $jprops['jftime'] = microtime( true );
261
                            autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful but job FAILED, status now is <' . $jprops['jqstat'] . '>', 3 );
262
                            $apireq['css'] = '/* critical css removed for DEBUG logging purposes */';
263
                            autoptimizeCriticalCSSCore::ao_ccss_log( 'Job response was: ' . json_encode( $apireq ), 3 );
264
                        } else {
265
                            // UNKNOWN: unhandled JOB_DONE exception
266
                            // Update job properties.
267
                            $jprops['jqstat'] = 'JOB_UNKNOWN';
268
                            $jprops['jrstat'] = $apireq['resultStatus'];
269
                            $jprops['jvstat'] = $apireq['validationStatus'];
270
                            $jprops['jftime'] = microtime( true );
271
                            autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful but job is UNKNOWN, status now is <' . $jprops['jqstat'] . '>', 2 );
272
                            $apireq['css'] = '/* critical css removed for DEBUG logging purposes */';
273
                            autoptimizeCriticalCSSCore::ao_ccss_log( 'Job response was: ' . json_encode( $apireq ), 3 );
274
                        }
275 View Code Duplication
                    } elseif ( 'JOB_FAILED' == $apireq['job']['status'] || 'STATUS_JOB_BAD' == $apireq['job']['status'] ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
276
                        // ERROR: failed job
277
                        // Update job properties.
278
                        $jprops['jqstat'] = $apireq['job']['status'];
279
                        if ( $apireq['job']['error'] ) {
280
                            $jprops['jrstat'] = $apireq['job']['error'];
281
                        } else {
282
                            $jprops['jrstat'] = 'Baby did a bad bad thing';
283
                        }
284
                        $jprops['jvstat'] = 'NONE';
285
                        $jprops['jftime'] = microtime( true );
286
                        autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful but job FAILED, status now is <' . $jprops['jqstat'] . '>', 3 );
287
                    } elseif ( 'This css no longer exists. Please re-generate it.' == $apireq['error'] ) {
288
                        // ERROR: CSS doesn't exist
289
                        // Update job properties.
290
                        $jprops['jqstat'] = 'NO_CSS';
291
                        $jprops['jrstat'] = $apireq['error'];
292
                        $jprops['jvstat'] = 'NONE';
293
                        $jprops['jftime'] = microtime( true );
294
                        autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful but job FAILED, status now is <' . $jprops['jqstat'] . '>', 3 );
295
                    } elseif ( empty( $apireq ) ) {
296
                        // ERROR: no response
297
                        // Update job properties.
298
                        $jprops['jqstat'] = 'NO_RESPONSE';
299
                        $jprops['jrstat'] = 'NONE';
300
                        $jprops['jvstat'] = 'NONE';
301
                        $jprops['jftime'] = microtime( true );
302
                        autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> request has no response, status now is <' . $jprops['jqstat'] . '>', 3 );
303
                    } else {
304
                        // UNKNOWN: unhandled results exception
305
                        // Update job properties.
306
                        $jprops['jqstat'] = 'JOB_UNKNOWN';
307
                        $jprops['jrstat'] = 'NONE';
308
                        $jprops['jvstat'] = 'NONE';
309
                        $jprops['jftime'] = microtime( true );
310
                        autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request has an UNKNOWN condition, status now is <' . $jprops['jqstat'] . '>, check log messages above for more information', 2 );
311
                    }
312
313
                    // Set queue update flag.
314
                    $update = true;
315
                }
316
317
                // Mark DONE jobs for removal.
318
                if ( 'JOB_DONE' == $jprops['jqstat'] ) {
319
                    $update = true;
320
                    $deljob = true;
321
                }
322
323
                // Persist updated queue object.
324
                if ( $update ) {
325
                    if ( ! $deljob ) {
326
                        // Update properties of a NEW or PENDING job...
327
                        $ao_ccss_queue[ $path ] = $jprops;
328
                    } else {
329
                        // ...or remove the DONE job.
330
                        unset( $ao_ccss_queue[ $path ] );
331
                        autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> is DONE and was removed from the queue', 3 );
332
                    }
333
334
                    // Update queue object.
335
                    $ao_ccss_queue_raw = json_encode( $ao_ccss_queue );
336
                    update_option( 'autoptimize_ccss_queue', $ao_ccss_queue_raw, false );
337
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue updated by job id <' . $jprops['ljid'] . '>', 3 );
338
339
                    // Update target rule.
340
                    if ( $rule_update ) {
341
                        $this->ao_ccss_rule_update( $jprops['ljid'], $jprops['rtarget'], $jprops['file'], $jprops['hash'] );
342
                        autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> updated the target rule <' . $jprops['rtarget'] . '>', 3 );
343
                    }
344
                } else {
345
                    // Or log no queue action.
346
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'Nothing to do on this job', 3 );
347
                }
348
349
                // Break the loop if request time limit is (almost exceeded).
350
                if ( time() > $mt ) {
351
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'The time limit of ' . $ao_ccss_rtimelimit . ' seconds was exceeded, queue control must finish now', 3 );
352
                    break;
353
                }
354
355
                // Increment job counter.
356
                $jc++;
357
            }
358
359
            // Remove the lock file and log the queue end.
360
            if ( file_exists( AO_CCSS_LOCK ) ) {
361
                unlink( AO_CCSS_LOCK );
362
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue control unlocked', 3 );
363
            }
364
            autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue control finished', 3 );
365
366
            // Log that queue is locked.
367
        } else {
368
            autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue is already running, skipping the attempt to run it again', 3 );
369
        }
370
    }
371
372
    public function ao_ccss_diff_hashes( $ljid, $hash, $hashes, $rule ) {
0 ignored issues
show
Unused Code introduced by
The parameter $hash 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...
373
        // Compare job hashes
374
        // STEP 1: update job hashes.
375
        if ( 1 == count( $hashes ) ) {
376
            // Job with a single hash
377
            // Set job hash.
378
            $hash = $hashes[0];
379
            autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $ljid . '> updated with SINGLE hash <' . $hash . '>', 3 );
380
        } else {
381
            // Job with multiple hashes
382
            // Loop through hashes to concatenate them.
383
            $nhash = '';
384
            foreach ( $hashes as $shash ) {
385
                $nhash .= $shash;
386
            }
387
388
            // Set job hash.
389
            $hash = md5( $nhash );
390
            autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $ljid . '> updated with a COMPOSITE hash <' . $hash . '>', 3 );
391
        }
392
393
        // STEP 2: compare job to existing jobs to prevent double submission for same type+hash.
394
        global $ao_ccss_queue;
395
396
        foreach ( $ao_ccss_queue as $queue_item ) {
397
            autoptimizeCriticalCSSCore::ao_ccss_log( 'Comparing <' . $rule . $hash . '> with <' . $queue_item['rtarget'] . $queue_item['hash'] . '>', 3 );
398
            if ( $queue_item['hash'] == $hash && $queue_item['rtarget'] == $rule && in_array( $queue_item['jqstat'], array( 'JOB_QUEUED', 'JOB_ONGOING', 'JOB_DONE' ) ) ) {
399
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $ljid . '> matches the already pending job <' . $queue_item['ljid'] . '>', 3 );
400
                return false;
401
            }
402
        }
403
404
        // STEP 3: compare job and existing rule (if any) hashes
405
        // Attach required arrays.
406
        global $ao_ccss_rules;
407
408
        // Prepare rule variables.
409
        $trule = explode( '|', $rule );
410
        $srule = $ao_ccss_rules[ $trule[0] ][ $trule[1] ];
411
412
        // Check if a MANUAL rule exist and return false.
413
        if ( ! empty( $srule ) && ( 0 == $srule['hash'] && 0 != $srule['file'] ) ) {
414
            autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $ljid . '> matches the MANUAL rule <' . $trule[0] . '|' . $trule[1] . '>', 3 );
415
            return false;
416
        } elseif ( ! empty( $srule ) ) {
417
            // Check if an AUTO rule exist.
418
            if ( $hash === $srule['hash'] && is_file( AO_CCSS_DIR . $srule['file'] ) && 0 != filesize( AO_CCSS_DIR . $srule['file'] ) ) {
419
                // Check if job hash matches rule, if the CCSS file exists said file is not empty and return FALSE is so.
420
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $ljid . '> with hash <' . $hash . '> MATCH the one in rule <' . $trule[0] . '|' . $trule[1] . '>', 3 );
421
                return false;
422
            } else {
423
                // Or return the new hash if they differ.
424
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $ljid . '> with hash <' . $hash . '> DOES NOT MATCH the one in rule <' . $trule[0] . '|' . $trule[1] . '> or rule\'s CCSS file was invalid.', 3 );
425
                return $hash;
426
            }
427
        } else {
428
            // Or just return the hash if no rule exist yet.
429
            autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $ljid . '> with hash <' . $hash . '> has no rule yet', 3 );
430
            return $hash;
431
        }
432
    }
433
434
    public function ao_ccss_api_generate( $path, $debug, $dcode ) {
435
        // POST jobs to criticalcss.com and return responses
436
        // Get key and key status.
437
        global $ao_ccss_key;
438
        global $ao_ccss_keyst;
439
        $key        = $ao_ccss_key;
440
        $key_status = $ao_ccss_keyst;
441
442
        // Prepare full URL to request.
443
        global $ao_ccss_noptimize;
444
445
        $site_host = get_site_url();
446
        $site_path = parse_url( $site_host, PHP_URL_PATH );
447
448
        if ( ! empty( $site_path ) ) {
449
            $site_host = str_replace( $site_path, '', $site_host );
450
        }
451
452
        // Logic to bind to one domain to avoid site clones of sites would
453
        // automatically begin spawning requests to criticalcss.com which has
454
        // a per domain cost.
455
        global $ao_ccss_domain;
456
        if ( empty( $ao_ccss_domain ) ) {
457
            // first request being done, update option to allow future requests are only allowed if from same domain.
458
            update_option( 'autoptimize_ccss_domain', str_rot13( $site_host ) );
459
        } elseif ( trim( $ao_ccss_domain, '\'"' ) !== 'none' && parse_url( $site_host, PHP_URL_HOST ) !== parse_url( $ao_ccss_domain, PHP_URL_HOST ) && apply_filters( 'autoptimize_filter_ccss_bind_domain', true ) ) {
460
            // not the same domain, log as error and return without posting to criticalcss.com.
461
            autoptimizeCriticalCSSCore::ao_ccss_log( 'Request for domain ' . $site_host . ' does not match bound domain ' . $ao_ccss_domain . ' so not proceeding.', 2 );
462
            return false;
463
        }
464
465
        $src_url = $site_host . $path;
466
467
        // Avoid AO optimizations if required by config or avoid lazyload if lazyload is active in AO.
468 View Code Duplication
        if ( ! empty( $ao_ccss_noptimize ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
469
            $src_url .= '?ao_noptirocket=1';
470
        } elseif ( class_exists( 'autoptimizeImages', false ) && autoptimizeImages::should_lazyload_wrapper() ) {
471
            $src_url .= '?ao_nolazy=1';
472
        }
473
474
        $src_url = apply_filters( 'autoptimize_filter_ccss_cron_srcurl', $src_url );
475
476
        // Initialize request body.
477
        $body           = array();
478
        $body['url']    = $src_url;
479
        $body['aff']    = 1;
480
        $body['aocssv'] = AO_CCSS_VER;
481
482
        // Prepare and add viewport size to the body if available.
483
        $viewport = autoptimizeCriticalCSSCore::ao_ccss_viewport();
484
        if ( ! empty( $viewport['w'] ) && ! empty( $viewport['h'] ) ) {
485
            $body['width']  = $viewport['w'];
486
            $body['height'] = $viewport['h'];
487
        }
488
489
        // Prepare and add forceInclude to the body if available.
490
        global $ao_ccss_finclude;
491
        $finclude = $this->ao_ccss_finclude( $ao_ccss_finclude );
492
        if ( ! empty( $finclude ) ) {
493
            $body['forceInclude'] = $finclude;
494
        }
495
496
        // Add filter to allow the body array to be altered (e.g. to add customPageHeaders).
497
        $body = apply_filters( 'autoptimize_ccss_cron_api_generate_body', $body );
498
499
        // Body must be json and log it.
500
        $body = json_encode( $body );
501
        autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request body is ' . $body, 3 );
502
503
        // Prepare the request.
504
        $url  = esc_url_raw( AO_CCSS_API . 'generate?aover=' . AO_CCSS_VER );
505
        $args = array(
506
            'headers' => array(
507
                'User-Agent'    => 'Autoptimize v' . AO_CCSS_VER,
508
                'Content-type'  => 'application/json; charset=utf-8',
509
                'Authorization' => 'JWT ' . $key,
510
                'Connection'    => 'close',
511
            ),
512
            'body'    => $body,
513
        );
514
515
        // Dispatch the request and store its response code.
516
        $req  = wp_safe_remote_post( $url, $args );
517
        $code = wp_remote_retrieve_response_code( $req );
518
        $body = json_decode( wp_remote_retrieve_body( $req ), true );
519
520
        if ( $debug && $dcode ) {
521
            // If queue debug is active, change response code.
522
            $code = $dcode;
523
        }
524
525
        if ( 200 == $code ) {
526
            // Response code is OK.
527
            // Workaround criticalcss.com non-RESTful reponses.
528
            if ( 'JOB_QUEUED' == $body['job']['status'] || 'JOB_ONGOING' == $body['job']['status'] || 'STATUS_JOB_BAD' == $body['job']['status'] ) {
529
                // Log successful and return encoded request body.
530
                autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied successfully', 3 );
531
532
                // This code also means the key is valid, so cache key status for 24h if not already cached.
533
                if ( ( ! $key_status || 2 != $key_status ) && $key ) {
534
                    update_option( 'autoptimize_ccss_keyst', 2 );
535
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: API key is valid, updating key status', 3 );
536
                }
537
538
                // Return the request body.
539
                return $body;
540 View Code Duplication
            } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
541
                // Log successful requests with invalid reponses.
542
                autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied with code <' . $code . '> and an UNKNOWN error condition, body follows...', 2 );
543
                autoptimizeCriticalCSSCore::ao_ccss_log( print_r( $body, true ), 2 );
544
                return $body;
545
            }
546
        } else {
547
            // Response code is anything else.
548
            // Log failed request with a valid response code and return body.
549
            if ( $code ) {
550
                autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied with error code <' . $code . '>, body follows...', 2 );
551
                autoptimizeCriticalCSSCore::ao_ccss_log( print_r( $body, true ), 2 );
552
553
                if ( 401 == $code ) {
554
                    // If request is unauthorized, also clear key status.
555
                    update_option( 'autoptimize_ccss_keyst', 1 );
556
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: API key is invalid, updating key status', 3 );
557
                }
558
559
                // Return the request body.
560
                return $body;
561 View Code Duplication
            } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
562
                // Log failed request with no response and return false.
563
                autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: POST generate request for path <' . $src_url . '> has no response, this could be a service timeout', 2 );
564
                if ( is_wp_error( $req ) ) {
565
                    autoptimizeCriticalCSSCore::ao_ccss_log( $req->get_error_message(), 2 );
566
                }
567
568
                return false;
569
            }
570
        }
571
    }
572
573
    public function ao_ccss_api_results( $jobid, $debug, $dcode ) {
574
        // GET jobs from criticalcss.com and return responses
575
        // Get key.
576
        global $ao_ccss_key;
577
        $key = $ao_ccss_key;
578
579
        // Prepare the request.
580
        $url  = AO_CCSS_API . 'results?resultId=' . $jobid;
581
        $args = array(
582
            'headers' => array(
583
                'User-Agent'    => 'Autoptimize CriticalCSS Power-Up v' . AO_CCSS_VER,
584
                'Authorization' => 'JWT ' . $key,
585
                'Connection'    => 'close',
586
            ),
587
        );
588
589
        // Dispatch the request and store its response code.
590
        $req  = wp_safe_remote_get( $url, $args );
591
        $code = wp_remote_retrieve_response_code( $req );
592
        $body = json_decode( wp_remote_retrieve_body( $req ), true );
593
594
        if ( $debug && $dcode ) {
595
            // If queue debug is active, change response code.
596
            $code = $dcode;
597
        }
598
599
        if ( 200 == $code ) {
600
            // Response code is OK.
601
            if ( is_array( $body ) && ( array_key_exists( 'status', $body ) || array_key_exists( 'job', $body ) ) && ( 'JOB_QUEUED' == $body['status'] || 'JOB_ONGOING' == $body['status'] || 'JOB_DONE' == $body['status'] || 'JOB_FAILED' == $body['status'] || 'JOB_UNKNOWN' == $body['status'] || 'STATUS_JOB_BAD' == $body['job']['status'] ) ) {
602
                // Workaround criticalcss.com non-RESTful reponses
603
                // Log successful and return encoded request body.
604
                autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> replied successfully', 3 );
605
                return $body;
606
            } elseif ( is_array( $body ) && ( array_key_exists( 'error', $body ) && 'This css no longer exists. Please re-generate it.' == $body['error'] ) ) {
607
                // Handle no CSS reply
608
                // Log no CSS error and return encoded request body.
609
                autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> replied successfully but the CSS for it does not exist anymore', 3 );
610
                return $body;
611 View Code Duplication
            } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
612
                // Log failed request and return false.
613
                autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> replied with code <' . $code . '> and an UNKNOWN error condition, body follows...', 2 );
614
                autoptimizeCriticalCSSCore::ao_ccss_log( print_r( $body, true ), 2 );
615
                return false;
616
            }
617
        } else {
618
            // Response code is anything else
619
            // Log failed request with a valid response code and return body.
620
            if ( $code ) {
621
                autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> replied with error code <' . $code . '>, body follows...', 2 );
622
                autoptimizeCriticalCSSCore::ao_ccss_log( print_r( $body, true ), 2 );
623
                if ( 401 == $code ) {
624
                    // If request is unauthorized, also clear key status.
625
                    update_option( 'autoptimize_ccss_keyst', 1 );
626
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: API key is invalid, updating key status', 3 );
627
                }
628
629
                // Return the request body.
630
                return $body;
631
            } else {
632
                // Log failed request with no response and return false.
633
                autoptimizeCriticalCSSCore::ao_ccss_log( 'criticalcss.com: GET results request for remote job id <' . $jobid . '> has no response, this could be a service timeout', 2 );
634
                return false;
635
            }
636
        }
637
    }
638
639
    public function ao_ccss_save_file( $ccss, $target, $review ) {
640
        // Save critical CSS into the filesystem and return its filename
641
        // Prepare review mark.
642
        if ( $review ) {
643
            $rmark = '_R';
644
        } else {
645
            $rmark = '';
646
        }
647
648
        // Prepare target rule, filename and content.
649
        $filename = false;
650
        $content  = $ccss;
651
652
        if ( autoptimizeCriticalCSSCore::ao_ccss_check_contents( $content ) ) {
653
            // Sanitize content, set filename and try to save file.
654
            $file     = AO_CCSS_DIR . 'ccss_' . md5( $ccss . $target[1] ) . $rmark . '.css';
655
            $status   = file_put_contents( $file, $content, LOCK_EX );
656
            $filename = pathinfo( $file, PATHINFO_BASENAME );
657
            autoptimizeCriticalCSSCore::ao_ccss_log( 'Critical CSS file for the rule <' . $target[0] . '|' . $target[1] . '> was saved as <' . $filename . '>, size in bytes is <' . $status . '>', 3 );
658
659
            if ( ! $status ) {
660
                // If file has not been saved, reset filename.
661
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Critical CSS file <' . $filename . '> could not be not saved', 2 );
662
                $filename = false;
663
                return $filename;
664
            }
665
        } else {
666
            autoptimizeCriticalCSSCore::ao_ccss_log( 'Critical CSS received did not pass content check', 2 );
667
            return $filename;
668
        }
669
670
        // Remove old critical CSS if a previous one existed in the rule and if that file exists in filesystem
671
        // NOTE: out of scope critical CSS file removal (issue #5)
672
        // Attach required arrays.
673
        global $ao_ccss_rules;
674
675
        // Prepare rule variables.
676
        $srule   = $ao_ccss_rules[ $target[0] ][ $target[1] ];
677
        $oldfile = $srule['file'];
678
679
        if ( $oldfile && $oldfile !== $filename ) {
680
            $delfile = AO_CCSS_DIR . $oldfile;
681
            if ( file_exists( $delfile ) ) {
682
                $unlinkst = unlink( $delfile );
683
                if ( $unlinkst ) {
684
                    autoptimizeCriticalCSSCore::ao_ccss_log( 'A previous critical CSS file <' . $oldfile . '> was removed for the rule <' . $target[0] . '|' . $target[1] . '>', 3 );
685
                }
686
            }
687
        }
688
689
        // Return filename or false.
690
        return $filename;
691
    }
692
693
    public function ao_ccss_rule_update( $ljid, $srule, $file, $hash ) {
694
        // Update or create a rule
695
        // Attach required arrays.
696
        global $ao_ccss_rules;
697
698
        // Prepare rule variables.
699
        $trule  = explode( '|', $srule );
700
        $rule   = $ao_ccss_rules[ $trule[0] ][ $trule[1] ];
701
        $action = false;
702
        $rtype  = '';
703
704
        if ( 0 === $rule['hash'] && 0 !== $rule['file'] ) {
705
            // manual rule, don't ever overwrite.
706
            $action = 'NOT UPDATED';
707
            $rtype  = 'MANUAL';
708
        } elseif ( 0 === $rule['hash'] && 0 === $rule['file'] ) {
709
            // If this is an user created AUTO rule with no hash and file yet, update its hash and filename
710
            // Set rule hash, file and action flag.
711
            $rule['hash'] = $hash;
712
            $rule['file'] = $file;
713
            $action       = 'UPDATED';
714
            $rtype        = 'AUTO';
715
        } elseif ( 0 !== $rule['hash'] && ctype_alnum( $rule['hash'] ) ) {
716
            // If this is an genuine AUTO rule, update its hash and filename
717
            // Set rule hash, file and action flag.
718
            $rule['hash'] = $hash;
719
            $rule['file'] = $file;
720
            $action       = 'UPDATED';
721
            $rtype        = 'AUTO';
722
        } else {
723
            // If rule doesn't exist, create an AUTO rule
724
            // AUTO rules were only for types, but will now also work for paths.
725
            if ( ( 'types' == $trule[0] || 'paths' == $trule[0] ) && ! empty( $trule[1] ) ) {
726
                // Set rule hash and file and action flag.
727
                $rule['hash'] = $hash;
728
                $rule['file'] = $file;
729
                $action       = 'CREATED';
730
                $rtype        = 'AUTO';
731
            } else {
732
                // Log that no rule was created.
733
                autoptimizeCriticalCSSCore::ao_ccss_log( 'Exception, no AUTO rule created', 3 );
734
            }
735
        }
736
737
        if ( $action ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $action of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
738
            // If a rule creation/update is required, persist updated rules object.
739
            $ao_ccss_rules[ $trule[0] ][ $trule[1] ] = $rule;
740
            $ao_ccss_rules_raw                       = json_encode( $ao_ccss_rules );
741
            update_option( 'autoptimize_ccss_rules', $ao_ccss_rules_raw );
742
            autoptimizeCriticalCSSCore::ao_ccss_log( 'Target rule <' . $srule . '> of type <' . $rtype . '> was ' . $action . ' for job id <' . $ljid . '>', 3 );
743
        } else {
744
            autoptimizeCriticalCSSCore::ao_ccss_log( 'No rule action required', 3 );
745
        }
746
    }
747
748
    function ao_ccss_finclude( $finclude_raw ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
749
        // Prepare forceInclude object.
750
        if ( ! empty( $finclude_raw ) ) {
751
            // If there are any content
752
            // Convert raw string into arra and initialize the returning object.
753
            $fincludes = explode( ',', $finclude_raw );
754
            $finclude  = array();
755
756
            // Interacts over every rule.
757
            $i = 0;
758
            foreach ( $fincludes as $include ) {
759
                // Trim leading and trailing whitespaces.
760
                $include = trim( $include );
761
762
                if ( substr( $include, 0, 2 ) === '//' ) {
763
                    // Regex rule
764
                    // Format value as required.
765
                    $include = str_replace( '//', '/', $include );
766
                    $include = $include . '/i';
767
768
                    // Store regex object.
769
                    $finclude[ $i ]['type']  = 'RegExp';
770
                    $finclude[ $i ]['value'] = $include;
771
                } else {
772
                    // Simple value rule.
773
                    $finclude[ $i ]['value'] = $include;
774
                }
775
776
                $i++;
777
            }
778
779
            // Return forceInclude object.
780
            return $finclude;
781
        } else {
782
            // Or just return false if empty.
783
            return false;
784
        }
785
    }
786
787
    public function ao_ccss_cleaning() {
788
        // Perform plugin maintenance
789
        // Truncate log file >= 1MB .
790
        if ( file_exists( AO_CCSS_LOG ) ) {
791
            if ( filesize( AO_CCSS_LOG ) >= 1048576 ) {
792
                $logfile = fopen( AO_CCSS_LOG, 'w' );
793
                fclose( $logfile );
794
            }
795
        }
796
797
        // Remove lock file.
798
        if ( file_exists( AO_CCSS_LOCK ) ) {
799
            unlink( AO_CCSS_LOCK );
800
        }
801
802
        // Make sure queue processing is scheduled, recreate if not.
803
        if ( ! wp_next_scheduled( 'ao_ccss_queue' ) ) {
804
            wp_schedule_event( time(), apply_filters( 'ao_ccss_queue_schedule', 'ao_ccss' ), 'ao_ccss_queue' );
805
        }
806
807
        // Queue cleaning.
808
        global $ao_ccss_queue;
809
        $queue_purge_threshold = 100;
810
        $queue_purge_age       = 24 * 60 * 60;
811
        $queue_length          = count( $ao_ccss_queue );
812
        $timestamp_yesterday   = microtime( true ) - $queue_purge_age;
813
        $remove_old_new        = false;
814
        $queue_altered         = false;
815
816
        if ( $queue_length > $queue_purge_threshold ) {
817
            $remove_old_new = true;
818
        }
819
820
        foreach ( $ao_ccss_queue as $path => $job ) {
821
            if ( ( $remove_old_new && 'NEW' == $job['jqstat'] && $job['jctime'] < $timestamp_yesterday ) || in_array( $job['jqstat'], array( 'JOB_FAILED', 'STATUS_JOB_BAD', 'NO_CSS', 'NO_RESPONSE' ) ) ) {
822
                unset( $ao_ccss_queue[ $path ] );
823
                $queue_altered = true;
824
            }
825
        }
826
827
        // save queue to options!
828
        if ( $queue_altered ) {
829
            $ao_ccss_queue_raw = json_encode( $ao_ccss_queue );
830
            update_option( 'autoptimize_ccss_queue', $ao_ccss_queue_raw, false );
831
            autoptimizeCriticalCSSCore::ao_ccss_log( 'Queue cleaning done.', 3 );
832
        }
833
834
        // re-check key if invalid.
835
        global $ao_ccss_keyst;
836
        if ( 1 == $ao_ccss_keyst ) {
837
            $this->ao_ccss_api_generate( '', '', '' );
838
        }
839
    }
840
}
841