csstidy_print::_reset()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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