csstidy::gvw_important()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
1
<?php
2
/**
3
 * CSSTidy - CSS Parser and Optimiser
4
 *
5
 * CSS Parser class
6
 *
7
 * Copyright 2005, 2006, 2007 Florian Schmitz
8
 *
9
 * This file is part of CSSTidy.
10
 *
11
 *   CSSTidy is free software; you can redistribute it and/or modify
12
 *   it under the terms of the GNU Lesser General Public License as published by
13
 *   the Free Software Foundation; either version 2.1 of the License, or
14
 *   (at your option) any later version.
15
 *
16
 *   CSSTidy is distributed in the hope that it will be useful,
17
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 *   GNU Lesser General Public License for more details.
20
 *
21
 *   You should have received a copy of the GNU Lesser General Public License
22
 *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
23
 *
24
 * @license https://opensource.org/licenses/lgpl-license.php GNU Lesser General Public License
25
 * @package csstidy
26
 * @author Florian Schmitz (floele at gmail dot com) 2005-2007
27
 * @author Brett Zamir (brettz9 at yahoo dot com) 2007
28
 * @author Nikolay Matsievsky (speed at webo dot name) 2009-2010
29
 * @author Cedric Morin (cedric at yterium dot com) 2010
30
 */
31
/**
32
 * Defines ctype functions if required
33
 *
34
 * @version 1.0
35
 */
36
require_once( dirname( __FILE__ ) . '/class.csstidy_ctype.php' );
37
38
/**
39
 * Various CSS data needed for correct optimisations etc.
40
 *
41
 * @version 1.3
42
 */
43
require( dirname( __FILE__ ) . '/data.inc.php' );
44
45
/**
46
 * Contains a class for printing CSS code
47
 *
48
 * @version 1.0
49
 */
50
require( dirname( __FILE__ ) . '/class.csstidy_print.php' );
51
52
/**
53
 * Contains a class for optimising CSS code
54
 *
55
 * @version 1.0
56
 */
57
require( dirname( __FILE__ ) . '/class.csstidy_optimise.php' );
58
59
/**
60
 * CSS Parser class
61
 *
62
63
 * This class represents a CSS parser which reads CSS code and saves it in an array.
64
 * In opposite to most other CSS parsers, it does not use regular expressions and
65
 * thus has full CSS2 support and a higher reliability.
66
 * Additional to that it applies some optimisations and fixes to the CSS code.
67
 * An online version should be available here: https://cdburnerxp.se/cssparse/css_optimiser.php
68
 * @package csstidy
69
 * @author Florian Schmitz (floele at gmail dot com) 2005-2006
70
 * @version 1.3.1
71
 */
72
class csstidy {
73
74
	/**
75
	 * Saves the parsed CSS. This array is empty if preserve_css is on.
76
	 * @var array
77
	 * @access public
78
	 */
79
	public $css = array();
80
	/**
81
	 * Saves the parsed CSS (raw)
82
	 * @var array
83
	 * @access private
84
	 */
85
	public $tokens = array();
86
	/**
87
	 * Printer class
88
	 * @see csstidy_print
89
	 * @var object
90
	 * @access public
91
	 */
92
	public $print;
93
	/**
94
	 * Optimiser class
95
	 * @see csstidy_optimise
96
	 * @var object
97
	 * @access private
98
	 */
99
	public $optimise;
100
	/**
101
	 * Saves the CSS charset (@charset)
102
	 * @var string
103
	 * @access private
104
	 */
105
	public $charset = '';
106
	/**
107
	 * Saves all @import URLs
108
	 * @var array
109
	 * @access private
110
	 */
111
	public $import = array();
112
	/**
113
	 * Saves the namespace
114
	 * @var string
115
	 * @access private
116
	 */
117
	public $namespace = '';
118
	/**
119
	 * Contains the version of csstidy
120
	 * @var string
121
	 * @access private
122
	 */
123
	public $version = '1.3';
124
	/**
125
	 * Stores the settings
126
	 * @var array
127
	 * @access private
128
	 */
129
	public $settings = array();
130
	/**
131
	 * Saves the parser-status.
132
	 *
133
	 * Possible values:
134
	 * - is = in selector
135
	 * - ip = in property
136
	 * - iv = in value
137
	 * - instr = in string (started at " or ' or ( )
138
	 * - ic = in comment (ignore everything)
139
	 * - at = in @-block
140
	 *
141
	 * @var string
142
	 * @access private
143
	 */
144
	public $status = 'is';
145
	/**
146
	 * Saves the current at rule (@media)
147
	 * @var string
148
	 * @access private
149
	 */
150
	public $at = '';
151
	/**
152
	 * Saves the current selector
153
	 * @var string
154
	 * @access private
155
	 */
156
	public $selector = '';
157
	/**
158
	 * Saves the current property
159
	 * @var string
160
	 * @access private
161
	 */
162
	public $property = '';
163
	/**
164
	 * Saves the position of , in selectors
165
	 * @var array
166
	 * @access private
167
	 */
168
	public $sel_separate = array();
169
	/**
170
	 * Saves the current value
171
	 * @var string
172
	 * @access private
173
	 */
174
	public $value = '';
175
	/**
176
	 * Saves the current sub-value
177
	 *
178
	 * Example for a subvalue:
179
	 * background:url(foo.png) red no-repeat;
180
	 * "url(foo.png)", "red", and  "no-repeat" are subvalues,
181
	 * separated by whitespace
182
	 * @var string
183
	 * @access private
184
	 */
185
	public $sub_value = '';
186
	/**
187
	 * Array which saves all subvalues for a property.
188
	 * @var array
189
	 * @see sub_value
190
	 * @access private
191
	 */
192
	public $sub_value_arr = array();
193
	/**
194
	 * Saves the stack of characters that opened the current strings
195
	 * @var array
196
	 * @access private
197
	 */
198
	public $str_char = array();
199
	public $cur_string = array();
200
	/**
201
	 * Status from which the parser switched to ic or instr
202
	 * @var array
203
	 * @access private
204
	 */
205
	public $from = array();
206
	/**
207
	/**
208
	 * =true if in invalid at-rule
209
	 * @var bool
210
	 * @access private
211
	 */
212
	public $invalid_at = false;
213
	/**
214
	 * =true if something has been added to the current selector
215
	 * @var bool
216
	 * @access private
217
	 */
218
	public $added = false;
219
	/**
220
	 * Array which saves the message log
221
	 * @var array
222
	 * @access private
223
	 */
224
	public $log = array();
225
	/**
226
	 * Saves the line number
227
	 * @var integer
228
	 * @access private
229
	 */
230
	public $line = 1;
231
	/**
232
	 * Marks if we need to leave quotes for a string
233
	 * @var array
234
	 * @access private
235
	 */
236
	public $quoted_string = array();
237
238
	/**
239
	 * List of tokens
240
	 * @var string
241
	 */
242
	public $tokens_list = "";
243
244
	/**
245
	 * Loads standard template and sets default settings
246
	 * @access private
247
	 * @version 1.3
248
	 */
249
	function __construct() {
250
		$this->settings['remove_bslash'] = true;
251
		$this->settings['compress_colors'] = true;
252
		$this->settings['compress_font-weight'] = true;
253
		$this->settings['lowercase_s'] = false;
254
		/*
255
		  1 common shorthands optimization
256
		  2 + font property optimization
257
		  3 + background property optimization
258
		 */
259
		$this->settings['optimise_shorthands'] = 1;
260
		$this->settings['remove_last_;'] = true;
261
		/* rewrite all properties with low case, better for later gzip OK, safe*/
262
		$this->settings['case_properties'] = 1;
263
		/* sort properties in alpabetic order, better for later gzip
264
		 * but can cause trouble in case of overiding same propertie or using hack
265
		 */
266
		$this->settings['sort_properties'] = false;
267
		/*
268
		  1, 3, 5, etc -- enable sorting selectors inside @media: a{}b{}c{}
269
		  2, 5, 8, etc -- enable sorting selectors inside one CSS declaration: a,b,c{}
270
		  preserve order by default cause it can break functionnality
271
		 */
272
		$this->settings['sort_selectors'] = 0;
273
		/* is dangeroues to be used: CSS is broken sometimes */
274
		$this->settings['merge_selectors'] = 0;
275
		/* preserve or not browser hacks */
276
		$this->settings['discard_invalid_selectors'] = false;
277
		$this->settings['discard_invalid_properties'] = false;
278
		$this->settings['css_level'] = 'CSS2.1';
279
		$this->settings['preserve_css'] = false;
280
		$this->settings['timestamp'] = false;
281
		$this->settings['template'] = ''; // say that propertie exist
282
		$this->set_cfg('template','default'); // call load_template
283
		/* Tells csstidy_optimise to keep leading zeros on decimal numbers, e.g., 0.7 */
284
		$this->settings['preserve_leading_zeros'] = false;
285
		$this->optimise = new csstidy_optimise($this);
0 ignored issues
show
Documentation introduced by
$this is of type this<csstidy>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
286
287
		$this->tokens_list = & $GLOBALS['csstidy']['tokens'];
288
	}
289
290
	function csstidy() {
291
		$this->__construct();
292
	}
293
294
	/**
295
	 * Get the value of a setting.
296
	 * @param string $setting
297
	 * @access public
298
	 * @return mixed
299
	 * @version 1.0
300
	 */
301
	function get_cfg($setting) {
302
		if (isset($this->settings[$setting])) {
303
			return $this->settings[$setting];
304
		}
305
		return false;
306
	}
307
308
	/**
309
	 * Load a template
310
	 * @param string $template used by set_cfg to load a template via a configuration setting
311
	 * @access private
312
	 * @version 1.4
313
	 */
314
	function _load_template($template) {
315
		switch ($template) {
316
			case 'default':
317
				$this->load_template('default');
318
				break;
319
320
			case 'highest':
321
				$this->load_template('highest_compression');
322
				break;
323
324
			case 'high':
325
				$this->load_template('high_compression');
326
				break;
327
328
			case 'low':
329
				$this->load_template('low_compression');
330
				break;
331
332
			default:
333
				$this->load_template($template);
334
				break;
335
		}
336
	}
337
338
	/**
339
	 * Set the value of a setting.
340
	 * @param string $setting
341
	 * @param mixed $value
342
	 * @access public
343
	 * @return bool
344
	 * @version 1.0
345
	 */
346
	function set_cfg($setting, $value=null) {
347
		if (is_array($setting) && $value === null) {
348
			foreach ($setting as $setprop => $setval) {
349
				$this->settings[$setprop] = $setval;
350
			}
351
			if (array_key_exists('template', $setting)) {
352
				$this->_load_template($this->settings['template']);
353
			}
354
			return true;
355
		} else if (isset($this->settings[$setting]) && $value !== '') {
356
			$this->settings[$setting] = $value;
357
			if ($setting === 'template') {
358
				$this->_load_template($this->settings['template']);
359
			}
360
			return true;
361
		}
362
		return false;
363
	}
364
365
	/**
366
	 * Adds a token to $this->tokens
367
	 * @param mixed $type
368
	 * @param string $data
369
	 * @param bool $do add a token even if preserve_css is off
370
	 * @access private
371
	 * @version 1.0
372
	 */
373
	function _add_token($type, $data, $do = false) {
374
		if ($this->get_cfg('preserve_css') || $do) {
375
			$this->tokens[] = array($type, ($type == COMMENT) ? $data : trim($data));
376
		}
377
	}
378
379
	/**
380
	 * Add a message to the message log
381
	 * @param string $message
382
	 * @param string $type
383
	 * @param integer $line
384
	 * @access private
385
	 * @version 1.0
386
	 */
387
	function log($message, $type, $line = -1) {
388
		if ($line === -1) {
389
			$line = $this->line;
390
		}
391
		$line = (int) $line;
392
		$add = array('m' => $message, 't' => $type);
393
		if (!isset($this->log[$line]) || !in_array($add, $this->log[$line])) {
394
			$this->log[$line][] = $add;
395
		}
396
	}
397
398
	/**
399
	 * Parse unicode notations and find a replacement character
400
	 * @param string $string
401
	 * @param integer $i
402
	 * @access private
403
	 * @return string
404
	 * @version 1.2
405
	 */
406
	function _unicode(&$string, &$i) {
407
		++$i;
408
		$add = '';
409
		$replaced = false;
410
411
		while ($i < strlen($string) && (ctype_xdigit($string[$i]) || ctype_space($string[$i])) && strlen($add) < 6) {
412
			$add .= $string[$i];
413
414
			if (ctype_space($string[$i])) {
415
				break;
416
			}
417
			$i++;
418
		}
419
420
		if (hexdec($add) > 47 && hexdec($add) < 58 || hexdec($add) > 64 && hexdec($add) < 91 || hexdec($add) > 96 && hexdec($add) < 123) {
421
			$this->log('Replaced unicode notation: Changed \\' . $add . ' to ' . chr(hexdec($add)), 'Information');
422
			$add = chr(hexdec($add));
423
			$replaced = true;
424
		} else {
425
			$add = trim('\\' . $add);
426
		}
427
428
		if (@ctype_xdigit($string[$i + 1]) && ctype_space($string[$i])
429
						&& !$replaced || !ctype_space($string[$i])) {
430
			$i--;
431
		}
432
433
		if ($add !== '\\' || !$this->get_cfg('remove_bslash') || strpos($this->tokens_list, $string[$i + 1]) !== false) {
434
			return $add;
435
		}
436
437
		if ($add === '\\') {
438
			$this->log('Removed unnecessary backslash', 'Information');
439
		}
440
		return '';
441
	}
442
443
	/**
444
	 * Write formatted output to a file
445
	 * @param string $filename
446
	 * @param string $doctype when printing formatted, is a shorthand for the document type
447
	 * @param bool $externalcss when printing formatted, indicates whether styles to be attached internally or as an external stylesheet
448
	 * @param string $title when printing formatted, is the title to be added in the head of the document
449
	 * @param string $lang when printing formatted, gives a two-letter language code to be added to the output
450
	 * @access public
451
	 * @version 1.4
452
	 */
453
	function write_page($filename, $doctype='xhtml1.1', $externalcss=true, $title='', $lang='en') {
454
		$this->write($filename, true);
455
	}
456
457
	/**
458
	 * Write plain output to a file
459
	 * @param string $filename
460
	 * @param bool $formatted whether to print formatted or not
461
	 * @param string $doctype when printing formatted, is a shorthand for the document type
462
	 * @param bool $externalcss when printing formatted, indicates whether styles to be attached internally or as an external stylesheet
463
	 * @param string $title when printing formatted, is the title to be added in the head of the document
464
	 * @param string $lang when printing formatted, gives a two-letter language code to be added to the output
465
	 * @param bool $pre_code whether to add pre and code tags around the code (for light HTML formatted templates)
466
	 * @access public
467
	 * @version 1.4
468
	 */
469
	function write($filename, $formatted=false, $doctype='xhtml1.1', $externalcss=true, $title='', $lang='en', $pre_code=true) {
470
		$filename .= ( $formatted) ? '.xhtml' : '.css';
471
472
		if (!is_dir('temp')) {
473
			$madedir = mkdir('temp');
474
			if (!$madedir) {
475
				print 'Could not make directory "temp" in ' . dirname(__FILE__);
476
				exit;
477
			}
478
		}
479
		$handle = fopen('temp/' . $filename, 'w');
480
		if ($handle) {
481
			if (!$formatted) {
482
				fwrite($handle, $this->print->plain());
483
			} else {
484
				fwrite($handle, $this->print->formatted_page($doctype, $externalcss, $title, $lang, $pre_code));
485
			}
486
		}
487
		fclose($handle);
488
	}
489
490
	/**
491
	 * Loads a new template
492
	 * @param string $content either filename (if $from_file == true), content of a template file, "high_compression", "highest_compression", "low_compression", or "default"
493
	 * @param bool $from_file uses $content as filename if true
494
	 * @access public
495
	 * @version 1.1
496
	 * @see http://csstidy.sourceforge.net/templates.php
497
	 */
498
	function load_template($content, $from_file=true) {
499
		$predefined_templates = & $GLOBALS['csstidy']['predefined_templates'];
500
		if ($content === 'high_compression' || $content === 'default' || $content === 'highest_compression' || $content === 'low_compression') {
501
			$this->template = $predefined_templates[$content];
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...
502
			return;
503
		}
504
505
506
		if ($from_file) {
507
			$content = strip_tags(file_get_contents($content), '<span>');
508
		}
509
		$content = str_replace("\r\n", "\n", $content); // Unify newlines (because the output also only uses \n)
510
		$template = explode('|', $content);
511
512
		for ($i = 0; $i < count($template); $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...
513
			$this->template[$i] = $template[$i];
514
		}
515
	}
516
517
	/**
518
	 * Starts parsing from URL
519
	 * @param string $url
520
	 * @access public
521
	 * @version 1.0
522
	 */
523
	function parse_from_url($url) {
524
		return $this->parse(@file_get_contents($url));
525
	}
526
527
	/**
528
	 * Checks if there is a token at the current position
529
	 * @param string $string
530
	 * @param integer $i
531
	 * @access public
532
	 * @version 1.11
533
	 */
534
	function is_token(&$string, $i) {
535
		return (strpos($this->tokens_list, $string[$i]) !== false && !csstidy::escaped($string, $i));
536
	}
537
538
	/**
539
	 * Parses CSS in $string. The code is saved as array in $this->css
540
	 * @param string $string the CSS code
541
	 * @access public
542
	 * @return bool
543
	 * @version 1.1
544
	 */
545
	function parse($string) {
546
		// Temporarily set locale to en_US in order to handle floats properly
547
		$old = @setlocale(LC_ALL, 0);
548
		@setlocale(LC_ALL, 'C');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
549
550
		// PHP bug? Settings need to be refreshed in PHP4
551
		$this->print = new csstidy_print($this);
0 ignored issues
show
Documentation introduced by
$this is of type this<csstidy>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
552
		//$this->optimise = new csstidy_optimise($this);
553
554
		$all_properties = & $GLOBALS['csstidy']['all_properties'];
555
		$at_rules = & $GLOBALS['csstidy']['at_rules'];
556
		$quoted_string_properties = & $GLOBALS['csstidy']['quoted_string_properties'];
557
558
		$this->css = array();
559
		$this->print->input_css = $string;
560
		$string = str_replace("\r\n", "\n", $string) . ' ';
561
		$cur_comment = '';
562
563
		for ($i = 0, $size = strlen($string); $i < $size; $i++) {
564
			if ($string[$i] === "\n" || $string[$i] === "\r") {
565
				++$this->line;
566
			}
567
568
			switch ($this->status) {
569
				/* Case in at-block */
570
				case 'at':
571
					if (csstidy::is_token($string, $i)) {
572
						if ($string[$i] === '/' && @$string[$i + 1] === '*') {
573
							$this->status = 'ic';
574
							++$i;
575
							$this->from[] = 'at';
576
						} elseif ($string[$i] === '{') {
577
							$this->status = 'is';
578
							$this->at = $this->css_new_media_section($this->at);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->css_new_media_section($this->at) can also be of type integer or double. However, the property $at is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
579
							$this->_add_token(AT_START, $this->at);
580
						} elseif ($string[$i] === ',') {
581
							$this->at = trim($this->at) . ',';
582
						} elseif ($string[$i] === '\\') {
583
							$this->at .= $this->_unicode($string, $i);
584
						}
585
						// fix for complicated media, i.e @media screen and (-webkit-min-device-pixel-ratio:1.5)
586
						// '/' is included for ratios in Opera: (-o-min-device-pixel-ratio: 3/2)
587 View Code Duplication
						elseif (in_array($string[$i], array('(', ')', ':', '.', '/'))) {
588
							$this->at .= $string[$i];
589
						}
590
					} else {
591
						$lastpos = strlen($this->at) - 1;
592
						if (!( (ctype_space($this->at[$lastpos]) || csstidy::is_token($this->at, $lastpos) && $this->at[$lastpos] === ',') && ctype_space($string[$i]))) {
593
							$this->at .= $string[$i];
594
						}
595
					}
596
					break;
597
598
				/* Case in-selector */
599
				case 'is':
600
					if (csstidy::is_token($string, $i)) {
601
						if ($string[$i] === '/' && @$string[$i + 1] === '*' && trim($this->selector) == '') {
602
							$this->status = 'ic';
603
							++$i;
604
							$this->from[] = 'is';
605
						} elseif ($string[$i] === '@' && trim($this->selector) == '') {
606
							// Check for at-rule
607
							$this->invalid_at = true;
608
							foreach ($at_rules as $name => $type) {
609
								if (!strcasecmp(substr($string, $i + 1, strlen($name)), $name)) {
610
									($type === 'at') ? $this->at = '@' . $name : $this->selector = '@' . $name;
611
									$this->status = $type;
612
									$i += strlen($name);
613
									$this->invalid_at = false;
614
								}
615
							}
616
617
							if ($this->invalid_at) {
618
								$this->selector = '@';
619
								$invalid_at_name = '';
620
								for ($j = $i + 1; $j < $size; ++$j) {
621
									if (!ctype_alpha($string[$j])) {
622
										break;
623
									}
624
									$invalid_at_name .= $string[$j];
625
								}
626
								$this->log('Invalid @-rule: ' . $invalid_at_name . ' (removed)', 'Warning');
627
							}
628
						} elseif (($string[$i] === '"' || $string[$i] === "'")) {
629
							$this->cur_string[] = $string[$i];
630
							$this->status = 'instr';
631
							$this->str_char[] = $string[$i];
632
							$this->from[] = 'is';
633
							/* fixing CSS3 attribute selectors, i.e. a[href$=".mp3" */
634
							$this->quoted_string[] = ($string[$i - 1] == '=' );
635
						} elseif ($this->invalid_at && $string[$i] === ';') {
636
							$this->invalid_at = false;
637
							$this->status = 'is';
638
						} elseif ($string[$i] === '{') {
639
							$this->status = 'ip';
640
							if($this->at == '') {
641
								$this->at = $this->css_new_media_section(DEFAULT_AT);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->css_new_media_section(DEFAULT_AT) can also be of type integer or double. However, the property $at is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
642
							}
643
							$this->selector = $this->css_new_selector($this->at,$this->selector);
644
							$this->_add_token(SEL_START, $this->selector);
645
							$this->added = false;
646
						} elseif ($string[$i] === '}') {
647
							$this->_add_token(AT_END, $this->at);
648
							$this->at = '';
649
							$this->selector = '';
650
							$this->sel_separate = array();
651
						} elseif ($string[$i] === ',') {
652
							$this->selector = trim($this->selector) . ',';
653
							$this->sel_separate[] = strlen($this->selector);
654
						} elseif ($string[$i] === '\\') {
655
							$this->selector .= $this->_unicode($string, $i);
656 View Code Duplication
						} elseif ($string[$i] === '*' && @in_array($string[$i + 1], array('.', '#', '[', ':'))) {
657
							// remove unnecessary universal selector, FS#147
658
						} else {
659
							$this->selector .= $string[$i];
660
						}
661
					} else {
662
						$lastpos = strlen($this->selector) - 1;
663
						if ($lastpos == -1 || !( (ctype_space($this->selector[$lastpos]) || csstidy::is_token($this->selector, $lastpos) && $this->selector[$lastpos] === ',') && ctype_space($string[$i]))) {
664
							$this->selector .= $string[$i];
665
						}
666
						else if (ctype_space($string[$i]) && $this->get_cfg('preserve_css') && !$this->get_cfg('merge_selectors')) {
667
							$this->selector .= $string[$i];
668
						}
669
					}
670
					break;
671
672
				/* Case in-property */
673
				case 'ip':
674
					if (csstidy::is_token($string, $i)) {
675
						if (($string[$i] === ':' || $string[$i] === '=') && $this->property != '') {
676
							$this->status = 'iv';
677
							if (!$this->get_cfg('discard_invalid_properties') || csstidy::property_is_valid($this->property)) {
678
								$this->property = $this->css_new_property($this->at,$this->selector,$this->property);
679
								$this->_add_token(PROPERTY, $this->property);
680
							}
681
						} elseif ($string[$i] === '/' && @$string[$i + 1] === '*' && $this->property == '') {
682
							$this->status = 'ic';
683
							++$i;
684
							$this->from[] = 'ip';
685 View Code Duplication
						} elseif ($string[$i] === '}') {
686
							$this->explode_selectors();
687
							$this->status = 'is';
688
							$this->invalid_at = false;
689
							$this->_add_token(SEL_END, $this->selector);
690
							$this->selector = '';
691
							$this->property = '';
692
						} elseif ($string[$i] === ';') {
693
							$this->property = '';
694
						} elseif ($string[$i] === '\\') {
695
							$this->property .= $this->_unicode($string, $i);
696
						}
697
						// else this is dumb IE a hack, keep it
698
						elseif ($this->property=='' AND !ctype_space($string[$i])) {
699
							$this->property .= $string[$i];
700
						}
701
					}
702
					elseif (!ctype_space($string[$i])) {
703
						$this->property .= $string[$i];
704
					}
705
					break;
706
707
				/* Case in-value */
708
				case 'iv':
709
					$pn = (($string[$i] === "\n" || $string[$i] === "\r") && $this->property_is_next($string, $i + 1) || $i == strlen($string) - 1);
710
					if ((csstidy::is_token($string, $i) || $pn) && (!($string[$i] == ',' && !ctype_space($string[$i+1])))) {
711
						if ($string[$i] === '/' && @$string[$i + 1] === '*') {
712
							$this->status = 'ic';
713
							++$i;
714
							$this->from[] = 'iv';
715
						} elseif (($string[$i] === '"' || $string[$i] === "'" || $string[$i] === '(')) {
716
							$this->cur_string[] = $string[$i];
717
							$this->str_char[] = ($string[$i] === '(') ? ')' : $string[$i];
718
							$this->status = 'instr';
719
							$this->from[] = 'iv';
720
							$this->quoted_string[] = in_array(strtolower($this->property), $quoted_string_properties);
721
						} elseif ($string[$i] === ',') {
722
							$this->sub_value = trim($this->sub_value) . ',';
723
						} elseif ($string[$i] === '\\') {
724
							$this->sub_value .= $this->_unicode($string, $i);
725
						} elseif ($string[$i] === ';' || $pn) {
726
							if ($this->selector[0] === '@' && isset($at_rules[substr($this->selector, 1)]) && $at_rules[substr($this->selector, 1)] === 'iv') {
727
								$this->status = 'is';
728
729
								switch ($this->selector) {
730
									case '@charset':
731
										/* Add quotes to charset */
732
										$this->sub_value_arr[] = '"' . trim($this->sub_value) . '"';
733
										$this->charset = $this->sub_value_arr[0];
734
										break;
735
									case '@namespace':
736
										/* Add quotes to namespace */
737
										$this->sub_value_arr[] = '"' . trim($this->sub_value) . '"';
738
										$this->namespace = implode(' ', $this->sub_value_arr);
739
										break;
740
									case '@import':
741
										$this->sub_value = trim($this->sub_value);
742
743
										if (empty($this->sub_value_arr)) {
744
											// Quote URLs in imports only if they're not already inside url() and not already quoted.
745
											if (substr($this->sub_value, 0, 4) != 'url(') {
746
												if (!($this->sub_value[0] == substr($this->sub_value, -1) && in_array($this->sub_value[0], array("'", '"')))) {
747
													$this->sub_value = '"' . $this->sub_value . '"';
748
												}
749
											}
750
										}
751
752
										$this->sub_value_arr[] = $this->sub_value;
753
										$this->import[] = implode(' ', $this->sub_value_arr);
754
										break;
755
								}
756
757
								$this->sub_value_arr = array();
758
								$this->sub_value = '';
759
								$this->selector = '';
760
								$this->sel_separate = array();
761
							} else {
762
								$this->status = 'ip';
763
							}
764
						} elseif ($string[$i] !== '}') {
765
							$this->sub_value .= $string[$i];
766
						}
767
						if (($string[$i] === '}' || $string[$i] === ';' || $pn) && !empty($this->selector)) {
768
							if ($this->at == '') {
769
								$this->at = $this->css_new_media_section(DEFAULT_AT);
770
							}
771
772
							// case settings
773
							if ($this->get_cfg('lowercase_s')) {
774
								$this->selector = strtolower($this->selector);
775
							}
776
							$this->property = strtolower($this->property);
777
778
							$this->optimise->subvalue();
779
							if ($this->sub_value != '') {
780
								if (substr($this->sub_value, 0, 6) == 'format') {
781
									$format_strings = csstidy::parse_string_list(substr($this->sub_value, 7, -1));
782
									if (!$format_strings) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $format_strings of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
783
										$this->sub_value = "";
784
									}
785
									else {
786
										$this->sub_value = "format(";
787
788
										foreach ($format_strings as $format_string) {
789
											$this->sub_value .= '"' . str_replace('"', '\\"', $format_string) . '",';
790
										}
791
792
										$this->sub_value = substr($this->sub_value, 0, -1) . ")";
793
									}
794
								}
795
								if ($this->sub_value != '') {
796
									$this->sub_value_arr[] = $this->sub_value;
797
								}
798
								$this->sub_value = '';
799
							}
800
801
							$this->value = array_shift($this->sub_value_arr);
802
							while(count($this->sub_value_arr)){
803
								//$this->value .= (substr($this->value,-1,1)==','?'':' ').array_shift($this->sub_value_arr);
804
								$this->value .= ' '.array_shift($this->sub_value_arr);
805
							}
806
807
							$this->optimise->value();
808
809
							$valid = csstidy::property_is_valid($this->property);
810
							if ((!$this->invalid_at || $this->get_cfg('preserve_css')) && (!$this->get_cfg('discard_invalid_properties') || $valid)) {
811
								$this->css_add_property($this->at, $this->selector, $this->property, $this->value);
812
								$this->_add_token(VALUE, $this->value);
813
								$this->optimise->shorthands();
814
							}
815
							if (!$valid) {
816
								if ($this->get_cfg('discard_invalid_properties')) {
817
									$this->log('Removed invalid property: ' . $this->property, 'Warning');
818
								} else {
819
									$this->log('Invalid property in ' . strtoupper($this->get_cfg('css_level')) . ': ' . $this->property, 'Warning');
820
								}
821
							}
822
823
							$this->property = '';
824
							$this->sub_value_arr = array();
825
							$this->value = '';
826
						}
827 View Code Duplication
						if ($string[$i] === '}') {
828
							$this->explode_selectors();
829
							$this->_add_token(SEL_END, $this->selector);
830
							$this->status = 'is';
831
							$this->invalid_at = false;
832
							$this->selector = '';
833
						}
834
					} elseif (!$pn) {
835
						$this->sub_value .= $string[$i];
836
837
						if (ctype_space($string[$i]) || $string[$i] == ',') {
838
							$this->optimise->subvalue();
839
							if ($this->sub_value != '') {
840
								$this->sub_value_arr[] = $this->sub_value;
841
								$this->sub_value = '';
842
							}
843
						}
844
					}
845
					break;
846
847
				/* Case in string */
848
				case 'instr':
849
					$_str_char = $this->str_char[count($this->str_char)-1];
850
					$_cur_string = $this->cur_string[count($this->cur_string)-1];
851
					$temp_add = $string[$i];
852
853
					// Add another string to the stack. Strings can't be nested inside of quotes, only parentheses, but
854
					// parentheticals can be nested more than once.
855
					if ($_str_char === ")" && ($string[$i] === "(" || $string[$i] === '"' || $string[$i] === '\'') && !csstidy::escaped($string, $i)) {
856
						$this->cur_string[] = $string[$i];
857
						$this->str_char[] = $string[$i] == "(" ? ")" : $string[$i];
858
						$this->from[] = 'instr';
859
						$this->quoted_string[] = !($string[$i] === "(");
860
						continue 2;
861
					}
862
863
					if ($_str_char !== ")" && ($string[$i] === "\n" || $string[$i] === "\r") && !($string[$i - 1] === '\\' && !csstidy::escaped($string, $i - 1))) {
864
						$temp_add = "\\A";
865
						$this->log('Fixed incorrect newline in string', 'Warning');
866
					}
867
868
					$_cur_string .= $temp_add;
869
870
					if ($string[$i] === $_str_char && !csstidy::escaped($string, $i)) {
871
						$_quoted_string = array_pop($this->quoted_string);
872
873
						$this->status = array_pop($this->from);
874
875
						if (!preg_match('|[' . implode('', $GLOBALS['csstidy']['whitespace']) . ']|uis', $_cur_string) && $this->property !== 'content') {
876
							if (!$_quoted_string) {
877
								if ($_str_char !== ')') {
878
									// Convert properties like
879
									// font-family: 'Arial';
880
									// to
881
									// font-family: Arial;
882
									// or
883
									// url("abc")
884
									// to
885
									// url(abc)
886
									$_cur_string = substr($_cur_string, 1, -1);
887
								}
888
							} else {
889
								$_quoted_string = false;
890
							}
891
						}
892
893
						array_pop($this->cur_string);
894
						array_pop($this->str_char);
895
896
						if ($_str_char === ")") {
897
							$_cur_string = "(" . trim(substr($_cur_string, 1, -1)) . ")";
898
						}
899
900
						if ($this->status === 'iv') {
901
							if (!$_quoted_string){
902
								if (strpos($_cur_string,',')!==false)
903
									// we can on only remove space next to ','
904
									$_cur_string = implode(',',array_map('trim',explode(',',$_cur_string)));
905
								// and multiple spaces (too expensive)
906
								if (strpos($_cur_string,'  ')!==false)
907
									$_cur_string = preg_replace(",\s+,"," ",$_cur_string);
908
							}
909
							$this->sub_value .= $_cur_string;
910
						} elseif ($this->status === 'is') {
911
							$this->selector .= $_cur_string;
912
						} elseif ($this->status === 'instr') {
913
							$this->cur_string[count($this->cur_string)-1] .= $_cur_string;
914
						}
915
					}
916
					else {
917
						$this->cur_string[count($this->cur_string)-1] = $_cur_string;
918
					}
919
					break;
920
921
				/* Case in-comment */
922
				case 'ic':
923
					if ($string[$i] === '*' && $string[$i + 1] === '/') {
924
						$this->status = array_pop($this->from);
925
						$i++;
926
						$this->_add_token(COMMENT, $cur_comment);
927
						$cur_comment = '';
928
					} else {
929
						$cur_comment .= $string[$i];
930
					}
931
					break;
932
			}
933
		}
934
935
		$this->optimise->postparse();
936
937
		$this->print->_reset();
938
939
		@setlocale(LC_ALL, $old); // Set locale back to original setting
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
940
941
		return!(empty($this->css) && empty($this->import) && empty($this->charset) && empty($this->tokens) && empty($this->namespace));
942
	}
943
944
	/**
945
	 * Explodes selectors
946
	 * @access private
947
	 * @version 1.0
948
	 */
949
	function explode_selectors() {
950
		// Explode multiple selectors
951
		if ($this->get_cfg('merge_selectors') === 1) {
952
			$new_sels = array();
953
			$lastpos = 0;
954
			$this->sel_separate[] = strlen($this->selector);
955
			foreach ($this->sel_separate as $num => $pos) {
956
				if ($num == count($this->sel_separate) - 1) {
957
					$pos += 1;
958
				}
959
960
				$new_sels[] = substr($this->selector, $lastpos, $pos - $lastpos - 1);
961
				$lastpos = $pos;
962
			}
963
964
			if (count($new_sels) > 1) {
965
				foreach ($new_sels as $selector) {
966
					if (isset($this->css[$this->at][$this->selector])) {
967
						$this->merge_css_blocks($this->at, $selector, $this->css[$this->at][$this->selector]);
968
					}
969
				}
970
				unset($this->css[$this->at][$this->selector]);
971
			}
972
		}
973
		$this->sel_separate = array();
974
	}
975
976
	/**
977
	 * Checks if a character is escaped (and returns true if it is)
978
	 * @param string $string
979
	 * @param integer $pos
980
	 * @access public
981
	 * @return bool
982
	 * @version 1.02
983
	 */
984
	static function escaped(&$string, $pos) {
985
		return!(@($string[$pos - 1] !== '\\') || csstidy::escaped($string, $pos - 1));
986
	}
987
988
	/**
989
	 * Adds a property with value to the existing CSS code
990
	 * @param string $media
991
	 * @param string $selector
992
	 * @param string $property
993
	 * @param string $new_val
994
	 * @access private
995
	 * @version 1.2
996
	 */
997
	function css_add_property($media, $selector, $property, $new_val) {
998
		if ($this->get_cfg('preserve_css') || trim($new_val) == '') {
999
			return;
1000
		}
1001
1002
		$this->added = true;
1003
		if (isset($this->css[$media][$selector][$property])) {
1004
			if ((csstidy::is_important($this->css[$media][$selector][$property]) && csstidy::is_important($new_val)) || !csstidy::is_important($this->css[$media][$selector][$property])) {
1005
				$this->css[$media][$selector][$property] = trim($new_val);
1006
			}
1007
		} else {
1008
			$this->css[$media][$selector][$property] = trim($new_val);
1009
		}
1010
	}
1011
1012
	/**
1013
	 * Start a new media section.
1014
	 * Check if the media is not already known,
1015
	 * else rename it with extra spaces
1016
	 * to avoid merging
1017
	 *
1018
	 * @param string $media
1019
	 * @return string
1020
	 */
1021
	function css_new_media_section($media){
1022
		if($this->get_cfg('preserve_css')) {
1023
			return $media;
1024
		}
1025
1026
		// if the last @media is the same as this
1027
		// keep it
1028
		if (!$this->css OR !is_array($this->css) OR empty($this->css)){
1029
			return $media;
1030
		}
1031
		end($this->css);
1032
		$at = current( $this->css );
1033
		if ($at == $media){
1034
			return $media;
1035
		}
1036
		while (isset($this->css[$media]))
1037
			if (is_numeric($media))
1038
				$media++;
1039
			else
1040
				$media .= " ";
1041
		return $media;
1042
	}
1043
1044
	/**
1045
	 * Start a new selector.
1046
	 * If already referenced in this media section,
1047
	 * rename it with extra space to avoid merging
1048
	 * except if merging is required,
1049
	 * or last selector is the same (merge siblings)
1050
	 *
1051
	 * never merge @font-face
1052
	 *
1053
	 * @param string $media
1054
	 * @param string $selector
1055
	 * @return string
1056
	 */
1057
	function css_new_selector($media,$selector){
1058
		if($this->get_cfg('preserve_css')) {
1059
			return $selector;
1060
		}
1061
		$selector = trim($selector);
1062
		if (strncmp($selector,"@font-face",10)!=0){
1063
			if ($this->settings['merge_selectors'] != false)
1064
				return $selector;
1065
1066 View Code Duplication
			if (!$this->css OR !isset($this->css[$media]) OR !$this->css[$media])
1067
				return $selector;
1068
1069
			// if last is the same, keep it
1070
			end($this->css[$media]);
1071
			$sel = current( $this->css[$media] );
1072
			if ($sel == $selector){
1073
				return $selector;
1074
			}
1075
		}
1076
1077
		while (isset($this->css[$media][$selector]))
1078
			$selector .= " ";
1079
		return $selector;
1080
	}
1081
1082
	/**
1083
	 * Start a new propertie.
1084
	 * If already references in this selector,
1085
	 * rename it with extra space to avoid override
1086
	 *
1087
	 * @param string $media
1088
	 * @param string $selector
1089
	 * @param string $property
1090
	 * @return string
1091
	 */
1092
	function css_new_property($media, $selector, $property){
1093
		if($this->get_cfg('preserve_css')) {
1094
			return $property;
1095
		}
1096 View Code Duplication
		if (!$this->css OR !isset($this->css[$media][$selector]) OR !$this->css[$media][$selector])
1097
			return $property;
1098
1099
		while (isset($this->css[$media][$selector][$property]))
1100
			$property .= " ";
1101
1102
		return $property;
1103
	}
1104
1105
	/**
1106
	 * Adds CSS to an existing media/selector
1107
	 * @param string $media
1108
	 * @param string $selector
1109
	 * @param array $css_add
1110
	 * @access private
1111
	 * @version 1.1
1112
	 */
1113
	function merge_css_blocks($media, $selector, $css_add) {
1114
		foreach ($css_add as $property => $value) {
1115
			$this->css_add_property($media, $selector, $property, $value, false);
0 ignored issues
show
Unused Code introduced by
The call to csstidy::css_add_property() has too many arguments starting with false.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
1116
		}
1117
	}
1118
1119
	/**
1120
	 * Checks if $value is !important.
1121
	 * @param string $value
1122
	 * @return bool
1123
	 * @access public
1124
	 * @version 1.0
1125
	 */
1126
	static function is_important(&$value) {
1127
		return (!strcasecmp(substr(str_replace($GLOBALS['csstidy']['whitespace'], '', $value), -10, 10), '!important'));
1128
	}
1129
1130
	/**
1131
	 * Returns a value without !important
1132
	 * @param string $value
1133
	 * @return string
1134
	 * @access public
1135
	 * @version 1.0
1136
	 */
1137
	static function gvw_important($value) {
1138
		if (csstidy::is_important($value)) {
1139
			$value = trim($value);
1140
			$value = substr($value, 0, -9);
1141
			$value = trim($value);
1142
			$value = substr($value, 0, -1);
1143
			$value = trim($value);
1144
			return $value;
1145
		}
1146
		return $value;
1147
	}
1148
1149
	/**
1150
	 * Checks if the next word in a string from pos is a CSS property
1151
	 * @param string $istring
1152
	 * @param integer $pos
1153
	 * @return bool
1154
	 * @access private
1155
	 * @version 1.2
1156
	 */
1157
	function property_is_next($istring, $pos) {
1158
		$all_properties = & $GLOBALS['csstidy']['all_properties'];
1159
		$istring = substr($istring, $pos, strlen($istring) - $pos);
1160
		$pos = strpos($istring, ':');
1161
		if ($pos === false) {
1162
			return false;
1163
		}
1164
		$istring = strtolower(trim(substr($istring, 0, $pos)));
1165
		if (isset($all_properties[$istring])) {
1166
			$this->log('Added semicolon to the end of declaration', 'Warning');
1167
			return true;
1168
		}
1169
		return false;
1170
	}
1171
1172
	/**
1173
	 * Checks if a property is valid
1174
	 * @param string $property
1175
	 * @return bool;
0 ignored issues
show
Documentation introduced by
The doc-type bool; could not be parsed: Expected "|" or "end of type", but got ";" at position 4. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
1176
	 * @access public
1177
	 * @version 1.0
1178
	 */
1179
	function property_is_valid($property) {
1180
		$property = strtolower($property);
1181
		if (in_array(trim($property), $GLOBALS['csstidy']['multiple_properties'])) $property = trim($property);
1182
		$all_properties = & $GLOBALS['csstidy']['all_properties'];
1183
		return (isset($all_properties[$property]) && strpos($all_properties[$property], strtoupper($this->get_cfg('css_level'))) !== false );
1184
	}
1185
1186
	/**
1187
	 * Accepts a list of strings (e.g., the argument to format() in a @font-face src property)
1188
	 * and returns a list of the strings.  Converts things like:
1189
	 *
1190
	 * format(abc) => format("abc")
1191
	 * format(abc def) => format("abc","def")
1192
	 * format(abc "def") => format("abc","def")
1193
	 * format(abc, def, ghi) => format("abc","def","ghi")
1194
	 * format("abc",'def') => format("abc","def")
1195
	 * format("abc, def, ghi") => format("abc, def, ghi")
1196
	 *
1197
	 * @param string
1198
	 * @return array
1199
	 */
1200
1201
	function parse_string_list($value) {
1202
		$value = trim($value);
1203
1204
		// Case: empty
1205
		if (!$value) return array();
1206
1207
		$strings = array();
1208
1209
		$in_str = false;
1210
		$current_string = "";
1211
1212
		for ($i = 0, $_len = strlen($value); $i < $_len; $i++) {
1213
			if (($value[$i] == "," || $value[$i] === " ") && $in_str === true) {
1214
				$in_str = false;
1215
				$strings[] = $current_string;
1216
				$current_string = "";
1217
			}
1218
			else if ($value[$i] == '"' || $value[$i] == "'"){
1219
				if ($in_str === $value[$i]) {
1220
					$strings[] = $current_string;
1221
					$in_str = false;
1222
					$current_string = "";
1223
					continue;
1224
				}
1225
				else if (!$in_str) {
1226
					$in_str = $value[$i];
1227
				}
1228
			}
1229
			else {
1230
				if ($in_str){
1231
					$current_string .= $value[$i];
1232
				}
1233
				else {
1234
					if (!preg_match("/[\s,]/", $value[$i])) {
1235
						$in_str = true;
1236
						$current_string = $value[$i];
1237
					}
1238
				}
1239
			}
1240
		}
1241
1242
		if ($current_string) {
1243
			$strings[] = $current_string;
1244
		}
1245
1246
		return $strings;
1247
	}
1248
}
1249