Completed
Push — master ( 9a01d9...c990d6 )
by frank
08:32
created

external/php/yui-php-cssmin-2.4.8-4_fgo.php (6 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*!
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++) {
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
        // based on regex from https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port/blob/v3.2.0/src/Minifier.php#L479
330
        $css = preg_replace('/(\s|\)\s)(and|not|or)\(/i', '$1$2 (', $css);
331
332
        // Remove the spaces after the things that should not have spaces after them.
333
        $css = preg_replace('/([\!\{\}\:;\>\+\(\[\~\=,])\s+/S', '$1', $css);
334
335
        // remove unnecessary semicolons
336
        $css = preg_replace('/;+\}/', '}', $css);
337
338
        // Fix for issue: #2528146
339
        // Restore semicolon if the last property is prefixed with a `*` (lte IE7 hack)
340
        // to avoid issues on Symbian S60 3.x browsers.
341
        $css = preg_replace('/(\*[a-z0-9\-]+\s*\:[^;\}]+)(\})/', '$1;$2', $css);
342
343
        // Replace 0 <length> and 0 <percentage> values with 0.
344
        // <length> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/length
345
        // <percentage> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/percentage
346
        $css = preg_replace('/([^\\\\]\:|\s)0(?:em|ex|ch|rem|vw|vh|vm|vmin|cm|mm|in|px|pt|pc|%)/iS', '${1}0', $css);
347
348
		// 0% step in a keyframe? restore the % unit
349
		$css = preg_replace_callback('/(@[a-z\-]*?keyframes[^\{]+\{)(.*?)(\}\})/iS', array($this, 'replace_keyframe_zero'), $css);
350
351
        // 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...
352
        $css = preg_replace('/\:0(?: 0){1,3}(;|\}| \!)/', ':0$1', $css);
353
354
        // Fix for issue: #2528142
355
        // Replace text-shadow:0; with text-shadow:0 0 0;
356
        $css = preg_replace('/(text-shadow\:0)(;|\}| \!)/i', '$1 0 0$2', $css);
357
358
        // Replace background-position:0; with background-position:0 0;
359
        // same for transform-origin
360
        // Changing -webkit-mask-position: 0 0 to just a single 0 will result in the second parameter defaulting to 50% (center)
361
        $css = preg_replace('/(background|background\-position|webkit-mask-position|(?:webkit|moz|o|ms|)\-?transform\-origin)\:0(;|\}| \!)/iS', '$1:0 0$2', $css);
362
363
        // 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...
364
        // Shorten colors from hsl(0, 100%, 50%) to #ff0000 (sRGB color space)
365
        // This makes it more likely that it'll get further compressed in the next step.
366
        $css = preg_replace_callback('/rgb\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'rgb_to_hex'), $css);
367
        $css = preg_replace_callback('/hsl\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'hsl_to_hex'), $css);
368
369
        // Shorten colors from #AABBCC to #ABC or short color name.
370
        $css = $this->compress_hex_colors($css);
371
372
        // border: none to border:0, outline: none to outline:0
373
        $css = preg_replace('/(border\-?(?:top|right|bottom|left|)|outline)\:none(;|\}| \!)/iS', '$1:0$2', $css);
374
375
        // shorter opacity IE filter
376
        $css = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $css);
377
378
        // Find a fraction that is used for Opera's -o-device-pixel-ratio query
379
        // Add token to add the "\" back in later
380
        $css = preg_replace('/\(([a-z\-]+):([0-9]+)\/([0-9]+)\)/i', '($1:$2'. self::QUERY_FRACTION .'$3)', $css);
381
382
        // Remove empty rules.
383
        $css = preg_replace('/[^\};\{\/]+\{\}/S', '', $css);
384
385
        // Add "/" back to fix Opera -o-device-pixel-ratio query
386
        $css = preg_replace('/'. self::QUERY_FRACTION .'/', '/', $css);
387
388
		// Replace multiple semi-colons in a row by a single one
389
        // See SF bug #1980989
390
        $css = preg_replace('/;;+/', ';', $css);
391
392
        // Restore new lines for /*! important comments
393
        $css = preg_replace('/'. self::NL .'/', "\n", $css);
394
395
        // Lowercase all uppercase properties
396
        $css = preg_replace_callback('/(\{|\;)([A-Z\-]+)(\:)/', array($this, 'lowercase_properties'), $css);
397
398
        // Some source control tools don't like it when files containing lines longer
399
        // than, say 8000 characters, are checked in. The linebreak option is used in
400
        // that case to split long lines after a specific column.
401
        if ($linebreak_pos !== FALSE && (int) $linebreak_pos >= 0) {
402
            $linebreak_pos = (int) $linebreak_pos;
403
            $start_index = $i = 0;
404
            while ($i < strlen($css)) {
405
                $i++;
406
                if ($css[$i - 1] === '}' && $i - $start_index > $linebreak_pos) {
407
                    $css = $this->str_slice($css, 0, $i) . "\n" . $this->str_slice($css, $i);
408
                    $start_index = $i;
409
                }
410
            }
411
        }
412
413
        // restore preserved comments and strings in reverse order
414
        for ($i = count($this->preserved_tokens) - 1; $i >= 0; $i--) {
415
			  $css = preg_replace('/' . self::TOKEN . $i . '___/', $this->preserved_tokens[$i], $css, 1);
416
			  // $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...
417
        }
418
419
        // Trim the final string (for any leading or trailing white spaces)
420
        return trim($css);
421
    }
422
423
    /**
424
     * Utility method to replace all data urls with tokens before we start
425
     * compressing, to avoid performance issues running some of the subsequent
426
     * regexes against large strings chunks.
427
     *
428
     * @param string $css
429
     * @return string
430
     */
431
    private function extract_data_urls($css)
432
    {
433
        // Leave data urls alone to increase parse performance.
434
        $max_index = strlen($css) - 1;
435
        $append_index = $index = $last_index = $offset = 0;
436
        $sb = array();
437
        $pattern = '/url\(\s*(["\']?)data\:/i';
438
439
        // Since we need to account for non-base64 data urls, we need to handle
440
        // ' and ) being part of the data string. Hence switching to indexOf,
441
        // to determine whether or not we have matching string terminators and
442
        // handling sb appends directly, instead of using matcher.append* methods.
443
444
        while (preg_match($pattern, $css, $m, 0, $offset)) {
445
            $index = $this->index_of($css, $m[0], $offset);
446
            $last_index = $index + strlen($m[0]);
447
            $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...
448
            $end_index = $last_index - 1;
449
            $terminator = $m[1]; // ', " or empty (not quoted)
450
            $found_terminator = FALSE;
451
452
            if (strlen($terminator) === 0) {
453
                $terminator = ')';
454
            }
455
456
            while ($found_terminator === FALSE && $end_index+1 <= $max_index) {
457
                $end_index = $this->index_of($css, $terminator, $end_index + 1);
458
459
                // endIndex == 0 doesn't really apply here
460
                if ($end_index > 0 && substr($css, $end_index - 1, 1) !== '\\') {
461
                    $found_terminator = TRUE;
462
                    if (')' != $terminator) {
463
                        $end_index = $this->index_of($css, ')', $end_index);
464
                    }
465
                }
466
            }
467
468
            // Enough searching, start moving stuff over to the buffer
469
            $sb[] = $this->str_slice($css, $append_index, $index);
470
471
            if ($found_terminator) {
472
                $token = $this->str_slice($css, $start_index, $end_index);
473
				if (strpos($token,"<svg")===false && strpos($token,'svg+xml')===false) {
474
					$token = preg_replace('/\s+/', '', $token);
475
				}
476
                $this->preserved_tokens[] = $token;
477
478
                $preserver = 'url(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___)';
479
                $sb[] = $preserver;
480
481
                $append_index = $end_index + 1;
482
            } else {
483
                // No end terminator found, re-add the whole match. Should we throw/warn here?
484
                $sb[] = $this->str_slice($css, $index, $last_index);
485
                $append_index = $last_index;
486
            }
487
488
            $offset = $last_index;
489
        }
490
491
        $sb[] = $this->str_slice($css, $append_index);
492
493
        return implode('', $sb);
494
    }
495
496
    /**
497
     * Utility method to compress hex color values of the form #AABBCC to #ABC or short color name.
498
     *
499
     * DOES NOT compress CSS ID selectors which match the above pattern (which would break things).
500
     * e.g. #AddressForm { ... }
501
     *
502
     * DOES NOT compress IE filters, which have hex color values (which would break things).
503
     * e.g. filter: chroma(color="#FFFFFF");
504
     *
505
     * DOES NOT compress invalid hex values.
506
     * e.g. background-color: #aabbccdd
507
     *
508
     * @param string $css
509
     * @return string
510
     */
511
    private function compress_hex_colors($css)
512
    {
513
        // Look for hex colors inside { ... } (to avoid IDs) and which don't have a =, or a " in front of them (to avoid filters)
514
        $pattern = '/(\=\s*?["\']?)?#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])(\}|[^0-9a-f{][^{]*?\})/iS';
515
        $_index = $index = $last_index = $offset = 0;
516
        $sb = array();
517
        // See: http://ajaxmin.codeplex.com/wikipage?title=CSS%20Colors
518
        $short_safe = array(
519
            '#808080' => 'gray',
520
            '#008000' => 'green',
521
            '#800000' => 'maroon',
522
            '#000080' => 'navy',
523
            '#808000' => 'olive',
524
            '#ffa500' => 'orange',
525
            '#800080' => 'purple',
526
            '#c0c0c0' => 'silver',
527
            '#008080' => 'teal',
528
            '#f00' => 'red'
529
        );
530
531
        while (preg_match($pattern, $css, $m, 0, $offset)) {
532
            $index = $this->index_of($css, $m[0], $offset);
533
            $last_index = $index + strlen($m[0]);
534
            $is_filter = $m[1] !== null && $m[1] !== '';
535
536
            $sb[] = $this->str_slice($css, $_index, $index);
537
538
            if ($is_filter) {
539
                // Restore, maintain case, otherwise filter will break
540
                $sb[] = $m[1] . '#' . $m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7];
541
            } else {
542
                if (strtolower($m[2]) == strtolower($m[3]) &&
543
                    strtolower($m[4]) == strtolower($m[5]) &&
544
                    strtolower($m[6]) == strtolower($m[7])) {
545
                    // Compress.
546
                    $hex = '#' . strtolower($m[3] . $m[5] . $m[7]);
547
                } else {
548
                    // Non compressible color, restore but lower case.
549
                    $hex = '#' . strtolower($m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7]);
550
                }
551
                // replace Hex colors to short safe color names
552
                $sb[] = array_key_exists($hex, $short_safe) ? $short_safe[$hex] : $hex;
553
            }
554
555
            $_index = $offset = $last_index - strlen($m[8]);
556
        }
557
558
        $sb[] = $this->str_slice($css, $_index);
559
560
        return implode('', $sb);
561
    }
562
563
    /* CALLBACKS
564
     * ---------------------------------------------------------------------------------------------
565
     */
566
567
    private function replace_string($matches)
568
    {
569
        $match = $matches[0];
570
        $quote = substr($match, 0, 1);
571
        // Must use addcslashes in PHP to avoid parsing of backslashes
572
        $match = addcslashes($this->str_slice($match, 1, -1), '\\');
573
574
        // maybe the string contains a comment-like substring?
575
        // one, maybe more? put'em back then
576
        if (($pos = $this->index_of($match, self::COMMENT)) >= 0) {
577
            for ($i = 0, $max = count($this->comments); $i < $max; $i++) {
578
                $match = preg_replace('/' . self::COMMENT . $i . '___/', $this->comments[$i], $match, 1);
579
            }
580
        }
581
582
        // minify alpha opacity in filter strings
583
        $match = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $match);
584
585
        $this->preserved_tokens[] = $match;
586
        return $quote . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . $quote;
587
    }
588
589
    private function replace_colon($matches)
590
    {
591
        return preg_replace('/\:/', self::CLASSCOLON, $matches[0]);
592
    }
593
594
    private function replace_calc($matches)
595
    {
596
        $this->preserved_tokens[] = preg_replace('/\)([\+\-]{1})/',') $1',preg_replace('/([\+\-]{1})\(/','$1 (',trim(preg_replace('/\s*([\*\/\(\),])\s*/', '$1', $matches[2]))));
597
        return 'calc('. self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
598
    }
599
    
600
    private function replace_flex($matches)
601
    {
602
        $this->preserved_tokens[] = trim($matches[1]);
603
        return 'flex:'.self::TOKEN . (count($this->preserved_tokens) - 1) . '___';
604
    }   
605
606
	private function preserve_old_IE_specific_matrix_definition($matches)
607
	{
608
		$this->preserved_tokens[] = $matches[1];
609
		return 'filter:progid:DXImageTransform.Microsoft.Matrix(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
610
    }
611
612
	private function replace_keyframe_zero($matches)
613
    {
614
        return $matches[1] . preg_replace('/0(\{|,[^\)\{]+\{)/', '0%$1', $matches[2]) . $matches[3];
615
    }
616
617
    private function rgb_to_hex($matches)
618
    {
619
        // 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...
620
        if ($this->index_of($matches[1], '%') >= 0){
621
            $rgbcolors = explode(',', str_replace('%', '', $matches[1]));
622
            for ($i = 0; $i < count($rgbcolors); $i++) {
623
                $rgbcolors[$i] = $this->round_number(floatval($rgbcolors[$i]) * 2.55);
624
            }
625
        } else {
626
            $rgbcolors = explode(',', $matches[1]);
627
        }
628
629
        // Values outside the sRGB color space should be clipped (0-255)
630
        for ($i = 0; $i < count($rgbcolors); $i++) {
631
            $rgbcolors[$i] = $this->clamp_number(intval($rgbcolors[$i], 10), 0, 255);
632
            $rgbcolors[$i] = sprintf("%02x", $rgbcolors[$i]);
633
        }
634
635
        // Fix for issue #2528093
636
        if (!preg_match('/[\s\,\);\}]/', $matches[2])){
637
            $matches[2] = ' ' . $matches[2];
638
        }
639
640
        return '#' . implode('', $rgbcolors) . $matches[2];
641
    }
642
643
    private function hsl_to_hex($matches)
644
    {
645
        $values = explode(',', str_replace('%', '', $matches[1]));
646
        $h = floatval($values[0]);
647
        $s = floatval($values[1]);
648
        $l = floatval($values[2]);
649
650
        // Wrap and clamp, then fraction!
651
        $h = ((($h % 360) + 360) % 360) / 360;
652
        $s = $this->clamp_number($s, 0, 100) / 100;
653
        $l = $this->clamp_number($l, 0, 100) / 100;
654
655 View Code Duplication
        if ($s == 0) {
656
            $r = $g = $b = $this->round_number(255 * $l);
657
        } else {
658
            $v2 = $l < 0.5 ? $l * (1 + $s) : ($l + $s) - ($s * $l);
659
            $v1 = (2 * $l) - $v2;
660
            $r = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h + (1/3)));
661
            $g = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h));
662
            $b = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h - (1/3)));
663
        }
664
665
        return $this->rgb_to_hex(array('', $r.','.$g.','.$b, $matches[2]));
666
    }
667
668
    private function lowercase_pseudo_first($matches)
669
    {
670
        return ':first-'. strtolower($matches[1]) .' '. $matches[2];
671
    }
672
673
    private function lowercase_directives($matches)
674
    {
675
        return '@'. strtolower($matches[1]);
676
    }
677
678
    private function lowercase_pseudo_elements($matches)
679
    {
680
        return ':'. strtolower($matches[1]);
681
    }
682
683
    private function lowercase_common_functions($matches)
684
    {
685
        return ':'. strtolower($matches[1]) .'(';
686
    }
687
688
    private function lowercase_common_functions_values($matches)
689
    {
690
        return $matches[1] . strtolower($matches[2]);
691
    }
692
693
    private function lowercase_properties($matches)
694
    {
695
        return $matches[1].strtolower($matches[2]).$matches[3];
696
    }
697
698
    /* HELPERS
699
     * ---------------------------------------------------------------------------------------------
700
     */
701
702 View Code Duplication
    private function hue_to_rgb($v1, $v2, $vh)
703
    {
704
        $vh = $vh < 0 ? $vh + 1 : ($vh > 1 ? $vh - 1 : $vh);
705
        if ($vh * 6 < 1) return $v1 + ($v2 - $v1) * 6 * $vh;
706
        if ($vh * 2 < 1) return $v2;
707
        if ($vh * 3 < 2) return $v1 + ($v2 - $v1) * ((2/3) - $vh) * 6;
708
        return $v1;
709
    }
710
711
    private function round_number($n)
712
    {
713
        return intval(floor(floatval($n) + 0.5), 10);
714
    }
715
716
    private function clamp_number($n, $min, $max)
717
    {
718
        return min(max($n, $min), $max);
719
    }
720
721
    /**
722
     * PHP port of Javascript's "indexOf" function for strings only
723
     * Author: Tubal Martin http://blog.margenn.com
724
     *
725
     * @param string $haystack
726
     * @param string $needle
727
     * @param int    $offset index (optional)
728
     * @return int
729
     */
730
    private function index_of($haystack, $needle, $offset = 0)
731
    {
732
        $index = strpos($haystack, $needle, $offset);
733
734
        return ($index !== FALSE) ? $index : -1;
735
    }
736
737
    /**
738
     * PHP port of Javascript's "slice" function for strings only
739
     * Author: Tubal Martin http://blog.margenn.com
740
     * Tests: http://margenn.com/tubal/str_slice/
741
     *
742
     * @param string   $str
743
     * @param int      $start index
744
     * @param int|bool $end index (optional)
745
     * @return string
746
     */
747 View Code Duplication
    private function str_slice($str, $start = 0, $end = FALSE)
748
    {
749
        if ($end !== FALSE && ($start < 0 || $end <= 0)) {
750
            $max = strlen($str);
751
752
            if ($start < 0) {
753
                if (($start = $max + $start) < 0) {
754
                    return '';
755
                }
756
            }
757
758
            if ($end < 0) {
759
                if (($end = $max + $end) < 0) {
760
                    return '';
761
                }
762
            }
763
764
            if ($end <= $start) {
765
                return '';
766
            }
767
        }
768
769
        $slice = ($end === FALSE) ? substr($str, $start) : substr($str, $start, $end - $start);
770
        return ($slice === FALSE) ? '' : $slice;
771
    }
772
773
    /**
774
     * Convert strings like "64M" or "30" to int values
775
     * @param mixed $size
776
     * @return int
777
     */
778
    private function normalize_int($size)
779
    {
780
        if (is_string($size)) {
781
            switch (substr($size, -1)) {
782
                case 'M': case 'm': return (int) $size * 1048576;
783
                case 'K': case 'k': return (int) $size * 1024;
784
                case 'G': case 'g': return (int) $size * 1073741824;
785
            }
786
        }
787
788
        return (int) $size;
789
    }
790
}
791