Completed
Push — update/wordads-shortcode-name ( 7e5709...86de40 )
by
unknown
11:35
created

csstidy_optimise   D

Complexity

Total Complexity 241

Size/Duplication

Total Lines 897
Duplicated Lines 4.46 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 40
loc 897
rs 4.4444
c 0
b 0
f 0
wmc 241
lcom 1
cbo 1

20 Methods

Rating   Name   Duplication   Size   Complexity  
C postparse() 10 40 12
A value() 0 17 4
C shorthands() 8 22 9
C subvalue() 0 47 12
C shorthand() 0 38 15
A compress_important() 0 5 2
C cut_color() 0 60 27
C compress_numbers() 0 41 11
D AnalyseCssNumber() 0 36 10
C merge_selectors() 0 33 8
B discard_invalid_selectors() 0 18 6
D dissolve_4value_shorthands() 6 37 10
D explode_ws() 0 35 17
D merge_4value_shorthands() 0 25 9
C dissolve_short_bg() 11 69 24
C merge_bg() 0 72 21
F dissolve_short_font() 5 79 22
C merge_font() 0 64 20
A __construct() 0 9 1
A csstidy_optimise() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like csstidy_optimise often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use csstidy_optimise, and based on these observations, apply Extract Interface, too.

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
	 * Constructor
45
	 * @param array $css contains the class csstidy
46
	 * @access private
47
	 * @version 1.0
48
	 */
49
	function __construct(&$css) {
50
		$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...
51
		$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...
52
		$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...
53
		$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...
54
		$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...
55
		$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...
56
		$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...
57
	}
58
59
	function csstidy_optimise(&$css) {
60
		$this->__construct($css);
61
	}
62
63
	/**
64
	 * Optimises $css after parsing
65
	 * @access public
66
	 * @version 1.0
67
	 */
68
	function postparse() {
69
		if ($this->parser->get_cfg('preserve_css')) {
70
			return;
71
		}
72
73 View Code Duplication
		if ($this->parser->get_cfg('merge_selectors') === 2) {
74
			foreach ($this->css as $medium => $value) {
75
				$this->merge_selectors($this->css[$medium]);
76
			}
77
		}
78
79 View Code Duplication
		if ($this->parser->get_cfg('discard_invalid_selectors')) {
80
			foreach ($this->css as $medium => $value) {
81
				$this->discard_invalid_selectors($this->css[$medium]);
82
			}
83
		}
84
85
		if ($this->parser->get_cfg('optimise_shorthands') > 0) {
86
			foreach ($this->css as $medium => $value) {
87
				foreach ($value as $selector => $value1) {
88
					$this->css[$medium][$selector] = csstidy_optimise::merge_4value_shorthands($this->css[$medium][$selector]);
89
90
					if ($this->parser->get_cfg('optimise_shorthands') < 2) {
91
						continue;
92
					}
93
94
					$this->css[$medium][$selector] = csstidy_optimise::merge_font($this->css[$medium][$selector]);
95
96
					if ($this->parser->get_cfg('optimise_shorthands') < 3) {
97
						continue;
98
					}
99
100
					$this->css[$medium][$selector] = csstidy_optimise::merge_bg($this->css[$medium][$selector]);
101
					if (empty($this->css[$medium][$selector])) {
102
						unset($this->css[$medium][$selector]);
103
					}
104
				}
105
			}
106
		}
107
	}
108
109
	/**
110
	 * Optimises values
111
	 * @access public
112
	 * @version 1.0
113
	 */
114
	function value() {
115
		$shorthands = & $GLOBALS['csstidy']['shorthands'];
116
117
		// optimise shorthand properties
118
		if (isset($shorthands[$this->property])) {
119
			$temp = csstidy_optimise::shorthand($this->value); // FIXME - move
120
			if ($temp != $this->value) {
121
				$this->parser->log('Optimised shorthand notation (' . $this->property . '): Changed "' . $this->value . '" to "' . $temp . '"', 'Information');
122
			}
123
			$this->value = $temp;
124
		}
125
126
		// Remove whitespace at ! important
127
		if ($this->value != $this->compress_important($this->value)) {
128
			$this->parser->log('Optimised !important', 'Information');
129
		}
130
	}
131
132
	/**
133
	 * Optimises shorthands
134
	 * @access public
135
	 * @version 1.0
136
	 */
137
	function shorthands() {
138
		$shorthands = & $GLOBALS['csstidy']['shorthands'];
139
140
		if (!$this->parser->get_cfg('optimise_shorthands') || $this->parser->get_cfg('preserve_css')) {
141
			return;
142
		}
143
144 View Code Duplication
		if ($this->property === 'font' && $this->parser->get_cfg('optimise_shorthands') > 1) {
145
			$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...
146
			$this->parser->merge_css_blocks($this->at, $this->selector, csstidy_optimise::dissolve_short_font($this->value));
147
		}
148 View Code Duplication
		if ($this->property === 'background' && $this->parser->get_cfg('optimise_shorthands') > 2) {
149
			$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...
150
			$this->parser->merge_css_blocks($this->at, $this->selector, csstidy_optimise::dissolve_short_bg($this->value));
151
		}
152
		if (isset($shorthands[$this->property])) {
153
			$this->parser->merge_css_blocks($this->at, $this->selector, csstidy_optimise::dissolve_4value_shorthands($this->property, $this->value));
154
			if (is_array($shorthands[$this->property])) {
155
				$this->css[$this->at][$this->selector][$this->property] = '';
156
			}
157
		}
158
	}
159
160
	/**
161
	 * Optimises a sub-value
162
	 * @access public
163
	 * @version 1.0
164
	 */
165
	function subvalue() {
166
		$replace_colors = & $GLOBALS['csstidy']['replace_colors'];
167
168
		$this->sub_value = trim($this->sub_value);
169
		if ($this->sub_value == '') { // caution : '0'
170
			return;
171
		}
172
173
		$important = '';
174
		if (csstidy::is_important($this->sub_value)) {
175
			$important = '!important';
176
		}
177
		$this->sub_value = csstidy::gvw_important($this->sub_value);
178
179
		// Compress font-weight
180
		if ($this->property === 'font-weight' && $this->parser->get_cfg('compress_font-weight')) {
181
			if ($this->sub_value === 'bold') {
182
				$this->sub_value = '700';
183
				$this->parser->log('Optimised font-weight: Changed "bold" to "700"', 'Information');
184
			} else if ($this->sub_value === 'normal') {
185
				$this->sub_value = '400';
186
				$this->parser->log('Optimised font-weight: Changed "normal" to "400"', 'Information');
187
			}
188
		}
189
190
		$temp = $this->compress_numbers($this->sub_value);
191
		if (strcasecmp($temp, $this->sub_value) !== 0) {
192
			if (strlen($temp) > strlen($this->sub_value)) {
193
				$this->parser->log('Fixed invalid number: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Warning');
194
			} else {
195
				$this->parser->log('Optimised number: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Information');
196
			}
197
			$this->sub_value = $temp;
198
		}
199
		if ($this->parser->get_cfg('compress_colors')) {
200
			$temp = $this->cut_color($this->sub_value);
201
			if ($temp !== $this->sub_value) {
202
				if (isset($replace_colors[$this->sub_value])) {
203
					$this->parser->log('Fixed invalid color name: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Warning');
204
				} else {
205
					$this->parser->log('Optimised color: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Information');
206
				}
207
				$this->sub_value = $temp;
208
			}
209
		}
210
		$this->sub_value .= $important;
211
	}
212
213
	/**
214
	 * Compresses shorthand values. Example: margin:1px 1px 1px 1px -> margin:1px
215
	 * @param string $value
216
	 * @access public
217
	 * @return string
218
	 * @version 1.0
219
	 */
220
	static function shorthand($value) {
221
		$important = '';
222
		if (csstidy::is_important($value)) {
223
			$values = csstidy::gvw_important($value);
224
			$important = '!important';
225
		}
226
		else
227
			$values = $value;
228
229
		$values = explode(' ', $values);
230
		switch (count($values)) {
231
			case 4:
232
				if ($values[0] == $values[1] && $values[0] == $values[2] && $values[0] == $values[3]) {
233
					return $values[0] . $important;
234
				} elseif ($values[1] == $values[3] && $values[0] == $values[2]) {
235
					return $values[0] . ' ' . $values[1] . $important;
236
				} elseif ($values[1] == $values[3]) {
237
					return $values[0] . ' ' . $values[1] . ' ' . $values[2] . $important;
238
				}
239
				break;
240
241
			case 3:
242
				if ($values[0] == $values[1] && $values[0] == $values[2]) {
243
					return $values[0] . $important;
244
				} elseif ($values[0] == $values[2]) {
245
					return $values[0] . ' ' . $values[1] . $important;
246
				}
247
				break;
248
249
			case 2:
250
				if ($values[0] == $values[1]) {
251
					return $values[0] . $important;
252
				}
253
				break;
254
		}
255
256
		return $value;
257
	}
258
259
	/**
260
	 * Removes unnecessary whitespace in ! important
261
	 * @param string $string
262
	 * @return string
263
	 * @access public
264
	 * @version 1.1
265
	 */
266
	function compress_important(&$string) {
267
		if (csstidy::is_important($string)) {
268
			$string = csstidy::gvw_important($string) . ' !important';		}
269
		return $string;
270
	}
271
272
	/**
273
	 * Color compression function. Converts all rgb() values to #-values and uses the short-form if possible. Also replaces 4 color names by #-values.
274
	 * @param string $color
275
	 * @return string
276
	 * @version 1.1
277
	 */
278
	function cut_color($color) {
279
		$replace_colors = & $GLOBALS['csstidy']['replace_colors'];
280
281
		// rgb(0,0,0) -> #000000 (or #000 in this case later)
282
		if (strtolower(substr($color, 0, 4)) === 'rgb(') {
283
			$color_tmp = substr($color, 4, strlen($color) - 5);
284
			$color_tmp = explode(',', $color_tmp);
285
			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...
286
				$color_tmp[$i] = trim($color_tmp[$i]);
287
				if (substr($color_tmp[$i], -1) === '%') {
288
					$color_tmp[$i] = round((255 * $color_tmp[$i]) / 100);
289
				}
290
				if ($color_tmp[$i] > 255)
291
					$color_tmp[$i] = 255;
292
			}
293
			$color = '#';
294
			for ($i = 0; $i < 3; $i++) {
295
				if ($color_tmp[$i] < 16) {
296
					$color .= '0' . dechex($color_tmp[$i]);
297
				} else {
298
					$color .= dechex($color_tmp[$i]);
299
				}
300
			}
301
		}
302
303
		// Fix bad color names
304
		if (isset($replace_colors[strtolower($color)])) {
305
			$color = $replace_colors[strtolower($color)];
306
		}
307
308
		// #aabbcc -> #abc
309
		if (strlen($color) == 7) {
310
			$color_temp = strtolower($color);
311
			if ($color_temp{0} === '#' && $color_temp{1} == $color_temp{2} && $color_temp{3} == $color_temp{4} && $color_temp{5} == $color_temp{6}) {
312
				$color = '#' . $color{1} . $color{3} . $color{5};
313
			}
314
		}
315
316
		switch (strtolower($color)) {
317
			/* color name -> hex code */
318
			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...
319
			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...
320
			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...
321
			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...
322
323
			/* hex code -> color name */
324
			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...
325
			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...
326
			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...
327
			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...
328
			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...
329
			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...
330
			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...
331
			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...
332
			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...
333
			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...
334
		}
335
336
		return $color;
337
	}
338
339
	/**
340
	 * Compresses numbers (ie. 1.0 becomes 1 or 1.100 becomes 1.1 )
341
	 * @param string $subvalue
342
	 * @return string
343
	 * @version 1.2
344
	 */
345
	function compress_numbers($subvalue) {
346
		$unit_values = & $GLOBALS['csstidy']['unit_values'];
347
		$color_values = & $GLOBALS['csstidy']['color_values'];
348
349
		// for font:1em/1em sans-serif...;
350
		if ($this->property === 'font') {
351
			$temp = explode('/', $subvalue);
352
		} else {
353
			$temp = array($subvalue);
354
		}
355
		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...
356
			// if we are not dealing with a number at this point, do not optimise anything
357
			$number = $this->AnalyseCssNumber($temp[$l]);
358
			if ($number === false) {
359
				return $subvalue;
360
			}
361
362
			// Fix bad colors
363
			if (in_array($this->property, $color_values)) {
364
				if (strlen($temp[$l]) == 3 || strlen($temp[$l]) == 6) {
365
					$temp[$l] = '#' . $temp[$l];
366
				}
367
				else {
368
					$temp[$l] = "0";
369
				}
370
				continue;
371
			}
372
373
			if (abs($number[0]) > 0) {
374
				if ($number[1] == '' && in_array($this->property, $unit_values, true)) {
375
					$number[1] = 'px';
376
				}
377
			} else {
378
				$number[1] = '';
379
			}
380
381
			$temp[$l] = $number[0] . $number[1];
382
		}
383
384
		return ((count($temp) > 1) ? $temp[0] . '/' . $temp[1] : $temp[0]);
385
	}
386
387
	/**
388
	 * Checks if a given string is a CSS valid number. If it is,
389
	 * an array containing the value and unit is returned
390
	 * @param string $string
391
	 * @return array ('unit' if unit is found or '' if no unit exists, number value) or false if no number
392
	 */
393
	function AnalyseCssNumber($string) {
394
		// most simple checks first
395
		if (strlen($string) == 0 || ctype_alpha($string{0})) {
396
			return false;
397
		}
398
399
		$units = & $GLOBALS['csstidy']['units'];
400
		$return = array(0, '');
401
402
		$return[0] = floatval($string);
403
		if (abs($return[0]) > 0 && abs($return[0]) < 1) {
404
			if ($return[0] < 0) {
405
				$return[0] = '-' . ltrim(substr($return[0], 1), '0');
406
			} else {
407
				$return[0] = ltrim($return[0], '0');
408
			}
409
		}
410
411
		// Look for unit and split from value if exists
412
		foreach ($units as $unit) {
413
			$expectUnitAt = strlen($string) - strlen($unit);
414
			if (!($unitInString = stristr($string, $unit))) { // mb_strpos() fails with "false"
415
				continue;
416
			}
417
			$actualPosition = strpos($string, $unitInString);
418
			if ($expectUnitAt === $actualPosition) {
419
				$return[1] = $unit;
420
				$string = substr($string, 0, - strlen($unit));
421
				break;
422
			}
423
		}
424
		if (!is_numeric($string)) {
425
			return false;
426
		}
427
		return $return;
428
	}
429
430
	/**
431
	 * Merges selectors with same properties. Example: a{color:red} b{color:red} -> a,b{color:red}
432
	 * Very basic and has at least one bug. Hopefully there is a replacement soon.
433
	 * @param array $array
434
	 * @return array
435
	 * @access public
436
	 * @version 1.2
437
	 */
438
	function merge_selectors(&$array) {
439
		$css = $array;
440
		foreach ($css as $key => $value) {
441
			if (!isset($css[$key])) {
442
				continue;
443
			}
444
			$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...
445
446
			// Check if properties also exist in another selector
447
			$keys = array();
448
			// PHP bug (?) without $css = $array; here
449
			foreach ($css as $selector => $vali) {
450
				if ($selector == $key) {
451
					continue;
452
				}
453
454
				if ($css[$key] === $vali) {
455
					$keys[] = $selector;
456
				}
457
			}
458
459
			if (!empty($keys)) {
460
				$newsel = $key;
461
				unset($css[$key]);
462
				foreach ($keys as $selector) {
463
					unset($css[$selector]);
464
					$newsel .= ',' . $selector;
465
				}
466
				$css[$newsel] = $value;
467
			}
468
		}
469
		$array = $css;
470
	}
471
472
	/**
473
	 * Removes invalid selectors and their corresponding rule-sets as
474
	 * defined by 4.1.7 in REC-CSS2. This is a very rudimentary check
475
	 * and should be replaced by a full-blown parsing algorithm or
476
	 * regular expression
477
	 * @version 1.4
478
	 */
479
	function discard_invalid_selectors(&$array) {
480
		$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...
481
		foreach ($array as $selector => $decls) {
482
			$ok = true;
483
			$selectors = array_map('trim', explode(',', $selector));
484
			foreach ($selectors as $s) {
485
				$simple_selectors = preg_split('/\s*[+>~\s]\s*/', $s);
486
				foreach ($simple_selectors as $ss) {
487
					if ($ss === '')
488
						$ok = false;
489
					// could also check $ss for internal structure,
490
					// but that probably would be too slow
491
				}
492
			}
493
			if (!$ok)
494
				unset($array[$selector]);
495
		}
496
	}
497
498
	/**
499
	 * Dissolves properties like padding:10px 10px 10px to padding-top:10px;padding-bottom:10px;...
500
	 * @param string $property
501
	 * @param string $value
502
	 * @return array
503
	 * @version 1.0
504
	 * @see merge_4value_shorthands()
505
	 */
506
	static function dissolve_4value_shorthands($property, $value) {
507
		$shorthands = & $GLOBALS['csstidy']['shorthands'];
508
		if (!is_array($shorthands[$property])) {
509
			$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...
510
			return $return;
511
		}
512
513
		$important = '';
514
		if (csstidy::is_important($value)) {
515
			$value = csstidy::gvw_important($value);
516
			$important = '!important';
517
		}
518
		$values = explode(' ', $value);
519
520
521
		$return = array();
522
		if (count($values) == 4) {
523 View Code Duplication
			for ($i = 0; $i < 4; $i++) {
524
				$return[$shorthands[$property][$i]] = $values[$i] . $important;
525
			}
526
		} elseif (count($values) == 3) {
527
			$return[$shorthands[$property][0]] = $values[0] . $important;
528
			$return[$shorthands[$property][1]] = $values[1] . $important;
529
			$return[$shorthands[$property][3]] = $values[1] . $important;
530
			$return[$shorthands[$property][2]] = $values[2] . $important;
531
		} elseif (count($values) == 2) {
532
			for ($i = 0; $i < 4; $i++) {
533
				$return[$shorthands[$property][$i]] = (($i % 2 != 0)) ? $values[1] . $important : $values[0] . $important;
534
			}
535
		} else {
536 View Code Duplication
			for ($i = 0; $i < 4; $i++) {
537
				$return[$shorthands[$property][$i]] = $values[0] . $important;
538
			}
539
		}
540
541
		return $return;
542
	}
543
544
	/**
545
	 * Explodes a string as explode() does, however, not if $sep is escaped or within a string.
546
	 * @param string $sep seperator
547
	 * @param string $string
548
	 * @return array
549
	 * @version 1.0
550
	 */
551
	static function explode_ws($sep, $string) {
552
		$status = 'st';
553
		$to = '';
554
555
		$output = array();
556
		$num = 0;
557
		for ($i = 0, $len = strlen($string); $i < $len; $i++) {
558
			switch ($status) {
559
				case 'st':
560
					if ($string{$i} == $sep && !csstidy::escaped($string, $i)) {
561
						++$num;
562
					} elseif ($string{$i} === '"' || $string{$i} === '\'' || $string{$i} === '(' && !csstidy::escaped($string, $i)) {
563
						$status = 'str';
564
						$to = ($string{$i} === '(') ? ')' : $string{$i};
565
						(isset($output[$num])) ? $output[$num] .= $string{$i} : $output[$num] = $string{$i};
566
					} else {
567
						(isset($output[$num])) ? $output[$num] .= $string{$i} : $output[$num] = $string{$i};
568
					}
569
					break;
570
571
				case 'str':
572
					if ($string{$i} == $to && !csstidy::escaped($string, $i)) {
573
						$status = 'st';
574
					}
575
					(isset($output[$num])) ? $output[$num] .= $string{$i} : $output[$num] = $string{$i};
576
					break;
577
			}
578
		}
579
580
		if (isset($output[0])) {
581
			return $output;
582
		} else {
583
			return array($output);
584
		}
585
	}
586
587
	/**
588
	 * Merges Shorthand properties again, the opposite of dissolve_4value_shorthands()
589
	 * @param array $array
590
	 * @return array
591
	 * @version 1.2
592
	 * @see dissolve_4value_shorthands()
593
	 */
594
	static function merge_4value_shorthands($array) {
595
		$return = $array;
596
		$shorthands = & $GLOBALS['csstidy']['shorthands'];
597
598
		foreach ($shorthands as $key => $value) {
599
			if (isset($array[$value[0]]) && isset($array[$value[1]])
600
							&& isset($array[$value[2]]) && isset($array[$value[3]]) && $value !== 0) {
601
				$return[$key] = '';
602
603
				$important = '';
604
				for ($i = 0; $i < 4; $i++) {
605
					$val = $array[$value[$i]];
606
					if (csstidy::is_important($val)) {
607
						$important = '!important';
608
						$return[$key] .= csstidy::gvw_important($val) . ' ';
609
					} else {
610
						$return[$key] .= $val . ' ';
611
					}
612
					unset($return[$value[$i]]);
613
				}
614
				$return[$key] = csstidy_optimise::shorthand(trim($return[$key] . $important));
615
			}
616
		}
617
		return $return;
618
	}
619
620
	/**
621
	 * Dissolve background property
622
	 * @param string $str_value
623
	 * @return array
624
	 * @version 1.0
625
	 * @see merge_bg()
626
	 * @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...
627
	 */
628
	static function dissolve_short_bg($str_value) {
629
		// don't try to explose background gradient !
630
		if (stripos($str_value, "gradient(")!==FALSE)
631
			return array('background'=>$str_value);
632
633
		$background_prop_default = & $GLOBALS['csstidy']['background_prop_default'];
634
		$repeat = array('repeat', 'repeat-x', 'repeat-y', 'no-repeat', 'space');
635
		$attachment = array('scroll', 'fixed', 'local');
636
		$clip = array('border', 'padding');
637
		$origin = array('border', 'padding', 'content');
638
		$pos = array('top', 'center', 'bottom', 'left', 'right');
639
		$important = '';
640
		$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);
641
642
		if (csstidy::is_important($str_value)) {
643
			$important = ' !important';
644
			$str_value = csstidy::gvw_important($str_value);
645
		}
646
647
		$str_value = csstidy_optimise::explode_ws(',', $str_value);
648
		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...
649
			$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...
650
			$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...
651
			$have['color'] = false;
652
			$have['bg'] = false;
653
654
			if (is_array($str_value[$i])) {
655
				$str_value[$i] = $str_value[$i][0];
656
			}
657
			$str_value[$i] = csstidy_optimise::explode_ws(' ', trim($str_value[$i]));
658
659
			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...
660
				if ($have['bg'] === false && (substr($str_value[$i][$j], 0, 4) === 'url(' || $str_value[$i][$j] === 'none')) {
661
					$return['background-image'] .= $str_value[$i][$j] . ',';
662
					$have['bg'] = true;
663 View Code Duplication
				} elseif (in_array($str_value[$i][$j], $repeat, true)) {
664
					$return['background-repeat'] .= $str_value[$i][$j] . ',';
665
				} elseif (in_array($str_value[$i][$j], $attachment, true)) {
666
					$return['background-attachment'] .= $str_value[$i][$j] . ',';
667
				} elseif (in_array($str_value[$i][$j], $clip, true) && !$have['clip']) {
668
					$return['background-clip'] .= $str_value[$i][$j] . ',';
669
					$have['clip'] = true;
670 View Code Duplication
				} elseif (in_array($str_value[$i][$j], $origin, true)) {
671
					$return['background-origin'] .= $str_value[$i][$j] . ',';
672
				} elseif ($str_value[$i][$j]{0} === '(') {
673
					$return['background-size'] .= substr($str_value[$i][$j], 1, -1) . ',';
674
				} 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} === '.') {
675
					$return['background-position'] .= $str_value[$i][$j];
676
					if (!$have['pos'])
677
						$return['background-position'] .= ' '; else
678
						$return['background-position'].= ',';
679
					$have['pos'] = true;
680
				}
681
				elseif (!$have['color']) {
682
					$return['background-color'] .= $str_value[$i][$j] . ',';
683
					$have['color'] = true;
684
				}
685
			}
686
		}
687
688
		foreach ($background_prop_default as $bg_prop => $default_value) {
689 View Code Duplication
			if ($return[$bg_prop] !== null) {
690
				$return[$bg_prop] = substr($return[$bg_prop], 0, -1) . $important;
691
			}
692
			else
693
				$return[$bg_prop] = $default_value . $important;
694
		}
695
		return $return;
696
	}
697
698
	/**
699
	 * Merges all background properties
700
	 * @param array $input_css
701
	 * @return array
702
	 * @version 1.0
703
	 * @see dissolve_short_bg()
704
	 * @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...
705
	 */
706
	static function merge_bg($input_css) {
707
		$background_prop_default = & $GLOBALS['csstidy']['background_prop_default'];
708
		// Max number of background images. CSS3 not yet fully implemented
709
		$number_of_values = @max(count(csstidy_optimise::explode_ws(',', $input_css['background-image'])), count(csstidy_optimise::explode_ws(',', $input_css['background-color'])), 1);
710
		// Array with background images to check if BG image exists
711
		$bg_img_array = @csstidy_optimise::explode_ws(',', csstidy::gvw_important($input_css['background-image']));
712
		$new_bg_value = '';
713
		$important = '';
714
715
		// if background properties is here and not empty, don't try anything
716
		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...
717
			return $input_css;
718
719
		for ($i = 0; $i < $number_of_values; $i++) {
720
			foreach ($background_prop_default as $bg_property => $default_value) {
721
				// Skip if property does not exist
722
				if (!isset($input_css[$bg_property])) {
723
					continue;
724
				}
725
726
				$cur_value = $input_css[$bg_property];
727
				// skip all optimisation if gradient() somewhere
728
				if (stripos($cur_value, "gradient(")!==FALSE)
729
					return $input_css;
730
731
				// Skip some properties if there is no background image
732
				if ((!isset($bg_img_array[$i]) || $bg_img_array[$i] === 'none')
733
								&& ($bg_property === 'background-size' || $bg_property === 'background-position'
734
								|| $bg_property === 'background-attachment' || $bg_property === 'background-repeat')) {
735
					continue;
736
				}
737
738
				// Remove !important
739
				if (csstidy::is_important($cur_value)) {
740
					$important = ' !important';
741
					$cur_value = csstidy::gvw_important($cur_value);
742
				}
743
744
				// Do not add default values
745
				if ($cur_value === $default_value) {
746
					continue;
747
				}
748
749
				$temp = csstidy_optimise::explode_ws(',', $cur_value);
750
751
				if (isset($temp[$i])) {
752
					if ($bg_property === 'background-size') {
753
						$new_bg_value .= '(' . $temp[$i] . ') ';
754
					} else {
755
						$new_bg_value .= $temp[$i] . ' ';
756
					}
757
				}
758
			}
759
760
			$new_bg_value = trim($new_bg_value);
761
			if ($i != $number_of_values - 1)
762
				$new_bg_value .= ',';
763
		}
764
765
		// Delete all background-properties
766
		foreach ($background_prop_default as $bg_property => $default_value) {
767
			unset($input_css[$bg_property]);
768
		}
769
770
		// Add new background property
771
		if ($new_bg_value !== '')
772
			$input_css['background'] = $new_bg_value . $important;
773
		elseif(isset ($input_css['background']))
774
			$input_css['background'] = 'none';
775
776
		return $input_css;
777
	}
778
779
	/**
780
	 * Dissolve font property
781
	 * @param string $str_value
782
	 * @return array
783
	 * @version 1.3
784
	 * @see merge_font()
785
	 */
786
	static function dissolve_short_font($str_value) {
787
		$font_prop_default = & $GLOBALS['csstidy']['font_prop_default'];
788
		$font_weight = array('normal', 'bold', 'bolder', 'lighter', 100, 200, 300, 400, 500, 600, 700, 800, 900);
789
		$font_variant = array('normal', 'small-caps');
790
		$font_style = array('normal', 'italic', 'oblique');
791
		$important = '';
792
		$return = array('font-style' => null, 'font-variant' => null, 'font-weight' => null, 'font-size' => null, 'line-height' => null, 'font-family' => null);
793
794
		if (csstidy::is_important($str_value)) {
795
			$important = '!important';
796
			$str_value = csstidy::gvw_important($str_value);
797
		}
798
799
		$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...
800
		$have['variant'] = false;
801
		$have['weight'] = false;
802
		$have['size'] = false;
803
		// Detects if font-family consists of several words w/o quotes
804
		$multiwords = false;
805
806
		// Workaround with multiple font-family
807
		$str_value = csstidy_optimise::explode_ws(',', trim($str_value));
808
809
		$str_value[0] = csstidy_optimise::explode_ws(' ', trim($str_value[0]));
810
811
		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...
812
			if ($have['weight'] === false && in_array($str_value[0][$j], $font_weight)) {
813
				$return['font-weight'] = $str_value[0][$j];
814
				$have['weight'] = true;
815
			} elseif ($have['variant'] === false && in_array($str_value[0][$j], $font_variant)) {
816
				$return['font-variant'] = $str_value[0][$j];
817
				$have['variant'] = true;
818
			} elseif ($have['style'] === false && in_array($str_value[0][$j], $font_style)) {
819
				$return['font-style'] = $str_value[0][$j];
820
				$have['style'] = true;
821
			} elseif ($have['size'] === false && (is_numeric($str_value[0][$j]{0}) || $str_value[0][$j]{0} === null || $str_value[0][$j]{0} === '.')) {
822
				$size = csstidy_optimise::explode_ws('/', trim($str_value[0][$j]));
823
				$return['font-size'] = $size[0];
824
				if (isset($size[1])) {
825
					$return['line-height'] = $size[1];
826
				} else {
827
					$return['line-height'] = ''; // don't add 'normal' !
828
				}
829
				$have['size'] = true;
830
			} else {
831
				if (isset($return['font-family'])) {
832
					$return['font-family'] .= ' ' . $str_value[0][$j];
833
					$multiwords = true;
834
				} else {
835
					$return['font-family'] = $str_value[0][$j];
836
				}
837
			}
838
		}
839
		// add quotes if we have several qords in font-family
840
		if ($multiwords !== false) {
841
			$return['font-family'] = '"' . $return['font-family'] . '"';
842
		}
843
		$i = 1;
844
		while (isset($str_value[$i])) {
845
			$return['font-family'] .= ',' . trim($str_value[$i]);
846
			$i++;
847
		}
848
849
		// Fix for 100 and more font-size
850
		if ($have['size'] === false && isset($return['font-weight']) &&
851
						is_numeric($return['font-weight']{0})) {
852
			$return['font-size'] = $return['font-weight'];
853
			unset($return['font-weight']);
854
		}
855
856
		foreach ($font_prop_default as $font_prop => $default_value) {
857 View Code Duplication
			if ($return[$font_prop] !== null) {
858
				$return[$font_prop] = $return[$font_prop] . $important;
859
			}
860
			else
861
				$return[$font_prop] = $default_value . $important;
862
		}
863
		return $return;
864
	}
865
866
	/**
867
	 * Merges all fonts properties
868
	 * @param array $input_css
869
	 * @return array
870
	 * @version 1.3
871
	 * @see dissolve_short_font()
872
	 */
873
	static function merge_font($input_css) {
874
		$font_prop_default = & $GLOBALS['csstidy']['font_prop_default'];
875
		$new_font_value = '';
876
		$important = '';
877
		// Skip if not font-family and font-size set
878
		if (isset($input_css['font-family']) && isset($input_css['font-size'])) {
879
			// fix several words in font-family - add quotes
880
			if (isset($input_css['font-family'])) {
881
				$families = explode(",", $input_css['font-family']);
882
				$result_families = array();
883
				foreach ($families as $family) {
884
					$family = trim($family);
885
					$len = strlen($family);
886
					if (strpos($family, " ") &&
887
									!(($family{0} == '"' && $family{$len - 1} == '"') ||
888
									($family{0} == "'" && $family{$len - 1} == "'"))) {
889
						$family = '"' . $family . '"';
890
					}
891
					$result_families[] = $family;
892
				}
893
				$input_css['font-family'] = implode(",", $result_families);
894
			}
895
			foreach ($font_prop_default as $font_property => $default_value) {
896
897
				// Skip if property does not exist
898
				if (!isset($input_css[$font_property])) {
899
					continue;
900
				}
901
902
				$cur_value = $input_css[$font_property];
903
904
				// Skip if default value is used
905
				if ($cur_value === $default_value) {
906
					continue;
907
				}
908
909
				// Remove !important
910
				if (csstidy::is_important($cur_value)) {
911
					$important = '!important';
912
					$cur_value = csstidy::gvw_important($cur_value);
913
				}
914
915
				$new_font_value .= $cur_value;
916
				// Add delimiter
917
				$new_font_value .= ( $font_property === 'font-size' &&
918
								isset($input_css['line-height'])) ? '/' : ' ';
919
			}
920
921
			$new_font_value = trim($new_font_value);
922
923
			// Delete all font-properties
924
			foreach ($font_prop_default as $font_property => $default_value) {
925
				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...
926
					unset($input_css[$font_property]);
927
			}
928
929
			// Add new font property
930
			if ($new_font_value !== '') {
931
				$input_css['font'] = $new_font_value . $important;
932
			}
933
		}
934
935
		return $input_css;
936
	}
937
938
}
939