Completed
Push — master ( 81fe1f...7cc981 )
by frank
02:39
created

CSSmin::run()   C

Complexity

Conditions 11
Paths 13

Size

Total Lines 91
Code Lines 39

Duplication

Lines 9
Ratio 9.89 %

Importance

Changes 0
Metric Value
cc 11
eloc 39
nc 13
nop 2
dl 9
loc 91
rs 5.2653
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
/*!
4
 * cssmin.php v2.4.8-4
5
 * Author: Tubal Martin - http://tubalmartin.me/
6
 * Repo: https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port
7
 *
8
 * This is a PHP port of the CSS minification tool distributed with YUICompressor,
9
 * itself a port of the cssmin utility by Isaac Schlueter - http://foohack.com/
10
 * Permission is hereby granted to use the PHP version under the same
11
 * conditions as the YUICompressor.
12
 */
13
14
/*!
15
 * YUI Compressor
16
 * http://developer.yahoo.com/yui/compressor/
17
 * Author: Julien Lecomte - http://www.julienlecomte.net/
18
 * Copyright (c) 2013 Yahoo! Inc. All rights reserved.
19
 * The copyrights embodied in the content of this file are licensed
20
 * by Yahoo! Inc. under the BSD (revised) open source license.
21
 */
22
23
class CSSmin
24
{
25
    const NL = '___YUICSSMIN_PRESERVED_NL___';
26
    const TOKEN = '___YUICSSMIN_PRESERVED_TOKEN_';
27
    const COMMENT = '___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_';
28
    const CLASSCOLON = '___YUICSSMIN_PSEUDOCLASSCOLON___';
29
    const QUERY_FRACTION = '___YUICSSMIN_QUERY_FRACTION___';
30
31
    private $comments;
32
    private $preserved_tokens;
33
    private $memory_limit;
34
    private $max_execution_time;
35
    private $pcre_backtrack_limit;
36
    private $pcre_recursion_limit;
37
    private $raise_php_limits;
38
39
    /**
40
     * @param bool|int $raise_php_limits
41
     * If true, PHP settings will be raised if needed
42
     */
43
    public function __construct($raise_php_limits = TRUE)
44
    {
45
        // Set suggested PHP limits
46
        $this->memory_limit = 128 * 1048576; // 128MB in bytes
47
        $this->max_execution_time = 60; // 1 min
48
        $this->pcre_backtrack_limit = 1000 * 1000;
49
        $this->pcre_recursion_limit =  500 * 1000;
50
51
        $this->raise_php_limits = (bool) $raise_php_limits;
52
    }
53
54
    /**
55
     * Minify a string of CSS
56
     * @param string $css
57
     * @param int|bool $linebreak_pos
58
     * @return string
59
     */
60
    public function run($css = '', $linebreak_pos = FALSE)
61
    {
62
        if (empty($css)) {
63
            return '';
64
        }
65
66
        if ($this->raise_php_limits) {
67
            $this->do_raise_php_limits();
68
        }
69
70
        $this->comments = array();
71
        $this->preserved_tokens = array();
72
73
        $start_index = 0;
74
        $length = strlen($css);
75
76
        $css = $this->extract_data_urls($css);
77
78
        // collect all comment blocks...
79
        while (($start_index = $this->index_of($css, '/*', $start_index)) >= 0) {
80
            $end_index = $this->index_of($css, '*/', $start_index + 2);
81
            if ($end_index < 0) {
82
                $end_index = $length;
83
            }
84
            $comment_found = $this->str_slice($css, $start_index + 2, $end_index);
85
            $this->comments[] = $comment_found;
86
            $comment_preserve_string = self::COMMENT . (count($this->comments) - 1) . '___';
87
            $css = $this->str_slice($css, 0, $start_index + 2) . $comment_preserve_string . $this->str_slice($css, $end_index);
88
            // Set correct start_index: Fixes issue #2528130
89
            $start_index = $end_index + 2 + strlen($comment_preserve_string) - strlen($comment_found);
90
        }
91
92
        // preserve strings so their content doesn't get accidentally minified
93
        $css = preg_replace_callback('/(?:"(?:[^\\\\"]|\\\\.|\\\\)*")|'."(?:'(?:[^\\\\']|\\\\.|\\\\)*')/S", array($this, 'replace_string'), $css);
94
95
        // Let's divide css code in chunks of 5.000 chars aprox.
96
        // Reason: PHP's PCRE functions like preg_replace have a "backtrack limit"
97
        // of 100.000 chars by default (php < 5.3.7) so if we're dealing with really
98
        // long strings and a (sub)pattern matches a number of chars greater than
99
        // the backtrack limit number (i.e. /(.*)/s) PCRE functions may fail silently
100
        // returning NULL and $css would be empty.
101
        $charset = '';
102
        $charset_regexp = '/(@charset)( [^;]+;)/i';
103
        $css_chunks = array();
104
        $css_chunk_length = 5000; // aprox size, not exact
105
        $start_index = 0;
106
        $i = $css_chunk_length; // save initial iterations
107
        $l = strlen($css);
108
109
110
        // if the number of characters is 5000 or less, do not chunk
111
        if ($l <= $css_chunk_length) {
112
            $css_chunks[] = $css;
113
        } else {
114
            // chunk css code securely
115
            while ($i < $l) {
116
                $i += 50; // save iterations
117
                if ($l - $start_index <= $css_chunk_length || $i >= $l) {
118
                    $css_chunks[] = $this->str_slice($css, $start_index);
119
                    break;
120
                }
121
                if ($css[$i - 1] === '}' && $i - $start_index > $css_chunk_length) {
122
                    // If there are two ending curly braces }} separated or not by spaces,
123
                    // join them in the same chunk (i.e. @media blocks)
124
                    $next_chunk = substr($css, $i);
125
                    if (preg_match('/^\s*\}/', $next_chunk)) {
126
                        $i = $i + $this->index_of($next_chunk, '}') + 1;
127
                    }
128
129
                    $css_chunks[] = $this->str_slice($css, $start_index, $i);
130
                    $start_index = $i;
131
                }
132
            }
133
        }
134
135
        // Minify each chunk
136 View Code Duplication
        for ($i = 0, $n = count($css_chunks); $i < $n; $i++) {
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...
137
            $css_chunks[$i] = $this->minify($css_chunks[$i], $linebreak_pos);
138
            // Keep the first @charset at-rule found
139
            if (empty($charset) && preg_match($charset_regexp, $css_chunks[$i], $matches)) {
140
                $charset = strtolower($matches[1]) . $matches[2];
141
            }
142
            // Delete all @charset at-rules
143
            $css_chunks[$i] = preg_replace($charset_regexp, '', $css_chunks[$i]);
144
        }
145
146
        // Update the first chunk and push the charset to the top of the file.
147
        $css_chunks[0] = $charset . $css_chunks[0];
148
149
        return implode('', $css_chunks);
150
    }
151
152
    /**
153
     * Sets the memory limit for this script
154
     * @param int|string $limit
155
     */
156
    public function set_memory_limit($limit)
157
    {
158
        $this->memory_limit = $this->normalize_int($limit);
159
    }
160
161
    /**
162
     * Sets the maximum execution time for this script
163
     * @param int|string $seconds
164
     */
165
    public function set_max_execution_time($seconds)
166
    {
167
        $this->max_execution_time = (int) $seconds;
168
    }
169
170
    /**
171
     * Sets the PCRE backtrack limit for this script
172
     * @param int $limit
173
     */
174
    public function set_pcre_backtrack_limit($limit)
175
    {
176
        $this->pcre_backtrack_limit = (int) $limit;
177
    }
178
179
    /**
180
     * Sets the PCRE recursion limit for this script
181
     * @param int $limit
182
     */
183
    public function set_pcre_recursion_limit($limit)
184
    {
185
        $this->pcre_recursion_limit = (int) $limit;
186
    }
187
188
    /**
189
     * Try to configure PHP to use at least the suggested minimum settings
190
     */
191
    private function do_raise_php_limits()
192
    {
193
        $php_limits = array(
194
            'memory_limit' => $this->memory_limit,
195
            'max_execution_time' => $this->max_execution_time,
196
            'pcre.backtrack_limit' => $this->pcre_backtrack_limit,
197
            'pcre.recursion_limit' =>  $this->pcre_recursion_limit
198
        );
199
200
        // If current settings are higher respect them.
201
        foreach ($php_limits as $name => $suggested) {
202
            $current = $this->normalize_int(ini_get($name));
203
            // memory_limit exception: allow -1 for "no memory limit".
204
            if ($current > -1 && ($suggested == -1 || $current < $suggested)) {
205
                ini_set($name, $suggested);
206
            }
207
        }
208
    }
209
210
    /**
211
     * Does bulk of the minification
212
     * @param string $css
213
     * @param int|bool $linebreak_pos
214
     * @return string
215
     */
216
    private function minify($css, $linebreak_pos)
217
    {
218
        // strings are safe, now wrestle the comments
219
        for ($i = 0, $max = count($this->comments); $i < $max; $i++) {
220
221
            $token = $this->comments[$i];
222
            $placeholder = '/' . self::COMMENT . $i . '___/';
223
224
            // ! in the first position of the comment means preserve
225
            // so push to the preserved tokens keeping the !
226
            if (substr($token, 0, 1) === '!') {
227
                $this->preserved_tokens[] = $token;
228
                $token_tring = self::TOKEN . (count($this->preserved_tokens) - 1) . '___';
229
                $css = preg_replace($placeholder, $token_tring, $css, 1);
230
                // Preserve new lines for /*! important comments
231
                $css = preg_replace('/\s*[\n\r\f]+\s*(\/\*'. $token_tring .')/S', self::NL.'$1', $css);
232
                $css = preg_replace('/('. $token_tring .'\*\/)\s*[\n\r\f]+\s*/', '$1'.self::NL, $css);
233
                continue;
234
            }
235
236
            // \ in the last position looks like hack for Mac/IE5
237
            // shorten that to /*\*/ and the next one to /**/
238
            if (substr($token, (strlen($token) - 1), 1) === '\\') {
239
                $this->preserved_tokens[] = '\\';
240
                $css = preg_replace($placeholder,  self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
241
                $i = $i + 1; // attn: advancing the loop
242
                $this->preserved_tokens[] = '';
243
                $css = preg_replace('/' . self::COMMENT . $i . '___/',  self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
244
                continue;
245
            }
246
247
            // keep empty comments after child selectors (IE7 hack)
248
            // e.g. html >/**/ body
249
            if (strlen($token) === 0) {
250
                $start_index = $this->index_of($css, $this->str_slice($placeholder, 1, -1));
251
                if ($start_index > 2) {
252
                    if (substr($css, $start_index - 3, 1) === '>') {
253
                        $this->preserved_tokens[] = '';
254
                        $css = preg_replace($placeholder,  self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
255
                    }
256
                }
257
            }
258
259
            // in all other cases kill the comment
260
            $css = preg_replace('/\/\*' . $this->str_slice($placeholder, 1, -1) . '\*\//', '', $css, 1);
261
        }
262
263
264
        // Normalize all whitespace strings to single spaces. Easier to work with that way.
265
        $css = preg_replace('/\s+/', ' ', $css);
266
267
	// preserve flex, keeping percentage even if 0
268
	$css = preg_replace_callback('/flex\s?:\s?((?:[0-9 ]*)\s?(?:px|em|auto|%)?(?:calc\(.*\))?)/i',array($this, 'replace_flex'),$css);
269
270
	// Fix IE7 issue on matrix filters which browser accept whitespaces between Matrix parameters
271
	$css = preg_replace_callback('/\s*filter\:\s*progid:DXImageTransform\.Microsoft\.Matrix\(([^\)]+)\)/', array($this, 'preserve_old_IE_specific_matrix_definition'), $css);
272
273
        // Shorten & preserve calculations calc(...) since spaces are important
274
        $css = preg_replace_callback('/calc(\(((?:[^\(\)]+|(?1))*)\))/i', array($this, 'replace_calc'), $css);
275
276
        // Replace positive sign from numbers preceded by : or a white-space before the leading space is removed
277
        // +1.2em to 1.2em, +.8px to .8px, +2% to 2%
278
        $css = preg_replace('/((?<!\\\\)\:|\s)\+(\.?\d+)/S', '$1$2', $css);
279
280
        // Remove leading zeros from integer and float numbers preceded by : or a white-space
281
        // 000.6 to .6, -0.8 to -.8, 0050 to 50, -01.05 to -1.05
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
282
        $css = preg_replace('/((?<!\\\\)\:|\s)(\-?)0+(\.?\d+)/S', '$1$2$3', $css);
283
284
        // Remove trailing zeros from float numbers preceded by : or a white-space
285
        // -6.0100em to -6.01em, .0100 to .01, 1.200px to 1.2px
286
        $css = preg_replace('/((?<!\\\\)\:|\s)(\-?)(\d?\.\d+?)0+([^\d])/S', '$1$2$3$4', $css);
287
288
        // Remove trailing .0 -> -9.0 to -9
289
        $css = preg_replace('/((?<!\\\\)\:|\s)(\-?\d+)\.0([^\d])/S', '$1$2$3', $css);
290
291
        // Replace 0 length numbers with 0
292
        $css = preg_replace('/((?<!\\\\)\:|\s)\-?\.?0+([^\d])/S', '${1}0$2', $css);
293
294
        // Remove the spaces before the things that should not have spaces before them.
295
        // But, be careful not to turn "p :link {...}" into "p:link{...}"
296
        // Swap out any pseudo-class colons with the token, and then swap back.
297
        $css = preg_replace_callback('/(?:^|\})[^\{]*\s+\:/', array($this, 'replace_colon'), $css);
298
299
        // Remove spaces before the things that should not have spaces before them.
300
        $css = preg_replace('/\s+([\!\{\}\;\:\>\+\(\)\]\~\=,])/', '$1', $css);
301
302
        // Restore spaces for !important
303
        $css = preg_replace('/\!important/i', ' !important', $css);
304
305
        // bring back the colon
306
        $css = preg_replace('/' . self::CLASSCOLON . '/', ':', $css);
307
308
        // retain space for special IE6 cases
309
        $css = preg_replace_callback('/\:first\-(line|letter)(\{|,)/i', array($this, 'lowercase_pseudo_first'), $css);
310
311
        // no space after the end of a preserved comment
312
        $css = preg_replace('/\*\/ /', '*/', $css);
313
314
        // lowercase some popular @directives
315
        $css = preg_replace_callback('/@(font-face|import|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?keyframe|media|page|namespace)/i', array($this, 'lowercase_directives'), $css);
316
317
        // lowercase some more common pseudo-elements
318
        $css = preg_replace_callback('/:(active|after|before|checked|disabled|empty|enabled|first-(?:child|of-type)|focus|hover|last-(?:child|of-type)|link|only-(?:child|of-type)|root|:selection|target|visited)/i', array($this, 'lowercase_pseudo_elements'), $css);
319
320
        // lowercase some more common functions
321
        $css = preg_replace_callback('/:(lang|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|(?:-(?:moz|webkit)-)?any)\(/i', array($this, 'lowercase_common_functions'), $css);
322
323
        // lower case some common function that can be values
324
        // NOTE: rgb() isn't useful as we replace with #hex later, as well as and() is already done for us
325
        $css = preg_replace_callback('/([:,\( ]\s*)(attr|color-stop|from|rgba|to|url|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?(?:calc|max|min|(?:repeating-)?(?:linear|radial)-gradient)|-webkit-gradient)/iS', array($this, 'lowercase_common_functions_values'), $css);
326
327
        // Put the space back in some cases, to support stuff like
328
        // @media screen and (-webkit-min-device-pixel-ratio:0){
329
        $css = preg_replace('/\band\(/i', 'and (', $css);
330
331
        // Remove the spaces after the things that should not have spaces after them.
332
        $css = preg_replace('/([\!\{\}\:;\>\+\(\[\~\=,])\s+/S', '$1', $css);
333
334
        // remove unnecessary semicolons
335
        $css = preg_replace('/;+\}/', '}', $css);
336
337
        // Fix for issue: #2528146
338
        // Restore semicolon if the last property is prefixed with a `*` (lte IE7 hack)
339
        // to avoid issues on Symbian S60 3.x browsers.
340
        $css = preg_replace('/(\*[a-z0-9\-]+\s*\:[^;\}]+)(\})/', '$1;$2', $css);
341
342
        // Replace 0 <length> and 0 <percentage> values with 0.
343
        // <length> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/length
344
        // <percentage> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/percentage
345
        $css = preg_replace('/([^\\\\]\:|\s)0(?:em|ex|ch|rem|vw|vh|vm|vmin|cm|mm|in|px|pt|pc|%)/iS', '${1}0', $css);
346
347
		// 0% step in a keyframe? restore the % unit
348
		$css = preg_replace_callback('/(@[a-z\-]*?keyframes[^\{]+\{)(.*?)(\}\})/iS', array($this, 'replace_keyframe_zero'), $css);
349
350
        // Replace 0 0; or 0 0 0; or 0 0 0 0; with 0.
0 ignored issues
show
Unused Code Comprehensibility introduced by
49% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
351
        $css = preg_replace('/\:0(?: 0){1,3}(;|\}| \!)/', ':0$1', $css);
352
353
        // Fix for issue: #2528142
354
        // Replace text-shadow:0; with text-shadow:0 0 0;
355
        $css = preg_replace('/(text-shadow\:0)(;|\}| \!)/i', '$1 0 0$2', $css);
356
357
        // Replace background-position:0; with background-position:0 0;
358
        // same for transform-origin
359
        // Changing -webkit-mask-position: 0 0 to just a single 0 will result in the second parameter defaulting to 50% (center)
360
        $css = preg_replace('/(background|background\-position|webkit-mask-position|(?:webkit|moz|o|ms|)\-?transform\-origin)\:0(;|\}| \!)/iS', '$1:0 0$2', $css);
361
362
        // Shorten colors from rgb(51,102,153) to #336699, rgb(100%,0%,0%) to #ff0000 (sRGB color space)
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
363
        // Shorten colors from hsl(0, 100%, 50%) to #ff0000 (sRGB color space)
364
        // This makes it more likely that it'll get further compressed in the next step.
365
        $css = preg_replace_callback('/rgb\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'rgb_to_hex'), $css);
366
        $css = preg_replace_callback('/hsl\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'hsl_to_hex'), $css);
367
368
        // Shorten colors from #AABBCC to #ABC or short color name.
369
        $css = $this->compress_hex_colors($css);
370
371
        // border: none to border:0, outline: none to outline:0
372
        $css = preg_replace('/(border\-?(?:top|right|bottom|left|)|outline)\:none(;|\}| \!)/iS', '$1:0$2', $css);
373
374
        // shorter opacity IE filter
375
        $css = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $css);
376
377
        // Find a fraction that is used for Opera's -o-device-pixel-ratio query
378
        // Add token to add the "\" back in later
379
        $css = preg_replace('/\(([a-z\-]+):([0-9]+)\/([0-9]+)\)/i', '($1:$2'. self::QUERY_FRACTION .'$3)', $css);
380
381
        // Remove empty rules.
382
        $css = preg_replace('/[^\};\{\/]+\{\}/S', '', $css);
383
384
        // Add "/" back to fix Opera -o-device-pixel-ratio query
385
        $css = preg_replace('/'. self::QUERY_FRACTION .'/', '/', $css);
386
387
		// Replace multiple semi-colons in a row by a single one
388
        // See SF bug #1980989
389
        $css = preg_replace('/;;+/', ';', $css);
390
391
        // Restore new lines for /*! important comments
392
        $css = preg_replace('/'. self::NL .'/', "\n", $css);
393
394
        // Lowercase all uppercase properties
395
        $css = preg_replace_callback('/(\{|\;)([A-Z\-]+)(\:)/', array($this, 'lowercase_properties'), $css);
396
397
        // Some source control tools don't like it when files containing lines longer
398
        // than, say 8000 characters, are checked in. The linebreak option is used in
399
        // that case to split long lines after a specific column.
400
        if ($linebreak_pos !== FALSE && (int) $linebreak_pos >= 0) {
401
            $linebreak_pos = (int) $linebreak_pos;
402
            $start_index = $i = 0;
403
            while ($i < strlen($css)) {
404
                $i++;
405
                if ($css[$i - 1] === '}' && $i - $start_index > $linebreak_pos) {
406
                    $css = $this->str_slice($css, 0, $i) . "\n" . $this->str_slice($css, $i);
407
                    $start_index = $i;
408
                }
409
            }
410
        }
411
412
        // restore preserved comments and strings in reverse order
413
        for ($i = count($this->preserved_tokens) - 1; $i >= 0; $i--) {
414
			  $css = preg_replace('/' . self::TOKEN . $i . '___/', $this->preserved_tokens[$i], $css, 1);
415
			  // $css.=$this->preserved_tokens[$i];
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
416
        }
417
418
        // Trim the final string (for any leading or trailing white spaces)
419
        return trim($css);
420
    }
421
422
    /**
423
     * Utility method to replace all data urls with tokens before we start
424
     * compressing, to avoid performance issues running some of the subsequent
425
     * regexes against large strings chunks.
426
     *
427
     * @param string $css
428
     * @return string
429
     */
430
    private function extract_data_urls($css)
431
    {
432
        // Leave data urls alone to increase parse performance.
433
        $max_index = strlen($css) - 1;
434
        $append_index = $index = $last_index = $offset = 0;
0 ignored issues
show
Unused Code introduced by
$last_index 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...
Unused Code introduced by
$index 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...
435
        $sb = array();
436
        $pattern = '/url\(\s*(["\']?)data\:/i';
437
438
        // Since we need to account for non-base64 data urls, we need to handle
439
        // ' and ) being part of the data string. Hence switching to indexOf,
440
        // to determine whether or not we have matching string terminators and
441
        // handling sb appends directly, instead of using matcher.append* methods.
442
443
        while (preg_match($pattern, $css, $m, 0, $offset)) {
444
            $index = $this->index_of($css, $m[0], $offset);
445
            $last_index = $index + strlen($m[0]);
446
            $start_index = $index + 4; // "url(".length()
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
447
            $end_index = $last_index - 1;
448
            $terminator = $m[1]; // ', " or empty (not quoted)
449
            $found_terminator = FALSE;
450
451
            if (strlen($terminator) === 0) {
452
                $terminator = ')';
453
            }
454
455
            while ($found_terminator === FALSE && $end_index+1 <= $max_index) {
456
                $end_index = $this->index_of($css, $terminator, $end_index + 1);
457
458
                // endIndex == 0 doesn't really apply here
459
                if ($end_index > 0 && substr($css, $end_index - 1, 1) !== '\\') {
460
                    $found_terminator = TRUE;
461
                    if (')' != $terminator) {
462
                        $end_index = $this->index_of($css, ')', $end_index);
463
                    }
464
                }
465
            }
466
467
            // Enough searching, start moving stuff over to the buffer
468
            $sb[] = $this->str_slice($css, $append_index, $index);
469
470
            if ($found_terminator) {
471
                $token = $this->str_slice($css, $start_index, $end_index);
472
				if (strpos($token,"<svg")===false && strpos($token,'svg+xml')===false) {
473
					$token = preg_replace('/\s+/', '', $token);
474
				}
475
                $this->preserved_tokens[] = $token;
476
477
                $preserver = 'url(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___)';
478
                $sb[] = $preserver;
479
480
                $append_index = $end_index + 1;
481
            } else {
482
                // No end terminator found, re-add the whole match. Should we throw/warn here?
483
                $sb[] = $this->str_slice($css, $index, $last_index);
484
                $append_index = $last_index;
485
            }
486
487
            $offset = $last_index;
488
        }
489
490
        $sb[] = $this->str_slice($css, $append_index);
491
492
        return implode('', $sb);
493
    }
494
495
    /**
496
     * Utility method to compress hex color values of the form #AABBCC to #ABC or short color name.
497
     *
498
     * DOES NOT compress CSS ID selectors which match the above pattern (which would break things).
499
     * e.g. #AddressForm { ... }
500
     *
501
     * DOES NOT compress IE filters, which have hex color values (which would break things).
502
     * e.g. filter: chroma(color="#FFFFFF");
503
     *
504
     * DOES NOT compress invalid hex values.
505
     * e.g. background-color: #aabbccdd
506
     *
507
     * @param string $css
508
     * @return string
509
     */
510
    private function compress_hex_colors($css)
511
    {
512
        // Look for hex colors inside { ... } (to avoid IDs) and which don't have a =, or a " in front of them (to avoid filters)
513
        $pattern = '/(\=\s*?["\']?)?#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])(\}|[^0-9a-f{][^{]*?\})/iS';
514
        $_index = $index = $last_index = $offset = 0;
0 ignored issues
show
Unused Code introduced by
$last_index 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...
Unused Code introduced by
$index 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...
515
        $sb = array();
516
        // See: http://ajaxmin.codeplex.com/wikipage?title=CSS%20Colors
517
        $short_safe = array(
518
            '#808080' => 'gray',
519
            '#008000' => 'green',
520
            '#800000' => 'maroon',
521
            '#000080' => 'navy',
522
            '#808000' => 'olive',
523
            '#ffa500' => 'orange',
524
            '#800080' => 'purple',
525
            '#c0c0c0' => 'silver',
526
            '#008080' => 'teal',
527
            '#f00' => 'red'
528
        );
529
530
        while (preg_match($pattern, $css, $m, 0, $offset)) {
531
            $index = $this->index_of($css, $m[0], $offset);
532
            $last_index = $index + strlen($m[0]);
533
            $is_filter = $m[1] !== null && $m[1] !== '';
534
535
            $sb[] = $this->str_slice($css, $_index, $index);
536
537
            if ($is_filter) {
538
                // Restore, maintain case, otherwise filter will break
539
                $sb[] = $m[1] . '#' . $m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7];
540
            } else {
541
                if (strtolower($m[2]) == strtolower($m[3]) &&
542
                    strtolower($m[4]) == strtolower($m[5]) &&
543
                    strtolower($m[6]) == strtolower($m[7])) {
544
                    // Compress.
545
                    $hex = '#' . strtolower($m[3] . $m[5] . $m[7]);
546
                } else {
547
                    // Non compressible color, restore but lower case.
548
                    $hex = '#' . strtolower($m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7]);
549
                }
550
                // replace Hex colors to short safe color names
551
                $sb[] = array_key_exists($hex, $short_safe) ? $short_safe[$hex] : $hex;
552
            }
553
554
            $_index = $offset = $last_index - strlen($m[8]);
555
        }
556
557
        $sb[] = $this->str_slice($css, $_index);
558
559
        return implode('', $sb);
560
    }
561
562
    /* CALLBACKS
563
     * ---------------------------------------------------------------------------------------------
564
     */
565
566
    private function replace_string($matches)
567
    {
568
        $match = $matches[0];
569
        $quote = substr($match, 0, 1);
570
        // Must use addcslashes in PHP to avoid parsing of backslashes
571
        $match = addcslashes($this->str_slice($match, 1, -1), '\\');
572
573
        // maybe the string contains a comment-like substring?
574
        // one, maybe more? put'em back then
575
        if (($pos = $this->index_of($match, self::COMMENT)) >= 0) {
576
            for ($i = 0, $max = count($this->comments); $i < $max; $i++) {
577
                $match = preg_replace('/' . self::COMMENT . $i . '___/', $this->comments[$i], $match, 1);
578
            }
579
        }
580
581
        // minify alpha opacity in filter strings
582
        $match = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $match);
583
584
        $this->preserved_tokens[] = $match;
585
        return $quote . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . $quote;
586
    }
587
588
    private function replace_colon($matches)
589
    {
590
        return preg_replace('/\:/', self::CLASSCOLON, $matches[0]);
591
    }
592
593
    private function replace_calc($matches)
594
    {
595
        $this->preserved_tokens[] = preg_replace('/\)([\+\-]{1})/',') $1',preg_replace('/([\+\-]{1})\(/','$1 (',trim(preg_replace('/\s*([\*\/\(\),])\s*/', '$1', $matches[2]))));
596
        return 'calc('. self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
597
    }
598
    
599
    private function replace_flex($matches)
600
    {
601
        $this->preserved_tokens[] = trim($matches[1]);
602
        return 'flex:'.self::TOKEN . (count($this->preserved_tokens) - 1) . '___';
603
    }   
604
605
	private function preserve_old_IE_specific_matrix_definition($matches)
606
	{
607
		$this->preserved_tokens[] = $matches[1];
608
		return 'filter:progid:DXImageTransform.Microsoft.Matrix(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
609
    }
610
611
	private function replace_keyframe_zero($matches)
612
    {
613
        return $matches[1] . preg_replace('/0(\{|,[^\)\{]+\{)/', '0%$1', $matches[2]) . $matches[3];
614
    }
615
616
    private function rgb_to_hex($matches)
617
    {
618
        // Support for percentage values rgb(100%, 0%, 45%);
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
619
        if ($this->index_of($matches[1], '%') >= 0){
620
            $rgbcolors = explode(',', str_replace('%', '', $matches[1]));
621
            for ($i = 0; $i < count($rgbcolors); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
622
                $rgbcolors[$i] = $this->round_number(floatval($rgbcolors[$i]) * 2.55);
623
            }
624
        } else {
625
            $rgbcolors = explode(',', $matches[1]);
626
        }
627
628
        // Values outside the sRGB color space should be clipped (0-255)
629
        for ($i = 0; $i < count($rgbcolors); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
630
            $rgbcolors[$i] = $this->clamp_number(intval($rgbcolors[$i], 10), 0, 255);
631
            $rgbcolors[$i] = sprintf("%02x", $rgbcolors[$i]);
632
        }
633
634
        // Fix for issue #2528093
635
        if (!preg_match('/[\s\,\);\}]/', $matches[2])){
636
            $matches[2] = ' ' . $matches[2];
637
        }
638
639
        return '#' . implode('', $rgbcolors) . $matches[2];
640
    }
641
642
    private function hsl_to_hex($matches)
643
    {
644
        $values = explode(',', str_replace('%', '', $matches[1]));
645
        $h = floatval($values[0]);
646
        $s = floatval($values[1]);
647
        $l = floatval($values[2]);
648
649
        // Wrap and clamp, then fraction!
650
        $h = ((($h % 360) + 360) % 360) / 360;
651
        $s = $this->clamp_number($s, 0, 100) / 100;
652
        $l = $this->clamp_number($l, 0, 100) / 100;
653
654 View Code Duplication
        if ($s == 0) {
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...
655
            $r = $g = $b = $this->round_number(255 * $l);
656
        } else {
657
            $v2 = $l < 0.5 ? $l * (1 + $s) : ($l + $s) - ($s * $l);
658
            $v1 = (2 * $l) - $v2;
659
            $r = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h + (1/3)));
660
            $g = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h));
661
            $b = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h - (1/3)));
662
        }
663
664
        return $this->rgb_to_hex(array('', $r.','.$g.','.$b, $matches[2]));
665
    }
666
667
    private function lowercase_pseudo_first($matches)
668
    {
669
        return ':first-'. strtolower($matches[1]) .' '. $matches[2];
670
    }
671
672
    private function lowercase_directives($matches)
673
    {
674
        return '@'. strtolower($matches[1]);
675
    }
676
677
    private function lowercase_pseudo_elements($matches)
678
    {
679
        return ':'. strtolower($matches[1]);
680
    }
681
682
    private function lowercase_common_functions($matches)
683
    {
684
        return ':'. strtolower($matches[1]) .'(';
685
    }
686
687
    private function lowercase_common_functions_values($matches)
688
    {
689
        return $matches[1] . strtolower($matches[2]);
690
    }
691
692
    private function lowercase_properties($matches)
693
    {
694
        return $matches[1].strtolower($matches[2]).$matches[3];
695
    }
696
697
    /* HELPERS
698
     * ---------------------------------------------------------------------------------------------
699
     */
700
701 View Code Duplication
    private function hue_to_rgb($v1, $v2, $vh)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
702
    {
703
        $vh = $vh < 0 ? $vh + 1 : ($vh > 1 ? $vh - 1 : $vh);
704
        if ($vh * 6 < 1) return $v1 + ($v2 - $v1) * 6 * $vh;
705
        if ($vh * 2 < 1) return $v2;
706
        if ($vh * 3 < 2) return $v1 + ($v2 - $v1) * ((2/3) - $vh) * 6;
707
        return $v1;
708
    }
709
710
    private function round_number($n)
711
    {
712
        return intval(floor(floatval($n) + 0.5), 10);
713
    }
714
715
    private function clamp_number($n, $min, $max)
716
    {
717
        return min(max($n, $min), $max);
718
    }
719
720
    /**
721
     * PHP port of Javascript's "indexOf" function for strings only
722
     * Author: Tubal Martin http://blog.margenn.com
723
     *
724
     * @param string $haystack
725
     * @param string $needle
726
     * @param int    $offset index (optional)
727
     * @return int
728
     */
729
    private function index_of($haystack, $needle, $offset = 0)
730
    {
731
        $index = strpos($haystack, $needle, $offset);
732
733
        return ($index !== FALSE) ? $index : -1;
734
    }
735
736
    /**
737
     * PHP port of Javascript's "slice" function for strings only
738
     * Author: Tubal Martin http://blog.margenn.com
739
     * Tests: http://margenn.com/tubal/str_slice/
740
     *
741
     * @param string   $str
742
     * @param int      $start index
743
     * @param int|bool $end index (optional)
744
     * @return string
745
     */
746 View Code Duplication
    private function str_slice($str, $start = 0, $end = FALSE)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
747
    {
748
        if ($end !== FALSE && ($start < 0 || $end <= 0)) {
749
            $max = strlen($str);
750
751
            if ($start < 0) {
752
                if (($start = $max + $start) < 0) {
753
                    return '';
754
                }
755
            }
756
757
            if ($end < 0) {
758
                if (($end = $max + $end) < 0) {
759
                    return '';
760
                }
761
            }
762
763
            if ($end <= $start) {
764
                return '';
765
            }
766
        }
767
768
        $slice = ($end === FALSE) ? substr($str, $start) : substr($str, $start, $end - $start);
769
        return ($slice === FALSE) ? '' : $slice;
770
    }
771
772
    /**
773
     * Convert strings like "64M" or "30" to int values
774
     * @param mixed $size
775
     * @return int
776
     */
777
    private function normalize_int($size)
778
    {
779
        if (is_string($size)) {
780
            switch (substr($size, -1)) {
781
                case 'M': case 'm': return (int) $size * 1048576;
782
                case 'K': case 'k': return (int) $size * 1024;
783
                case 'G': case 'g': return (int) $size * 1073741824;
784
            }
785
        }
786
787
        return (int) $size;
788
    }
789
}
790