Completed
Push — branch-4.0 ( fc0d6f...bf547c )
by
unknown
08:22
created

csstidy_print::_print()   F

Complexity

Conditions 30
Paths 3073

Size

Total Lines 109
Code Lines 75

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 30
eloc 75
nc 3073
nop 2
dl 0
loc 109
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * CSSTidy - CSS Parser and Optimiser
5
 *
6
 * CSS Printing class
7
 * This class prints 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 Cedric Morin (cedric at yterium dot com) 2010
31
 */
32
33
/**
34
 * CSS Printing class
35
 *
36
 * This class prints CSS data generated by csstidy.
37
 *
38
 * @package csstidy
39
 * @author Florian Schmitz (floele at gmail dot com) 2005-2006
40
 * @version 1.0.1
41
 */
42
class csstidy_print {
43
44
	/**
45
	 * Saves the input CSS string
46
	 * @var string
47
	 * @access private
48
	 */
49
	public $input_css = '';
50
	/**
51
	 * Saves the formatted CSS string
52
	 * @var string
53
	 * @access public
54
	 */
55
	public $output_css = '';
56
	/**
57
	 * Saves the formatted CSS string (plain text)
58
	 * @var string
59
	 * @access public
60
	 */
61
	public $output_css_plain = '';
62
63
	/**
64
	 * Constructor
65
	 * @param array $css contains the class csstidy
66
	 * @access private
67
	 * @version 1.0
68
	 */
69
	function csstidy_print(&$css) {
0 ignored issues
show
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
70
		$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...
71
		$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...
72
		$this->template = & $css->template;
0 ignored issues
show
Bug introduced by
The property template 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...
73
		$this->tokens = & $css->tokens;
0 ignored issues
show
Bug introduced by
The property tokens 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...
74
		$this->charset = & $css->charset;
0 ignored issues
show
Bug introduced by
The property charset 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...
75
		$this->import = & $css->import;
0 ignored issues
show
Bug introduced by
The property import 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...
76
		$this->namespace = & $css->namespace;
0 ignored issues
show
Bug introduced by
The property namespace 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...
77
	}
78
79
	/**
80
	 * Resets output_css and output_css_plain (new css code)
81
	 * @access private
82
	 * @version 1.0
83
	 */
84
	function _reset() {
85
		$this->output_css = '';
86
		$this->output_css_plain = '';
87
	}
88
89
	/**
90
	 * Returns the CSS code as plain text
91
	 * @param string $default_media default @media to add to selectors without any @media
92
	 * @return string
93
	 * @access public
94
	 * @version 1.0
95
	 */
96
	function plain($default_media='') {
97
		$this->_print(true, $default_media);
98
		return $this->output_css_plain;
99
	}
100
101
	/**
102
	 * Returns the formatted CSS code
103
	 * @param string $default_media default @media to add to selectors without any @media
104
	 * @return string
105
	 * @access public
106
	 * @version 1.0
107
	 */
108
	function formatted($default_media='') {
109
		$this->_print(false, $default_media);
110
		return $this->output_css;
111
	}
112
113
	/**
114
	 * Returns the formatted CSS code to make a complete webpage
115
	 * @param string $doctype shorthand for the document type
116
	 * @param bool $externalcss indicates whether styles to be attached internally or as an external stylesheet
117
	 * @param string $title title to be added in the head of the document
118
	 * @param string $lang two-letter language code to be added to the output
119
	 * @return string
120
	 * @access public
121
	 * @version 1.4
122
	 */
123
	function formatted_page($doctype='xhtml1.1', $externalcss=true, $title='', $lang='en') {
124
		switch ($doctype) {
125
			case 'xhtml1.0strict':
126
				$doctype_output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
127
			"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
128
				break;
129
			case 'xhtml1.1':
130
			default:
131
				$doctype_output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
132
				"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">';
133
				break;
134
		}
135
136
		$output = $cssparsed = '';
0 ignored issues
show
Unused Code introduced by
$cssparsed 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...
137
		$this->output_css_plain = & $output;
138
139
		$output .= $doctype_output . "\n" . '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="' . $lang . '"';
140
		$output .= ( $doctype === 'xhtml1.1') ? '>' : ' lang="' . $lang . '">';
141
		$output .= "\n<head>\n    <title>$title</title>";
142
143
		if ($externalcss) {
144
			$output .= "\n    <style type=\"text/css\">\n";
145
			$cssparsed = file_get_contents('cssparsed.css');
146
			$output .= $cssparsed; // Adds an invisible BOM or something, but not in css_optimised.php
147
			$output .= "\n</style>";
148
		} else {
149
			$output .= "\n" . '    <link rel="stylesheet" type="text/css" href="cssparsed.css" />';
150
//			}
151
		}
152
		$output .= "\n</head>\n<body><code id=\"copytext\">";
153
		$output .= $this->formatted();
154
		$output .= '</code>' . "\n" . '</body></html>';
155
		return $this->output_css_plain;
156
	}
157
158
	/**
159
	 * Returns the formatted CSS Code and saves it into $this->output_css and $this->output_css_plain
160
	 * @param bool $plain plain text or not
161
	 * @param string $default_media default @media to add to selectors without any @media
162
	 * @access private
163
	 * @version 2.0
164
	 */
165
	function _print($plain = false, $default_media='') {
166
		if ($this->output_css && $this->output_css_plain) {
167
			return;
168
		}
169
170
		$output = '';
171
		if (!$this->parser->get_cfg('preserve_css')) {
172
			$this->_convert_raw_css($default_media);
173
		}
174
175
		$template = & $this->template;
176
177
		if ($plain) {
178
			$template = array_map('strip_tags', $template);
179
		}
180
181
		if ($this->parser->get_cfg('timestamp')) {
182
			array_unshift($this->tokens, array(COMMENT, ' CSSTidy ' . $this->parser->version . ': ' . date('r') . ' '));
183
		}
184
185
		if (!empty($this->charset)) {
186
			$output .= $template[0] . '@charset ' . $template[5] . $this->charset . $template[6];
187
		}
188
189
		if (!empty($this->import)) {
190
			for ($i = 0, $size = count($this->import); $i < $size; $i++) {
191
				$import_components = explode(' ', $this->import[$i]);
192
				if (substr($import_components[0], 0, 4) === 'url(' && substr($import_components[0], -1, 1) === ')') {
193
					$import_components[0] = '\'' . trim(substr($import_components[0], 4, -1), "'\"") . '\'';
194
					$this->import[$i] = implode(' ', $import_components);
195
					$this->parser->log('Optimised @import : Removed "url("', 'Information');
196
				}
197
				$output .= $template[0] . '@import ' . $template[5] . $this->import[$i] . $template[6];
198
			}
199
		}
200
201
		if (!empty($this->namespace)) {
202
			if (substr($this->namespace, 0, 4) === 'url(' && substr($this->namespace, -1, 1) === ')') {
203
				$this->namespace = '\'' . substr($this->namespace, 4, -1) . '\'';
204
				$this->parser->log('Optimised @namespace : Removed "url("', 'Information');
205
			}
206
			$output .= $template[0] . '@namespace ' . $template[5] . $this->namespace . $template[6];
207
		}
208
209
		$output .= $template[13];
210
		$in_at_out = '';
211
		$out = & $output;
212
213
		foreach ($this->tokens as $key => $token) {
214
			switch ($token[0]) {
215
				case AT_START:
216
					$out .= $template[0] . $this->_htmlsp($token[1], $plain) . $template[1];
217
					$out = & $in_at_out;
218
					break;
219
220
				case SEL_START:
221
					if ($this->parser->get_cfg('lowercase_s'))
222
						$token[1] = strtolower($token[1]);
223
					$out .= ( $token[1]{0} !== '@') ? $template[2] . $this->_htmlsp($token[1], $plain) : $template[0] . $this->_htmlsp($token[1], $plain);
224
					$out .= $template[3];
225
					break;
226
227
				case PROPERTY:
228
					if ($this->parser->get_cfg('case_properties') === 2) {
229
						$token[1] = strtoupper($token[1]);
230
					} elseif ($this->parser->get_cfg('case_properties') === 1) {
231
						$token[1] = strtolower($token[1]);
232
					}
233
					$out .= $template[4] . $this->_htmlsp($token[1], $plain) . ':' . $template[5];
234
					break;
235
236
				case VALUE:
237
					$out .= $this->_htmlsp($token[1], $plain);
238
					if ($this->_seeknocomment($key, 1) == SEL_END && $this->parser->get_cfg('remove_last_;')) {
239
						$out .= str_replace(';', '', $template[6]);
240
					} else {
241
						$out .= $template[6];
242
					}
243
					break;
244
245
				case SEL_END:
246
					$out .= $template[7];
247
					if ($this->_seeknocomment($key, 1) != AT_END)
248
						$out .= $template[8];
249
					break;
250
251
				case AT_END:
252
					$out = & $output;
253
					$out .= $template[10] . str_replace("\n", "\n" . $template[10], $in_at_out);
254
					$in_at_out = '';
255
					$out .= $template[9];
256
					break;
257
258
				case COMMENT:
259
					$out .= $template[11] . '/*' . $this->_htmlsp($token[1], $plain) . '*/' . $template[12];
260
					break;
261
			}
262
		}
263
264
		$output = trim($output);
265
266
		if (!$plain) {
267
			$this->output_css = $output;
268
			$this->_print(true);
269
		} else {
270
			// If using spaces in the template, don't want these to appear in the plain output
271
			$this->output_css_plain = str_replace('&#160;', '', $output);
272
		}
273
	}
274
275
	/**
276
	 * Gets the next token type which is $move away from $key, excluding comments
277
	 * @param integer $key current position
278
	 * @param integer $move move this far
279
	 * @return mixed a token type
280
	 * @access private
281
	 * @version 1.0
282
	 */
283
	function _seeknocomment($key, $move) {
284
		$go = ($move > 0) ? 1 : -1;
285
		for ($i = $key + 1; abs($key - $i) - 1 < abs($move); $i += $go) {
286
			if (!isset($this->tokens[$i])) {
287
				return;
288
			}
289
			if ($this->tokens[$i][0] == COMMENT) {
290
				$move += 1;
291
				continue;
292
			}
293
			return $this->tokens[$i][0];
294
		}
295
	}
296
297
	/**
298
	 * Converts $this->css array to a raw array ($this->tokens)
299
	 * @param string $default_media default @media to add to selectors without any @media
300
	 * @access private
301
	 * @version 1.0
302
	 */
303
	function _convert_raw_css($default_media='') {
304
		$this->tokens = array();
305
306
		foreach ($this->css as $medium => $val) {
307
			if ($this->parser->get_cfg('sort_selectors'))
308
				ksort($val);
309 View Code Duplication
			if (intval($medium) < DEFAULT_AT) {
310
				$this->parser->_add_token(AT_START, $medium, true);
311
			}
312
			elseif ($default_media) {
313
				$this->parser->_add_token(AT_START, $default_media, true);
314
			}
315
316
			foreach ($val as $selector => $vali) {
317
				if ($this->parser->get_cfg('sort_properties'))
318
					ksort($vali);
319
				$this->parser->_add_token(SEL_START, $selector, true);
320
321
				foreach ($vali as $property => $valj) {
322
					$this->parser->_add_token(PROPERTY, $property, true);
323
					$this->parser->_add_token(VALUE, $valj, true);
324
				}
325
326
				$this->parser->_add_token(SEL_END, $selector, true);
327
			}
328
329 View Code Duplication
			if (intval($medium) < DEFAULT_AT) {
330
				$this->parser->_add_token(AT_END, $medium, true);
331
			}
332
			elseif ($default_media) {
333
				$this->parser->_add_token(AT_END, $default_media, true);
334
			}
335
		}
336
	}
337
338
	/**
339
	 * Same as htmlspecialchars, only that chars are not replaced if $plain !== true. This makes  print_code() cleaner.
340
	 * @param string $string
341
	 * @param bool $plain
342
	 * @return string
343
	 * @see csstidy_print::_print()
344
	 * @access private
345
	 * @version 1.0
346
	 */
347
	function _htmlsp($string, $plain) {
348
		if (!$plain) {
349
			return htmlspecialchars($string, ENT_QUOTES, 'utf-8');
350
		}
351
		return $string;
352
	}
353
354
	/**
355
	 * Get compression ratio
356
	 * @access public
357
	 * @return float
358
	 * @version 1.2
359
	 */
360
	function get_ratio() {
361
		if (!$this->output_css_plain) {
362
			$this->formatted();
363
		}
364
		return round((strlen($this->input_css) - strlen($this->output_css_plain)) / strlen($this->input_css), 3) * 100;
365
	}
366
367
	/**
368
	 * Get difference between the old and new code in bytes and prints the code if necessary.
369
	 * @access public
370
	 * @return string
371
	 * @version 1.1
372
	 */
373
	function get_diff() {
374
		if (!$this->output_css_plain) {
375
			$this->formatted();
376
		}
377
378
		$diff = strlen($this->output_css_plain) - strlen($this->input_css);
379
380
		if ($diff > 0) {
381
			return '+' . $diff;
382
		} elseif ($diff == 0) {
383
			return '+-' . $diff;
384
		}
385
386
		return $diff;
387
	}
388
389
	/**
390
	 * Get the size of either input or output CSS in KB
391
	 * @param string $loc default is "output"
392
	 * @access public
393
	 * @return integer
394
	 * @version 1.0
395
	 */
396
	function size($loc = 'output') {
397
		if ($loc === 'output' && !$this->output_css) {
398
			$this->formatted();
399
		}
400
401
		if ($loc === 'input') {
402
			return (strlen($this->input_css) / 1000);
403
		} else {
404
			return (strlen($this->output_css_plain) / 1000);
405
		}
406
	}
407
408
}
409