Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 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 Squiz Pty Ltd (ABN 77 084 670 600)
11
 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
12
 * @version   CVS: $Id: CSS.php 287661 2009-08-25 01:32:53Z squiz $
13
 * @link      http://pear.php.net/package/PHP_CodeSniffer
14
 */
15
 
16
if (class_exists('PHP_CodeSniffer_Tokenizers_PHP', true) === false) {
17
    throw new Exception('Class PHP_CodeSniffer_Tokenizers_PHP not found');
18
}
19
 
20
/**
21
 * Tokenizes CSS code.
22
 *
23
 * @category  PHP
24
 * @package   PHP_CodeSniffer
25
 * @author    Greg Sherwood <gsherwood@squiz.net>
26
 * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
27
 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
28
 * @version   Release: 1.2.1
29
 * @link      http://pear.php.net/package/PHP_CodeSniffer
30
 */
31
class PHP_CodeSniffer_Tokenizers_CSS extends PHP_CodeSniffer_Tokenizers_PHP
32
{
33
 
34
 
35
    /**
36
     * Creates an array of tokens when given some CSS code.
37
     *
38
     * Uses the PHP tokenizer to do all the tricky work
39
     *
40
     * @param string $string  The string to tokenize.
41
     * @param string $eolChar The EOL character to use for splitting strings.
42
     *
43
     * @return array
44
     */
45
    public function tokenizeString($string, $eolChar='\n')
46
    {
47
        $tokens      = parent::tokenizeString('<?php '.$string.' ?>', $eolChar);
48
        $finalTokens = array();
49
 
50
        $newStackPtr      = 0;
51
        $numTokens        = count($tokens);
52
        $multiLineComment = false;
53
        for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) {
54
            $token = $tokens[$stackPtr];
55
 
56
            // Styles like list-style are tokenized as T_LIST-T_STRING
57
            // so convert the T_LIST to a string.
58
            if ($token['code'] === T_LIST) {
59
                $token['code'] = T_STRING;
60
                $token['type'] = 'T_STRING';
61
            }
62
 
63
            if ($token['code'] === T_COMMENT
64
                && substr($token['content'], 0, 2) === '/*'
65
            ) {
66
                // Multi-line comment. Record it so we can ignore other
67
                // comment tags until we get out of this one.
68
                $multiLineComment = true;
69
            }
70
 
71
            if ($token['code'] === T_COMMENT
72
                && $multiLineComment === false
73
                && (substr($token['content'], 0, 2) === '//'
74
                || $token['content']{0} === '#')
75
            ) {
76
                $content = ltrim($token['content'], '#/');
77
                $commentTokens
78
                    = parent::tokenizeString('<?php '.$content.'?>', $eolChar);
79
 
80
                // The first and last tokens are the open/close tags.
81
                array_shift($commentTokens);
82
                array_pop($commentTokens);
83
 
84
                if ($token['content']{0} === '#') {
85
                    // The # character is not a comment in CSS files, so
86
                    // determine what it means in this context.
87
                    $firstContent = $commentTokens[0]['content'];
88
 
89
                    // If the first content is just a number, it is probably a
90
                    // colour like 8FB7DB, which PHP splits into 8 and FB7DB.
91
                    if (($commentTokens[0]['code'] === T_LNUMBER
92
                        || $commentTokens[0]['code'] === T_DNUMBER)
93
                        && $commentTokens[1]['code'] === T_STRING
94
                    ) {
95
                        $firstContent .= $commentTokens[1]['content'];
96
                        array_shift($commentTokens);
97
                    }
98
 
99
                    // If the first content looks like a colour and not a class
100
                    // definition, join the tokens together.
101
                    if (preg_match('/^[ABCDEF0-9]+$/i', $firstContent) === 1) {
102
                        array_shift($commentTokens);
103
                        $finalTokens[$newStackPtr] = array(
104
                                                      'type'    => 'T_COLOUR',
105
                                                      'code'    => T_COLOUR,
106
                                                      'content' => '#'.$firstContent,
107
                                                     );
108
                    } else {
109
                        $finalTokens[$newStackPtr] = array(
110
                                                      'type'    => 'T_HASH',
111
                                                      'code'    => T_HASH,
112
                                                      'content' => '#',
113
                                                     );
114
                    }
115
                } else {
116
                    $finalTokens[$newStackPtr] = array(
117
                                                  'type'    => 'T_STRING',
118
                                                  'code'    => T_STRING,
119
                                                  'content' => '//',
120
                                                 );
121
                }//end if
122
 
123
                $newStackPtr++;
124
 
125
                foreach ($commentTokens as $tokenData) {
126
                    if ($tokenData['code'] === T_COMMENT
127
                        && (substr($tokenData['content'], 0, 2) === '//'
128
                        || $tokenData['content']{0} === '#')
129
                    ) {
130
                        // This is a comment in a comment, so it needs
131
                        // to go through the whole process again.
132
                        $tokens[$stackPtr]['content'] = $tokenData['content'];
133
                        $stackPtr--;
134
                        break;
135
                    }
136
 
137
                    $finalTokens[$newStackPtr] = $tokenData;
138
                    $newStackPtr++;
139
                }
140
 
141
                continue;
142
            }//end if
143
 
144
            if ($token['code'] === T_COMMENT
145
                && substr($token['content'], -2) === '*/'
146
            ) {
147
                // Multi-line comment is done.
148
                $multiLineComment = false;
149
            }
150
 
151
            $finalTokens[$newStackPtr] = $token;
152
            $newStackPtr++;
153
        }//end for
154
 
155
        // A flag to indicate if we are inside a style definition,
156
        // which is defined using curly braces. I'm assuming you can't
157
        // have nested curly brackets.
158
        $inStyleDef = false;
159
 
160
        $numTokens = count($finalTokens);
161
        for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) {
162
            $token = $finalTokens[$stackPtr];
163
 
164
            switch ($token['code']) {
165
            case T_OPEN_CURLY_BRACKET:
166
                $inStyleDef = true;
167
                break;
168
            case T_CLOSE_CURLY_BRACKET:
169
                $inStyleDef = false;
170
                break;
171
            case T_MINUS:
172
                // Minus signs are often used instead of spaces inside
173
                // class names, IDs and styles.
174
                if ($finalTokens[($stackPtr + 1)]['code'] === T_STRING) {
175
                    if ($finalTokens[($stackPtr - 1)]['code'] === T_STRING) {
176
                        $newContent = $finalTokens[($stackPtr - 1)]['content'].'-'.$finalTokens[($stackPtr + 1)]['content'];
177
 
178
                        $finalTokens[($stackPtr - 1)]['content'] = $newContent;
179
                        unset($finalTokens[$stackPtr]);
180
                        unset($finalTokens[($stackPtr + 1)]);
181
                        $stackPtr -= 2;
182
                    } else {
183
                        $newContent = '-'.$finalTokens[($stackPtr + 1)]['content'];
184
 
185
                        $finalTokens[($stackPtr + 1)]['content'] = $newContent;
186
                        unset($finalTokens[$stackPtr]);
187
                        $stackPtr--;
188
                    }
189
 
190
                    $finalTokens = array_values($finalTokens);
191
                    $numTokens   = count($finalTokens);
192
                } else if ($finalTokens[($stackPtr + 1)]['code'] === T_LNUMBER) {
193
                    // They can also be used to provide negative numbers.
194
                    $finalTokens[($stackPtr + 1)]['content']
195
                        = '-'.$finalTokens[($stackPtr + 1)]['content'];
196
                    unset($finalTokens[$stackPtr]);
197
 
198
                    $finalTokens = array_values($finalTokens);
199
                    $numTokens   = count($finalTokens);
200
                }
201
 
202
                break;
203
            case T_COLON:
204
                // Only interested in colons that are defining styles.
205
                if ($inStyleDef === false) {
206
                    break;
207
                }
208
 
209
                for ($x = ($stackPtr - 1); $x >= 0; $x--) {
210
                    if (in_array($finalTokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) {
211
                        break;
212
                    }
213
                }
214
 
215
                $finalTokens[$x]['type'] = 'T_STYLE';
216
                $finalTokens[$x]['code'] = T_STYLE;
217
                break;
218
            case T_STRING:
219
                if (strtolower($token['content']) === 'url') {
220
                    // Find the next content.
221
                    for ($x = ($stackPtr + 1); $x < $numTokens; $x++) {
222
                        if (in_array($finalTokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) {
223
                            break;
224
                        }
225
                    }
226
 
227
                    // Needs to be in the format url( for it to be a URL.
228
                    if ($finalTokens[$x]['code'] !== T_OPEN_PARENTHESIS) {
229
                        continue;
230
                    }
231
 
232
                    // Make sure the content isn't empty.
233
                    for ($y = ($x + 1); $y < $numTokens; $y++) {
234
                        if (in_array($finalTokens[$y]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) {
235
                            break;
236
                        }
237
                    }
238
 
239
                    if ($finalTokens[$y]['code'] === T_CLOSE_PARENTHESIS) {
240
                        continue;
241
                    }
242
 
243
                    // Join all the content together inside the url() statement.
244
                    $newContent = '';
245
                    for ($i = ($x + 2); $i < $numTokens; $i++) {
246
                        if ($finalTokens[$i]['code'] === T_CLOSE_PARENTHESIS) {
247
                            break;
248
                        }
249
 
250
                        $newContent .= $finalTokens[$i]['content'];
251
                        unset($finalTokens[$i]);
252
                    }
253
 
254
                    if ($newContent !== '') {
255
                        $finalTokens[($x + 1)]['type']     = 'T_URL';
256
                        $finalTokens[($x + 1)]['code']     = T_URL;
257
                        $finalTokens[($x + 1)]['content'] .= $newContent;
258
 
259
                        $finalTokens = array_values($finalTokens);
260
                        $numTokens   = count($finalTokens);
261
                    }
262
                }//end if
263
 
264
                break;
265
            default:
266
                // Nothing special to be done with this token.
267
                break;
268
            }//end switch
269
        }//end for
270
 
271
        return $finalTokens;
272
 
273
    }//end tokenizeString()
274
 
275
 
276
    /**
277
     * Performs additional processing after main tokenizing.
278
     *
279
     * This method is blank because we don't want the extra
280
     * processing that the PHP tokenizer performs.
281
     *
282
     * @param array  &$tokens The array of tokens to process.
283
     * @param string $eolChar The EOL character to use for splitting strings.
284
     *
285
     * @return void
286
     */
287
    public function processAdditional(&$tokens, $eolChar)
288
    {
289
 
290
    }//end processAdditional()
291
 
292
 
293
}//end class
294
 
295
?>