Completed
Push — remove/4.3min ( 891e8d...3c41cc )
by
unknown
27:51 queued 18:26
created

csstidy_optimise::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 1
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * CSSTidy - CSS Parser and Optimiser
5
 *
6
 * CSS Optimising Class
7
 * This class optimises CSS data generated by csstidy.
8
 *
9
 * Copyright 2005, 2006, 2007 Florian Schmitz
10
 *
11
 * This file is part of CSSTidy.
12
 *
13
 *   CSSTidy is free software; you can redistribute it and/or modify
14
 *   it under the terms of the GNU Lesser General Public License as published by
15
 *   the Free Software Foundation; either version 2.1 of the License, or
16
 *   (at your option) any later version.
17
 *
18
 *   CSSTidy is distributed in the hope that it will be useful,
19
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 *   GNU Lesser General Public License for more details.
22
 *
23
 *   You should have received a copy of the GNU Lesser General Public License
24
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
25
 *
26
 * @license http://opensource.org/licenses/lgpl-license.php GNU Lesser General Public License
27
 * @package csstidy
28
 * @author Florian Schmitz (floele at gmail dot com) 2005-2007
29
 * @author Brett Zamir (brettz9 at yahoo dot com) 2007
30
 * @author Nikolay Matsievsky (speed at webo dot name) 2009-2010
31
 */
32
33
/**
34
 * CSS Optimising Class
35
 *
36
 * This class optimises CSS data generated by csstidy.
37
 *
38
 * @package csstidy
39
 * @author Florian Schmitz (floele at gmail dot com) 2005-2006
40
 * @version 1.0
41
 */
42
class csstidy_optimise {
43
44
	/**
45
	 * Constructor
46
	 * @param array $css contains the class csstidy
47
	 * @access private
48
	 * @version 1.0
49
	 */
50
	function __construct(&$css) {
51
		$this->parser = & $css;
0 ignored issues
show
Bug introduced by
The property parser does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
52
		$this->css = & $css->css;
0 ignored issues
show
Bug introduced by
The property css does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
53
		$this->sub_value = & $css->sub_value;
0 ignored issues
show
Bug introduced by
The property sub_value does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
54
		$this->at = & $css->at;
0 ignored issues
show
Bug introduced by
The property at does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
55
		$this->selector = & $css->selector;
0 ignored issues
show
Bug introduced by
The property selector does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
56
		$this->property = & $css->property;
0 ignored issues
show
Bug introduced by
The property property does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
57
		$this->value = & $css->value;
0 ignored issues
show
Bug introduced by
The property value does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
58
	}
59
60
	/**
61
	 * Optimises $css after parsing
62
	 * @access public
63
	 * @version 1.0
64
	 */
65
	function postparse() {
66
		if ($this->parser->get_cfg('preserve_css')) {
67
			return;
68
		}
69
70 View Code Duplication
		if ($this->parser->get_cfg('merge_selectors') === 2) {
71
			foreach ($this->css as $medium => $value) {
72
				$this->merge_selectors($this->css[$medium]);
73
			}
74
		}
75
76 View Code Duplication
		if ($this->parser->get_cfg('discard_invalid_selectors')) {
77
			foreach ($this->css as $medium => $value) {
78
				$this->discard_invalid_selectors($this->css[$medium]);
79
			}
80
		}
81
82
		if ($this->parser->get_cfg('optimise_shorthands') > 0) {
83
			foreach ($this->css as $medium => $value) {
84
				foreach ($value as $selector => $value1) {
85
					$this->css[$medium][$selector] = csstidy_optimise::merge_4value_shorthands($this->css[$medium][$selector]);
86
87
					if ($this->parser->get_cfg('optimise_shorthands') < 2) {
88
						continue;
89
					}
90
91
					$this->css[$medium][$selector] = csstidy_optimise::merge_font($this->css[$medium][$selector]);
92
93
					if ($this->parser->get_cfg('optimise_shorthands') < 3) {
94
						continue;
95
					}
96
97
					$this->css[$medium][$selector] = csstidy_optimise::merge_bg($this->css[$medium][$selector]);
98
					if (empty($this->css[$medium][$selector])) {
99
						unset($this->css[$medium][$selector]);
100
					}
101
				}
102
			}
103
		}
104
	}
105
106
	/**
107
	 * Optimises values
108
	 * @access public
109
	 * @version 1.0
110
	 */
111
	function value() {
112
		$shorthands = & $GLOBALS['csstidy']['shorthands'];
113
114
		// optimise shorthand properties
115
		if (isset($shorthands[$this->property])) {
116
			$temp = csstidy_optimise::shorthand($this->value); // FIXME - move
117
			if ($temp != $this->value) {
118
				$this->parser->log('Optimised shorthand notation (' . $this->property . '): Changed "' . $this->value . '" to "' . $temp . '"', 'Information');
119
			}
120
			$this->value = $temp;
121
		}
122
123
		// Remove whitespace at ! important
124
		if ($this->value != $this->compress_important($this->value)) {
125
			$this->parser->log('Optimised !important', 'Information');
126
		}
127
	}
128
129
	/**
130
	 * Optimises shorthands
131
	 * @access public
132
	 * @version 1.0
133
	 */
134
	function shorthands() {
135
		$shorthands = & $GLOBALS['csstidy']['shorthands'];
136
137
		if (!$this->parser->get_cfg('optimise_shorthands') || $this->parser->get_cfg('preserve_css')) {
138
			return;
139
		}
140
141 View Code Duplication
		if ($this->property === 'font' && $this->parser->get_cfg('optimise_shorthands') > 1) {
142
			$this->css[$this->at][$this->selector]['font']='';
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 0 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
143
			$this->parser->merge_css_blocks($this->at, $this->selector, csstidy_optimise::dissolve_short_font($this->value));
144
		}
145 View Code Duplication
		if ($this->property === 'background' && $this->parser->get_cfg('optimise_shorthands') > 2) {
146
			$this->css[$this->at][$this->selector]['background']='';
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 0 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
147
			$this->parser->merge_css_blocks($this->at, $this->selector, csstidy_optimise::dissolve_short_bg($this->value));
148
		}
149
		if (isset($shorthands[$this->property])) {
150
			$this->parser->merge_css_blocks($this->at, $this->selector, csstidy_optimise::dissolve_4value_shorthands($this->property, $this->value));
151
			if (is_array($shorthands[$this->property])) {
152
				$this->css[$this->at][$this->selector][$this->property] = '';
153
			}
154
		}
155
	}
156
157
	/**
158
	 * Optimises a sub-value
159
	 * @access public
160
	 * @version 1.0
161
	 */
162
	function subvalue() {
163
		$replace_colors = & $GLOBALS['csstidy']['replace_colors'];
164
165
		$this->sub_value = trim($this->sub_value);
166
		if ($this->sub_value == '') { // caution : '0'
167
			return;
168
		}
169
170
		$important = '';
171
		if (csstidy::is_important($this->sub_value)) {
172
			$important = '!important';
173
		}
174
		$this->sub_value = csstidy::gvw_important($this->sub_value);
175
176
		// Compress font-weight
177
		if ($this->property === 'font-weight' && $this->parser->get_cfg('compress_font-weight')) {
178
			if ($this->sub_value === 'bold') {
179
				$this->sub_value = '700';
180
				$this->parser->log('Optimised font-weight: Changed "bold" to "700"', 'Information');
181
			} else if ($this->sub_value === 'normal') {
182
				$this->sub_value = '400';
183
				$this->parser->log('Optimised font-weight: Changed "normal" to "400"', 'Information');
184
			}
185
		}
186
187
		$temp = $this->compress_numbers($this->sub_value);
188
		if (strcasecmp($temp, $this->sub_value) !== 0) {
189
			if (strlen($temp) > strlen($this->sub_value)) {
190
				$this->parser->log('Fixed invalid number: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Warning');
191
			} else {
192
				$this->parser->log('Optimised number: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Information');
193
			}
194
			$this->sub_value = $temp;
195
		}
196
		if ($this->parser->get_cfg('compress_colors')) {
197
			$temp = $this->cut_color($this->sub_value);
198
			if ($temp !== $this->sub_value) {
199
				if (isset($replace_colors[$this->sub_value])) {
200
					$this->parser->log('Fixed invalid color name: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Warning');
201
				} else {
202
					$this->parser->log('Optimised color: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Information');
203
				}
204
				$this->sub_value = $temp;
205
			}
206
		}
207
		$this->sub_value .= $important;
208
	}
209
210
	/**
211
	 * Compresses shorthand values. Example: margin:1px 1px 1px 1px -> margin:1px
212
	 * @param string $value
213
	 * @access public
214
	 * @return string
215
	 * @version 1.0
216
	 */
217
	function shorthand($value) {
218
		$important = '';
219
		if (csstidy::is_important($value)) {
220
			$values = csstidy::gvw_important($value);
221
			$important = '!important';
222
		}
223
		else
224
			$values = $value;
225
226
		$values = explode(' ', $values);
227
		switch (count($values)) {
228
			case 4:
229
				if ($values[0] == $values[1] && $values[0] == $values[2] && $values[0] == $values[3]) {
230
					return $values[0] . $important;
231
				} elseif ($values[1] == $values[3] && $values[0] == $values[2]) {
232
					return $values[0] . ' ' . $values[1] . $important;
233
				} elseif ($values[1] == $values[3]) {
234
					return $values[0] . ' ' . $values[1] . ' ' . $values[2] . $important;
235
				}
236
				break;
237
238
			case 3:
239
				if ($values[0] == $values[1] && $values[0] == $values[2]) {
240
					return $values[0] . $important;
241
				} elseif ($values[0] == $values[2]) {
242
					return $values[0] . ' ' . $values[1] . $important;
243
				}
244
				break;
245
246
			case 2:
247
				if ($values[0] == $values[1]) {
248
					return $values[0] . $important;
249
				}
250
				break;
251
		}
252
253
		return $value;
254
	}
255
256
	/**
257
	 * Removes unnecessary whitespace in ! important
258
	 * @param string $string
259
	 * @return string
260
	 * @access public
261
	 * @version 1.1
262
	 */
263
	function compress_important(&$string) {
264
		if (csstidy::is_important($string)) {
265
			$string = csstidy::gvw_important($string) . ' !important';		}
266
		return $string;
267
	}
268
269
	/**
270
	 * Color compression function. Converts all rgb() values to #-values and uses the short-form if possible. Also replaces 4 color names by #-values.
271
	 * @param string $color
272
	 * @return string
273
	 * @version 1.1
274
	 */
275
	function cut_color($color) {
276
		$replace_colors = & $GLOBALS['csstidy']['replace_colors'];
277
278
		// rgb(0,0,0) -> #000000 (or #000 in this case later)
279
		if (strtolower(substr($color, 0, 4)) === 'rgb(') {
280
			$color_tmp = substr($color, 4, strlen($color) - 5);
281
			$color_tmp = explode(',', $color_tmp);
282
			for ($i = 0; $i < count($color_tmp); $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...
283
				$color_tmp[$i] = trim($color_tmp[$i]);
284
				if (substr($color_tmp[$i], -1) === '%') {
285
					$color_tmp[$i] = round((255 * $color_tmp[$i]) / 100);
286
				}
287
				if ($color_tmp[$i] > 255)
288
					$color_tmp[$i] = 255;
289
			}
290
			$color = '#';
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $color. This often makes code more readable.
Loading history...
291
			for ($i = 0; $i < 3; $i++) {
292
				if ($color_tmp[$i] < 16) {
293
					$color .= '0' . dechex($color_tmp[$i]);
294
				} else {
295
					$color .= dechex($color_tmp[$i]);
296
				}
297
			}
298
		}
299
300
		// Fix bad color names
301
		if (isset($replace_colors[strtolower($color)])) {
302
			$color = $replace_colors[strtolower($color)];
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $color. This often makes code more readable.
Loading history...
303
		}
304
305
		// #aabbcc -> #abc
306
		if (strlen($color) == 7) {
307
			$color_temp = strtolower($color);
308
			if ($color_temp{0} === '#' && $color_temp{1} == $color_temp{2} && $color_temp{3} == $color_temp{4} && $color_temp{5} == $color_temp{6}) {
309
				$color = '#' . $color{1} . $color{3} . $color{5};
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $color. This often makes code more readable.
Loading history...
310
			}
311
		}
312
313
		switch (strtolower($color)) {
314
			/* color name -> hex code */
315
			case 'black': return '#000';
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
316
			case 'fuchsia': return '#f0f';
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
317
			case 'white': return '#fff';
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
318
			case 'yellow': return '#ff0';
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
319
320
			/* hex code -> color name */
321
			case '#800000': return 'maroon';
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
322
			case '#ffa500': return 'orange';
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
323
			case '#808000': return 'olive';
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
324
			case '#800080': return 'purple';
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
325
			case '#008000': return 'green';
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
326
			case '#000080': return 'navy';
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
327
			case '#008080': return 'teal';
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
328
			case '#c0c0c0': return 'silver';
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
329
			case '#808080': return 'gray';
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
330
			case '#f00': return 'red';
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
331
		}
332
333
		return $color;
334
	}
335
336
	/**
337
	 * Compresses numbers (ie. 1.0 becomes 1 or 1.100 becomes 1.1 )
338
	 * @param string $subvalue
339
	 * @return string
340
	 * @version 1.2
341
	 */
342
	function compress_numbers($subvalue) {
343
		$unit_values = & $GLOBALS['csstidy']['unit_values'];
344
		$color_values = & $GLOBALS['csstidy']['color_values'];
345
346
		// for font:1em/1em sans-serif...;
347
		if ($this->property === 'font') {
348
			$temp = explode('/', $subvalue);
349
		} else {
350
			$temp = array($subvalue);
351
		}
352
		for ($l = 0; $l < count($temp); $l++) {
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...
353
			// if we are not dealing with a number at this point, do not optimise anything
354
			$number = $this->AnalyseCssNumber($temp[$l]);
355
			if ($number === false) {
356
				return $subvalue;
357
			}
358
359
			// Fix bad colors
360
			if (in_array($this->property, $color_values)) {
361
				if (strlen($temp[$l]) == 3 || strlen($temp[$l]) == 6) {
362
					$temp[$l] = '#' . $temp[$l];
363
				}
364
				else {
365
					$temp[$l] = "0";
366
				}
367
				continue;
368
			}
369
370
			if (abs($number[0]) > 0) {
371
				if ($number[1] == '' && in_array($this->property, $unit_values, true)) {
372
					$number[1] = 'px';
373
				}
374
			} else {
375
				$number[1] = '';
376
			}
377
378
			$temp[$l] = $number[0] . $number[1];
379
		}
380
381
		return ((count($temp) > 1) ? $temp[0] . '/' . $temp[1] : $temp[0]);
382
	}
383
384
	/**
385
	 * Checks if a given string is a CSS valid number. If it is,
386
	 * an array containing the value and unit is returned
387
	 * @param string $string
388
	 * @return array ('unit' if unit is found or '' if no unit exists, number value) or false if no number
389
	 */
390
	function AnalyseCssNumber($string) {
391
		// most simple checks first
392
		if (strlen($string) == 0 || ctype_alpha($string{0})) {
393
			return false;
394
		}
395
396
		$units = & $GLOBALS['csstidy']['units'];
397
		$return = array(0, '');
398
399
		$return[0] = floatval($string);
400
		if (abs($return[0]) > 0 && abs($return[0]) < 1) {
401
			if ($return[0] < 0) {
402
				$return[0] = '-' . ltrim(substr($return[0], 1), '0');
403
			} else {
404
				$return[0] = ltrim($return[0], '0');
405
			}
406
		}
407
408
		// Look for unit and split from value if exists
409
		foreach ($units as $unit) {
410
			$expectUnitAt = strlen($string) - strlen($unit);
411
			if (!($unitInString = stristr($string, $unit))) { // mb_strpos() fails with "false"
412
				continue;
413
			}
414
			$actualPosition = strpos($string, $unitInString);
415
			if ($expectUnitAt === $actualPosition) {
416
				$return[1] = $unit;
417
				$string = substr($string, 0, - strlen($unit));
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $string. This often makes code more readable.
Loading history...
418
				break;
419
			}
420
		}
421
		if (!is_numeric($string)) {
422
			return false;
423
		}
424
		return $return;
425
	}
426
427
	/**
428
	 * Merges selectors with same properties. Example: a{color:red} b{color:red} -> a,b{color:red}
429
	 * Very basic and has at least one bug. Hopefully there is a replacement soon.
430
	 * @param array $array
431
	 * @return array
432
	 * @access public
433
	 * @version 1.2
434
	 */
435
	function merge_selectors(&$array) {
436
		$css = $array;
437
		foreach ($css as $key => $value) {
438
			if (!isset($css[$key])) {
439
				continue;
440
			}
441
			$newsel = '';
0 ignored issues
show
Unused Code introduced by
$newsel 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...
442
443
			// Check if properties also exist in another selector
444
			$keys = array();
445
			// PHP bug (?) without $css = $array; here
446
			foreach ($css as $selector => $vali) {
447
				if ($selector == $key) {
448
					continue;
449
				}
450
451
				if ($css[$key] === $vali) {
452
					$keys[] = $selector;
453
				}
454
			}
455
456
			if (!empty($keys)) {
457
				$newsel = $key;
458
				unset($css[$key]);
459
				foreach ($keys as $selector) {
460
					unset($css[$selector]);
461
					$newsel .= ',' . $selector;
462
				}
463
				$css[$newsel] = $value;
464
			}
465
		}
466
		$array = $css;
467
	}
468
469
	/**
470
	 * Removes invalid selectors and their corresponding rule-sets as
471
	 * defined by 4.1.7 in REC-CSS2. This is a very rudimentary check
472
	 * and should be replaced by a full-blown parsing algorithm or
473
	 * regular expression
474
	 * @version 1.4
475
	 */
476
	function discard_invalid_selectors(&$array) {
477
		$invalid = array('+' => true, '~' => true, ',' => true, '>' => true);
0 ignored issues
show
Unused Code introduced by
$invalid 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...
478
		foreach ($array as $selector => $decls) {
479
			$ok = true;
480
			$selectors = array_map('trim', explode(',', $selector));
481
			foreach ($selectors as $s) {
482
				$simple_selectors = preg_split('/\s*[+>~\s]\s*/', $s);
483
				foreach ($simple_selectors as $ss) {
484
					if ($ss === '')
485
						$ok = false;
486
					// could also check $ss for internal structure,
487
					// but that probably would be too slow
488
				}
489
			}
490
			if (!$ok)
491
				unset($array[$selector]);
492
		}
493
	}
494
495
	/**
496
	 * Dissolves properties like padding:10px 10px 10px to padding-top:10px;padding-bottom:10px;...
497
	 * @param string $property
498
	 * @param string $value
499
	 * @return array
500
	 * @version 1.0
501
	 * @see merge_4value_shorthands()
502
	 */
503
	function dissolve_4value_shorthands($property, $value) {
504
		$shorthands = & $GLOBALS['csstidy']['shorthands'];
505
		if (!is_array($shorthands[$property])) {
506
			$return[$property] = $value;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$return was never initialized. Although not strictly required by PHP, it is generally a good practice to add $return = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
507
			return $return;
508
		}
509
510
		$important = '';
511
		if (csstidy::is_important($value)) {
512
			$value = csstidy::gvw_important($value);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $value. This often makes code more readable.
Loading history...
513
			$important = '!important';
514
		}
515
		$values = explode(' ', $value);
516
517
518
		$return = array();
519
		if (count($values) == 4) {
520 View Code Duplication
			for ($i = 0; $i < 4; $i++) {
521
				$return[$shorthands[$property][$i]] = $values[$i] . $important;
522
			}
523
		} elseif (count($values) == 3) {
524
			$return[$shorthands[$property][0]] = $values[0] . $important;
525
			$return[$shorthands[$property][1]] = $values[1] . $important;
526
			$return[$shorthands[$property][3]] = $values[1] . $important;
527
			$return[$shorthands[$property][2]] = $values[2] . $important;
528
		} elseif (count($values) == 2) {
529
			for ($i = 0; $i < 4; $i++) {
530
				$return[$shorthands[$property][$i]] = (($i % 2 != 0)) ? $values[1] . $important : $values[0] . $important;
531
			}
532
		} else {
533 View Code Duplication
			for ($i = 0; $i < 4; $i++) {
534
				$return[$shorthands[$property][$i]] = $values[0] . $important;
535
			}
536
		}
537
538
		return $return;
539
	}
540
541
	/**
542
	 * Explodes a string as explode() does, however, not if $sep is escaped or within a string.
543
	 * @param string $sep seperator
544
	 * @param string $string
545
	 * @return array
546
	 * @version 1.0
547
	 */
548
	function explode_ws($sep, $string) {
549
		$status = 'st';
550
		$to = '';
551
552
		$output = array();
553
		$num = 0;
554
		for ($i = 0, $len = strlen($string); $i < $len; $i++) {
555
			switch ($status) {
556
				case 'st':
557
					if ($string{$i} == $sep && !csstidy::escaped($string, $i)) {
558
						++$num;
559
					} elseif ($string{$i} === '"' || $string{$i} === '\'' || $string{$i} === '(' && !csstidy::escaped($string, $i)) {
560
						$status = 'str';
561
						$to = ($string{$i} === '(') ? ')' : $string{$i};
562
						(isset($output[$num])) ? $output[$num] .= $string{$i} : $output[$num] = $string{$i};
563
					} else {
564
						(isset($output[$num])) ? $output[$num] .= $string{$i} : $output[$num] = $string{$i};
565
					}
566
					break;
567
568
				case 'str':
569
					if ($string{$i} == $to && !csstidy::escaped($string, $i)) {
570
						$status = 'st';
571
					}
572
					(isset($output[$num])) ? $output[$num] .= $string{$i} : $output[$num] = $string{$i};
573
					break;
574
			}
575
		}
576
577
		if (isset($output[0])) {
578
			return $output;
579
		} else {
580
			return array($output);
581
		}
582
	}
583
584
	/**
585
	 * Merges Shorthand properties again, the opposite of dissolve_4value_shorthands()
586
	 * @param array $array
587
	 * @return array
588
	 * @version 1.2
589
	 * @see dissolve_4value_shorthands()
590
	 */
591
	function merge_4value_shorthands($array) {
592
		$return = $array;
593
		$shorthands = & $GLOBALS['csstidy']['shorthands'];
594
595
		foreach ($shorthands as $key => $value) {
596
			if (isset($array[$value[0]]) && isset($array[$value[1]])
597
							&& isset($array[$value[2]]) && isset($array[$value[3]]) && $value !== 0) {
598
				$return[$key] = '';
599
600
				$important = '';
601
				for ($i = 0; $i < 4; $i++) {
602
					$val = $array[$value[$i]];
603
					if (csstidy::is_important($val)) {
604
						$important = '!important';
605
						$return[$key] .= csstidy::gvw_important($val) . ' ';
606
					} else {
607
						$return[$key] .= $val . ' ';
608
					}
609
					unset($return[$value[$i]]);
610
				}
611
				$return[$key] = csstidy_optimise::shorthand(trim($return[$key] . $important));
612
			}
613
		}
614
		return $return;
615
	}
616
617
	/**
618
	 * Dissolve background property
619
	 * @param string $str_value
620
	 * @return array
621
	 * @version 1.0
622
	 * @see merge_bg()
623
	 * @todo full CSS 3 compliance
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
624
	 */
625
	function dissolve_short_bg($str_value) {
626
		// don't try to explose background gradient !
627
		if (stripos($str_value, "gradient(")!==FALSE)
628
			return array('background'=>$str_value);
629
630
		$background_prop_default = & $GLOBALS['csstidy']['background_prop_default'];
631
		$repeat = array('repeat', 'repeat-x', 'repeat-y', 'no-repeat', 'space');
632
		$attachment = array('scroll', 'fixed', 'local');
633
		$clip = array('border', 'padding');
634
		$origin = array('border', 'padding', 'content');
635
		$pos = array('top', 'center', 'bottom', 'left', 'right');
636
		$important = '';
637
		$return = array('background-image' => null, 'background-size' => null, 'background-repeat' => null, 'background-position' => null, 'background-attachment' => null, 'background-clip' => null, 'background-origin' => null, 'background-color' => null);
638
639
		if (csstidy::is_important($str_value)) {
640
			$important = ' !important';
641
			$str_value = csstidy::gvw_important($str_value);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $str_value. This often makes code more readable.
Loading history...
642
		}
643
644
		$str_value = csstidy_optimise::explode_ws(',', $str_value);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $str_value. This often makes code more readable.
Loading history...
645
		for ($i = 0; $i < count($str_value); $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...
646
			$have['clip'] = false;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$have was never initialized. Although not strictly required by PHP, it is generally a good practice to add $have = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
647
			$have['pos'] = false;
0 ignored issues
show
Bug introduced by
The variable $have 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...
648
			$have['color'] = false;
649
			$have['bg'] = false;
650
651
			if (is_array($str_value[$i])) {
652
				$str_value[$i] = $str_value[$i][0];
653
			}
654
			$str_value[$i] = csstidy_optimise::explode_ws(' ', trim($str_value[$i]));
655
656
			for ($j = 0; $j < count($str_value[$i]); $j++) {
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...
657
				if ($have['bg'] === false && (substr($str_value[$i][$j], 0, 4) === 'url(' || $str_value[$i][$j] === 'none')) {
658
					$return['background-image'] .= $str_value[$i][$j] . ',';
659
					$have['bg'] = true;
660 View Code Duplication
				} elseif (in_array($str_value[$i][$j], $repeat, true)) {
661
					$return['background-repeat'] .= $str_value[$i][$j] . ',';
662
				} elseif (in_array($str_value[$i][$j], $attachment, true)) {
663
					$return['background-attachment'] .= $str_value[$i][$j] . ',';
664
				} elseif (in_array($str_value[$i][$j], $clip, true) && !$have['clip']) {
665
					$return['background-clip'] .= $str_value[$i][$j] . ',';
666
					$have['clip'] = true;
667 View Code Duplication
				} elseif (in_array($str_value[$i][$j], $origin, true)) {
668
					$return['background-origin'] .= $str_value[$i][$j] . ',';
669
				} elseif ($str_value[$i][$j]{0} === '(') {
670
					$return['background-size'] .= substr($str_value[$i][$j], 1, -1) . ',';
671
				} elseif (in_array($str_value[$i][$j], $pos, true) || is_numeric($str_value[$i][$j]{0}) || $str_value[$i][$j]{0} === null || $str_value[$i][$j]{0} === '-' || $str_value[$i][$j]{0} === '.') {
672
					$return['background-position'] .= $str_value[$i][$j];
673
					if (!$have['pos'])
674
						$return['background-position'] .= ' '; else
675
						$return['background-position'].= ',';
676
					$have['pos'] = true;
677
				}
678
				elseif (!$have['color']) {
679
					$return['background-color'] .= $str_value[$i][$j] . ',';
680
					$have['color'] = true;
681
				}
682
			}
683
		}
684
685
		foreach ($background_prop_default as $bg_prop => $default_value) {
686 View Code Duplication
			if ($return[$bg_prop] !== null) {
687
				$return[$bg_prop] = substr($return[$bg_prop], 0, -1) . $important;
688
			}
689
			else
690
				$return[$bg_prop] = $default_value . $important;
691
		}
692
		return $return;
693
	}
694
695
	/**
696
	 * Merges all background properties
697
	 * @param array $input_css
698
	 * @return array
699
	 * @version 1.0
700
	 * @see dissolve_short_bg()
701
	 * @todo full CSS 3 compliance
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
702
	 */
703
	function merge_bg($input_css) {
704
		$background_prop_default = & $GLOBALS['csstidy']['background_prop_default'];
705
		// Max number of background images. CSS3 not yet fully implemented
706
		$number_of_values = @max(count(csstidy_optimise::explode_ws(',', $input_css['background-image'])), count(csstidy_optimise::explode_ws(',', $input_css['background-color'])), 1);
707
		// Array with background images to check if BG image exists
708
		$bg_img_array = @csstidy_optimise::explode_ws(',', csstidy::gvw_important($input_css['background-image']));
709
		$new_bg_value = '';
710
		$important = '';
711
712
		// if background properties is here and not empty, don't try anything
713
		if (isset($input_css['background']) AND $input_css['background'])
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
714
			return $input_css;
715
716
		for ($i = 0; $i < $number_of_values; $i++) {
717
			foreach ($background_prop_default as $bg_property => $default_value) {
718
				// Skip if property does not exist
719
				if (!isset($input_css[$bg_property])) {
720
					continue;
721
				}
722
723
				$cur_value = $input_css[$bg_property];
724
				// skip all optimisation if gradient() somewhere
725
				if (stripos($cur_value, "gradient(")!==FALSE)
726
					return $input_css;
727
728
				// Skip some properties if there is no background image
729
				if ((!isset($bg_img_array[$i]) || $bg_img_array[$i] === 'none')
730
								&& ($bg_property === 'background-size' || $bg_property === 'background-position'
731
								|| $bg_property === 'background-attachment' || $bg_property === 'background-repeat')) {
732
					continue;
733
				}
734
735
				// Remove !important
736
				if (csstidy::is_important($cur_value)) {
737
					$important = ' !important';
738
					$cur_value = csstidy::gvw_important($cur_value);
739
				}
740
741
				// Do not add default values
742
				if ($cur_value === $default_value) {
743
					continue;
744
				}
745
746
				$temp = csstidy_optimise::explode_ws(',', $cur_value);
747
748
				if (isset($temp[$i])) {
749
					if ($bg_property === 'background-size') {
750
						$new_bg_value .= '(' . $temp[$i] . ') ';
751
					} else {
752
						$new_bg_value .= $temp[$i] . ' ';
753
					}
754
				}
755
			}
756
757
			$new_bg_value = trim($new_bg_value);
758
			if ($i != $number_of_values - 1)
759
				$new_bg_value .= ',';
760
		}
761
762
		// Delete all background-properties
763
		foreach ($background_prop_default as $bg_property => $default_value) {
764
			unset($input_css[$bg_property]);
765
		}
766
767
		// Add new background property
768
		if ($new_bg_value !== '')
769
			$input_css['background'] = $new_bg_value . $important;
770
		elseif(isset ($input_css['background']))
771
			$input_css['background'] = 'none';
772
773
		return $input_css;
774
	}
775
776
	/**
777
	 * Dissolve font property
778
	 * @param string $str_value
779
	 * @return array
780
	 * @version 1.3
781
	 * @see merge_font()
782
	 */
783
	function dissolve_short_font($str_value) {
784
		$font_prop_default = & $GLOBALS['csstidy']['font_prop_default'];
785
		$font_weight = array('normal', 'bold', 'bolder', 'lighter', 100, 200, 300, 400, 500, 600, 700, 800, 900);
786
		$font_variant = array('normal', 'small-caps');
787
		$font_style = array('normal', 'italic', 'oblique');
788
		$important = '';
789
		$return = array('font-style' => null, 'font-variant' => null, 'font-weight' => null, 'font-size' => null, 'line-height' => null, 'font-family' => null);
790
791
		if (csstidy::is_important($str_value)) {
792
			$important = '!important';
793
			$str_value = csstidy::gvw_important($str_value);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $str_value. This often makes code more readable.
Loading history...
794
		}
795
796
		$have['style'] = false;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$have was never initialized. Although not strictly required by PHP, it is generally a good practice to add $have = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
797
		$have['variant'] = false;
798
		$have['weight'] = false;
799
		$have['size'] = false;
800
		// Detects if font-family consists of several words w/o quotes
801
		$multiwords = false;
802
803
		// Workaround with multiple font-family
804
		$str_value = csstidy_optimise::explode_ws(',', trim($str_value));
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $str_value. This often makes code more readable.
Loading history...
805
806
		$str_value[0] = csstidy_optimise::explode_ws(' ', trim($str_value[0]));
807
808
		for ($j = 0; $j < count($str_value[0]); $j++) {
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...
809
			if ($have['weight'] === false && in_array($str_value[0][$j], $font_weight)) {
810
				$return['font-weight'] = $str_value[0][$j];
811
				$have['weight'] = true;
812
			} elseif ($have['variant'] === false && in_array($str_value[0][$j], $font_variant)) {
813
				$return['font-variant'] = $str_value[0][$j];
814
				$have['variant'] = true;
815
			} elseif ($have['style'] === false && in_array($str_value[0][$j], $font_style)) {
816
				$return['font-style'] = $str_value[0][$j];
817
				$have['style'] = true;
818
			} elseif ($have['size'] === false && (is_numeric($str_value[0][$j]{0}) || $str_value[0][$j]{0} === null || $str_value[0][$j]{0} === '.')) {
819
				$size = csstidy_optimise::explode_ws('/', trim($str_value[0][$j]));
820
				$return['font-size'] = $size[0];
821
				if (isset($size[1])) {
822
					$return['line-height'] = $size[1];
823
				} else {
824
					$return['line-height'] = ''; // don't add 'normal' !
825
				}
826
				$have['size'] = true;
827
			} else {
828
				if (isset($return['font-family'])) {
829
					$return['font-family'] .= ' ' . $str_value[0][$j];
830
					$multiwords = true;
831
				} else {
832
					$return['font-family'] = $str_value[0][$j];
833
				}
834
			}
835
		}
836
		// add quotes if we have several qords in font-family
837
		if ($multiwords !== false) {
838
			$return['font-family'] = '"' . $return['font-family'] . '"';
839
		}
840
		$i = 1;
841
		while (isset($str_value[$i])) {
842
			$return['font-family'] .= ',' . trim($str_value[$i]);
843
			$i++;
844
		}
845
846
		// Fix for 100 and more font-size
847
		if ($have['size'] === false && isset($return['font-weight']) &&
848
						is_numeric($return['font-weight']{0})) {
849
			$return['font-size'] = $return['font-weight'];
850
			unset($return['font-weight']);
851
		}
852
853
		foreach ($font_prop_default as $font_prop => $default_value) {
854 View Code Duplication
			if ($return[$font_prop] !== null) {
855
				$return[$font_prop] = $return[$font_prop] . $important;
856
			}
857
			else
858
				$return[$font_prop] = $default_value . $important;
859
		}
860
		return $return;
861
	}
862
863
	/**
864
	 * Merges all fonts properties
865
	 * @param array $input_css
866
	 * @return array
867
	 * @version 1.3
868
	 * @see dissolve_short_font()
869
	 */
870
	function merge_font($input_css) {
871
		$font_prop_default = & $GLOBALS['csstidy']['font_prop_default'];
872
		$new_font_value = '';
873
		$important = '';
874
		// Skip if not font-family and font-size set
875
		if (isset($input_css['font-family']) && isset($input_css['font-size'])) {
876
			// fix several words in font-family - add quotes
877
			if (isset($input_css['font-family'])) {
878
				$families = explode(",", $input_css['font-family']);
879
				$result_families = array();
880
				foreach ($families as $family) {
881
					$family = trim($family);
882
					$len = strlen($family);
883
					if (strpos($family, " ") &&
884
									!(($family{0} == '"' && $family{$len - 1} == '"') ||
885
									($family{0} == "'" && $family{$len - 1} == "'"))) {
886
						$family = '"' . $family . '"';
887
					}
888
					$result_families[] = $family;
889
				}
890
				$input_css['font-family'] = implode(",", $result_families);
891
			}
892
			foreach ($font_prop_default as $font_property => $default_value) {
893
894
				// Skip if property does not exist
895
				if (!isset($input_css[$font_property])) {
896
					continue;
897
				}
898
899
				$cur_value = $input_css[$font_property];
900
901
				// Skip if default value is used
902
				if ($cur_value === $default_value) {
903
					continue;
904
				}
905
906
				// Remove !important
907
				if (csstidy::is_important($cur_value)) {
908
					$important = '!important';
909
					$cur_value = csstidy::gvw_important($cur_value);
910
				}
911
912
				$new_font_value .= $cur_value;
913
				// Add delimiter
914
				$new_font_value .= ( $font_property === 'font-size' &&
915
								isset($input_css['line-height'])) ? '/' : ' ';
916
			}
917
918
			$new_font_value = trim($new_font_value);
919
920
			// Delete all font-properties
921
			foreach ($font_prop_default as $font_property => $default_value) {
922
				if ($font_property!=='font' OR !$new_font_value)
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
923
					unset($input_css[$font_property]);
924
			}
925
926
			// Add new font property
927
			if ($new_font_value !== '') {
928
				$input_css['font'] = $new_font_value . $important;
929
			}
930
		}
931
932
		return $input_css;
933
	}
934
935
}
936