~ubuntu-branches/ubuntu/vivid/php-codesniffer/vivid

« back to all changes in this revision

Viewing changes to PHP_CodeSniffer-1.5.4/CodeSniffer/Tokenizers/CSS.php

  • Committer: Package Import Robot
  • Author(s): David Prévot, Greg Sherwood, Alexey, Emily, David Prévot
  • Date: 2014-09-26 13:44:35 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20140926134435-wvjq16miqq4d60y0
Tags: 1.5.5-1
[ Greg Sherwood ]
* Improved closure support in Generic ScopeIndentSniff
* Improved indented PHP tag support in Generic ScopeIndentSniff
* Standards can now be located within hidden directories
 (further fix for bug #20323)
* Fixed bug #20373 : Inline comment sniff tab handling way
* Fixed bug #20378 : Report appended to existing file if no errors
  found in run
* Fixed bug #20381 : Invalid "Comment closer must be on a new line"
* PHP tokenizer no longer converts class/function names to special
  tokens types
* Fixed bug #20386 : Squiz.Commenting.ClassComment.SpacingBefore
  thrown if first block comment
* Squiz and PEAR FunctionCommentSnif now support _()
* PEAR ValidFunctionNameSniff no longer throws an error for _()
* Fixed bug #248 : FunctionCommentSniff expects ampersand on param name
* Fixed bug #248 in Squiz sniff as well
* Fixed bug #265 : False positives with type hints in ForbiddenFunctionsSniff
* Prepare for 1.5.5 release

[ Alexey ]
* Allowed single undersored methods and functions

[ Emily ]
* Added var_dump to discouraged functions sniff

[ David Prévot ]
* Revert "Add XS-Testsuite still needed for ci.d.n"
* Add self to uploaders
* Bump standards version to 3.9.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
<?php
2
 
/**
3
 
 * Tokenizes CSS code.
4
 
 *
5
 
 * PHP version 5
6
 
 *
7
 
 * @category  PHP
8
 
 * @package   PHP_CodeSniffer
9
 
 * @author    Greg Sherwood <gsherwood@squiz.net>
10
 
 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
11
 
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
12
 
 * @link      http://pear.php.net/package/PHP_CodeSniffer
13
 
 */
14
 
 
15
 
if (class_exists('PHP_CodeSniffer_Tokenizers_PHP', true) === false) {
16
 
    throw new Exception('Class PHP_CodeSniffer_Tokenizers_PHP not found');
17
 
}
18
 
 
19
 
/**
20
 
 * Tokenizes CSS code.
21
 
 *
22
 
 * @category  PHP
23
 
 * @package   PHP_CodeSniffer
24
 
 * @author    Greg Sherwood <gsherwood@squiz.net>
25
 
 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
26
 
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
27
 
 * @version   Release: 1.5.4
28
 
 * @link      http://pear.php.net/package/PHP_CodeSniffer
29
 
 */
30
 
class PHP_CodeSniffer_Tokenizers_CSS extends PHP_CodeSniffer_Tokenizers_PHP
31
 
{
32
 
 
33
 
 
34
 
    /**
35
 
     * Creates an array of tokens when given some CSS code.
36
 
     *
37
 
     * Uses the PHP tokenizer to do all the tricky work
38
 
     *
39
 
     * @param string $string  The string to tokenize.
40
 
     * @param string $eolChar The EOL character to use for splitting strings.
41
 
     *
42
 
     * @return array
43
 
     */
44
 
    public function tokenizeString($string, $eolChar='\n')
45
 
    {
46
 
        if (PHP_CODESNIFFER_VERBOSITY > 1) {
47
 
            echo "\t*** START CSS TOKENIZING ***".PHP_EOL;
48
 
        }
49
 
 
50
 
        // If the content doesn't have an EOl char on the end, add one so
51
 
        // the open and close tags we add are parsed correctly.
52
 
        if (substr($string, 0, (strlen($eolChar) * -1)) !== $eolChar) {
53
 
            $string .= $eolChar;
54
 
        }
55
 
 
56
 
        $tokens      = parent::tokenizeString('<?php '.$string.'?>', $eolChar);
57
 
        $finalTokens = array();
58
 
 
59
 
        $newStackPtr      = 0;
60
 
        $numTokens        = count($tokens);
61
 
        $multiLineComment = false;
62
 
        for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) {
63
 
            $token = $tokens[$stackPtr];
64
 
 
65
 
            // CSS files don't have lists or break tags, so convert these to
66
 
            // standard strings early so they can be converted into T_STYLE
67
 
            // tokens and joined with other strings if needed.
68
 
            if ($token['code'] === T_BREAK || $token['code'] === T_LIST) {
69
 
                $token['type'] = 'T_STRING';
70
 
                $token['code'] = T_STRING;
71
 
            }
72
 
 
73
 
            if (PHP_CODESNIFFER_VERBOSITY > 1) {
74
 
                $type    = $token['type'];
75
 
                $content = str_replace($eolChar, '\n', $token['content']);
76
 
                echo "\tProcess token $stackPtr: $type => $content".PHP_EOL;
77
 
            }
78
 
 
79
 
            // Sometimes, there are PHP tags embedded in the code, which causes issues
80
 
            // with how PHP tokenizeses the string. After the first closing tag is found,
81
 
            // everything outside PHP tags is set as inline HTML tokens (1 for each line).
82
 
            // So we need to go through and find these tokens so we can re-tokenize them.
83
 
            if ($token['code'] === T_CLOSE_TAG && $stackPtr !== ($numTokens - 1)) {
84
 
                $content = '<?php ';
85
 
                for ($x = ($stackPtr + 1); $x < $numTokens; $x++) {
86
 
                    if ($tokens[$x]['code'] === T_INLINE_HTML) {
87
 
                        $content .= $tokens[$x]['content'];
88
 
                    } else {
89
 
                        $x--;
90
 
                        break;
91
 
                    }
92
 
                }
93
 
 
94
 
                if ($x < ($numTokens - 1)) {
95
 
                    // This is not the last closing tag in the file, so we
96
 
                    // have to add another closing tag here. If it is the last closing
97
 
                    // tag, this additional one would have been added during the
98
 
                    // original tokenize call.
99
 
                    $content .= ' ?>';
100
 
                }
101
 
 
102
 
                if (PHP_CODESNIFFER_VERBOSITY > 1) {
103
 
                    echo "\t\t=> Found premature closing tag at $stackPtr".PHP_EOL;
104
 
                    $cleanContent = str_replace($eolChar, '\n', $content);
105
 
                    echo "\t\tcontent: $cleanContent".PHP_EOL;
106
 
                    $oldNumTokens = $numTokens;
107
 
                }
108
 
 
109
 
                // Tokenize the string and remove the extra PHP tags we don't need.
110
 
                $moreTokens = parent::tokenizeString($content, $eolChar);
111
 
                array_shift($moreTokens);
112
 
                array_pop($moreTokens);
113
 
                array_pop($moreTokens);
114
 
 
115
 
                // Rebuild the tokens array.
116
 
                array_splice($tokens, ($stackPtr + 1), ($x - $stackPtr), $moreTokens);
117
 
                $numTokens = count($tokens);
118
 
                if (PHP_CODESNIFFER_VERBOSITY > 1) {
119
 
                    $count = count($moreTokens);
120
 
                    $diff  = ($x - $stackPtr);
121
 
                    echo "\t\t* added $count tokens, replaced $diff; size changed from $oldNumTokens to $numTokens *".PHP_EOL;
122
 
                }
123
 
            }//end if
124
 
 
125
 
            if ($token['code'] === T_GOTO_LABEL) {
126
 
                // Convert these back to T_STRING folowed by T_COLON so we can
127
 
                // more easily process style definitions.
128
 
                $finalTokens[$newStackPtr] = array(
129
 
                                              'type'    => 'T_STRING',
130
 
                                              'code'    => T_STRING,
131
 
                                              'content' => substr($token['content'], 0, -1),
132
 
                                             );
133
 
                $newStackPtr++;
134
 
                $finalTokens[$newStackPtr] = array(
135
 
                                              'type'    => 'T_COLON',
136
 
                                              'code'    => T_COLON,
137
 
                                              'content' => ':',
138
 
                                             );
139
 
                $newStackPtr++;
140
 
                continue;
141
 
            }
142
 
 
143
 
            if ($token['code'] === T_FUNCTION) {
144
 
                // There are no functions in CSS, so convert this to a string.
145
 
                $finalTokens[$newStackPtr] = array(
146
 
                                              'type'    => 'T_STRING',
147
 
                                              'code'    => T_STRING,
148
 
                                              'content' => $token['content'],
149
 
                                             );
150
 
 
151
 
                $newStackPtr++;
152
 
                continue;
153
 
            }
154
 
 
155
 
            if ($token['code'] === T_COMMENT
156
 
                && substr($token['content'], 0, 2) === '/*'
157
 
            ) {
158
 
                // Multi-line comment. Record it so we can ignore other
159
 
                // comment tags until we get out of this one.
160
 
                $multiLineComment = true;
161
 
            }
162
 
 
163
 
            if ($token['code'] === T_COMMENT
164
 
                && $multiLineComment === false
165
 
                && (substr($token['content'], 0, 2) === '//'
166
 
                || $token['content']{0} === '#')
167
 
            ) {
168
 
                $content = ltrim($token['content'], '#/');
169
 
                $commentTokens
170
 
                    = parent::tokenizeString('<?php '.$content.'?>', $eolChar);
171
 
 
172
 
                // The first and last tokens are the open/close tags.
173
 
                array_shift($commentTokens);
174
 
                array_pop($commentTokens);
175
 
 
176
 
                if ($token['content']{0} === '#') {
177
 
                    // The # character is not a comment in CSS files, so
178
 
                    // determine what it means in this context.
179
 
                    $firstContent = $commentTokens[0]['content'];
180
 
 
181
 
                    // If the first content is just a number, it is probably a
182
 
                    // colour like 8FB7DB, which PHP splits into 8 and FB7DB.
183
 
                    if (($commentTokens[0]['code'] === T_LNUMBER
184
 
                        || $commentTokens[0]['code'] === T_DNUMBER)
185
 
                        && $commentTokens[1]['code'] === T_STRING
186
 
                    ) {
187
 
                        $firstContent .= $commentTokens[1]['content'];
188
 
                        array_shift($commentTokens);
189
 
                    }
190
 
 
191
 
                    // If the first content looks like a colour and not a class
192
 
                    // definition, join the tokens together.
193
 
                    if (preg_match('/^[ABCDEF0-9]+$/i', $firstContent) === 1
194
 
                        && $commentTokens[1]['content'] !== '-'
195
 
                    ) {
196
 
                        array_shift($commentTokens);
197
 
                        // Work out what we trimmed off above and remember to re-add it.
198
 
                        $trimmed = substr($token['content'], 0, (strlen($token['content']) - strlen($content)));
199
 
                        $finalTokens[$newStackPtr] = array(
200
 
                                                      'type'    => 'T_COLOUR',
201
 
                                                      'code'    => T_COLOUR,
202
 
                                                      'content' => $trimmed.$firstContent,
203
 
                                                     );
204
 
                    } else {
205
 
                        $finalTokens[$newStackPtr] = array(
206
 
                                                      'type'    => 'T_HASH',
207
 
                                                      'code'    => T_HASH,
208
 
                                                      'content' => '#',
209
 
                                                     );
210
 
                    }
211
 
                } else {
212
 
                    $finalTokens[$newStackPtr] = array(
213
 
                                                  'type'    => 'T_STRING',
214
 
                                                  'code'    => T_STRING,
215
 
                                                  'content' => '//',
216
 
                                                 );
217
 
                }//end if
218
 
 
219
 
                $newStackPtr++;
220
 
 
221
 
                foreach ($commentTokens as $tokenData) {
222
 
                    if ($tokenData['code'] === T_COMMENT
223
 
                        && (substr($tokenData['content'], 0, 2) === '//'
224
 
                        || $tokenData['content']{0} === '#')
225
 
                    ) {
226
 
                        // This is a comment in a comment, so it needs
227
 
                        // to go through the whole process again.
228
 
                        $tokens[$stackPtr]['content'] = $tokenData['content'];
229
 
                        $stackPtr--;
230
 
                        break;
231
 
                    }
232
 
 
233
 
                    $finalTokens[$newStackPtr] = $tokenData;
234
 
                    $newStackPtr++;
235
 
                }
236
 
 
237
 
                continue;
238
 
            }//end if
239
 
 
240
 
            if ($token['code'] === T_COMMENT 
241
 
                && substr($token['content'], -2) === '*/'
242
 
            ) {
243
 
                // Multi-line comment is done.
244
 
                $multiLineComment = false;
245
 
            }
246
 
 
247
 
            $finalTokens[$newStackPtr] = $token;
248
 
            $newStackPtr++;
249
 
        }//end for
250
 
 
251
 
        // A flag to indicate if we are inside a style definition,
252
 
        // which is defined using curly braces. I'm assuming you can't
253
 
        // have nested curly brackets.
254
 
        $inStyleDef = false;
255
 
 
256
 
        $numTokens = count($finalTokens);
257
 
        for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) {
258
 
            $token = $finalTokens[$stackPtr];
259
 
 
260
 
            switch ($token['code']) {
261
 
            case T_OPEN_CURLY_BRACKET:
262
 
                $inStyleDef = true;
263
 
                break;
264
 
            case T_CLOSE_CURLY_BRACKET:
265
 
                $inStyleDef = false;
266
 
                break;
267
 
            case T_MINUS:
268
 
                // Minus signs are often used instead of spaces inside
269
 
                // class names, IDs and styles.
270
 
                if ($finalTokens[($stackPtr + 1)]['code'] === T_STRING) {
271
 
                    if ($finalTokens[($stackPtr - 1)]['code'] === T_STRING) {
272
 
                        $newContent = $finalTokens[($stackPtr - 1)]['content'].'-'.$finalTokens[($stackPtr + 1)]['content'];
273
 
 
274
 
                        $finalTokens[($stackPtr - 1)]['content'] = $newContent;
275
 
                        unset($finalTokens[$stackPtr]);
276
 
                        unset($finalTokens[($stackPtr + 1)]);
277
 
                        $stackPtr -= 2;
278
 
                    } else {
279
 
                        $newContent = '-'.$finalTokens[($stackPtr + 1)]['content'];
280
 
 
281
 
                        $finalTokens[($stackPtr + 1)]['content'] = $newContent;
282
 
                        unset($finalTokens[$stackPtr]);
283
 
                        $stackPtr--;
284
 
                    }
285
 
 
286
 
                    $finalTokens = array_values($finalTokens);
287
 
                    $numTokens   = count($finalTokens);
288
 
                } else if ($finalTokens[($stackPtr + 1)]['code'] === T_LNUMBER) {
289
 
                    // They can also be used to provide negative numbers.
290
 
                    $finalTokens[($stackPtr + 1)]['content']
291
 
                        = '-'.$finalTokens[($stackPtr + 1)]['content'];
292
 
                    unset($finalTokens[$stackPtr]);
293
 
 
294
 
                    $finalTokens = array_values($finalTokens);
295
 
                    $numTokens   = count($finalTokens);
296
 
                }
297
 
 
298
 
                break;
299
 
            case T_COLON:
300
 
                // Only interested in colons that are defining styles.
301
 
                if ($inStyleDef === false) {
302
 
                    break;
303
 
                }
304
 
 
305
 
                for ($x = ($stackPtr - 1); $x >= 0; $x--) {
306
 
                    if (in_array($finalTokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) {
307
 
                        break;
308
 
                    }
309
 
                }
310
 
 
311
 
                $finalTokens[$x]['type'] = 'T_STYLE';
312
 
                $finalTokens[$x]['code'] = T_STYLE;
313
 
                break;
314
 
            case T_STRING:
315
 
                if (strtolower($token['content']) === 'url') {
316
 
                    // Find the next content.
317
 
                    for ($x = ($stackPtr + 1); $x < $numTokens; $x++) {
318
 
                        if (in_array($finalTokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) {
319
 
                            break;
320
 
                        }
321
 
                    }
322
 
 
323
 
                    // Needs to be in the format "url(" for it to be a URL.
324
 
                    if ($finalTokens[$x]['code'] !== T_OPEN_PARENTHESIS) {
325
 
                        continue;
326
 
                    }
327
 
 
328
 
                    // Make sure the content isn't empty.
329
 
                    for ($y = ($x + 1); $y < $numTokens; $y++) {
330
 
                        if (in_array($finalTokens[$y]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) {
331
 
                            break;
332
 
                        }
333
 
                    }
334
 
 
335
 
                    if ($finalTokens[$y]['code'] === T_CLOSE_PARENTHESIS) {
336
 
                        continue;
337
 
                    }
338
 
 
339
 
                    // Join all the content together inside the url() statement.
340
 
                    $newContent = '';
341
 
                    for ($i = ($x + 2); $i < $numTokens; $i++) {
342
 
                        if ($finalTokens[$i]['code'] === T_CLOSE_PARENTHESIS) {
343
 
                            break;
344
 
                        }
345
 
 
346
 
                        $newContent .= $finalTokens[$i]['content'];
347
 
                        unset($finalTokens[$i]);
348
 
                    }
349
 
 
350
 
                    // If the content inside the "url()" is in double quotes
351
 
                    // there will only be one token and so we don't have to do
352
 
                    // anything except change its type. If it is not empty,
353
 
                    // we need to do some token merging.
354
 
                    $finalTokens[($x + 1)]['type'] = 'T_URL';
355
 
                    $finalTokens[($x + 1)]['code'] = T_URL;
356
 
 
357
 
                    if ($newContent !== '') {
358
 
                        $finalTokens[($x + 1)]['content'] .= $newContent;
359
 
 
360
 
                        $finalTokens = array_values($finalTokens);
361
 
                        $numTokens   = count($finalTokens);
362
 
                    }
363
 
                }//end if
364
 
 
365
 
                break;
366
 
            default:
367
 
                // Nothing special to be done with this token.
368
 
                break;
369
 
            }//end switch
370
 
        }//end for
371
 
 
372
 
        if (PHP_CODESNIFFER_VERBOSITY > 1) {
373
 
            echo "\t*** END CSS TOKENIZING ***".PHP_EOL;
374
 
        }
375
 
 
376
 
        return $finalTokens;
377
 
 
378
 
    }//end tokenizeString()
379
 
 
380
 
 
381
 
    /**
382
 
     * Performs additional processing after main tokenizing.
383
 
     *
384
 
     * @param array  &$tokens The array of tokens to process.
385
 
     * @param string $eolChar The EOL character to use for splitting strings.
386
 
     *
387
 
     * @return void
388
 
     */
389
 
    public function processAdditional(&$tokens, $eolChar)
390
 
    {
391
 
        // We override this method because we don't want the PHP version to
392
 
        // run during CSS processing because it is wasted processing time.
393
 
 
394
 
    }//end processAdditional()
395
 
 
396
 
 
397
 
}//end class
398
 
 
399
 
?>