Completed
Push — master ( ed92f4...60669a )
by Daniel
03:02
created

thirdparty/html5lib/HTML5/InputStream.php (7 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
5
Copyright 2009 Geoffrey Sneddon <http://gsnedders.com/>
6
7
Permission is hereby granted, free of charge, to any person obtaining a
8
copy of this software and associated documentation files (the
9
"Software"), to deal in the Software without restriction, including
10
without limitation the rights to use, copy, modify, merge, publish,
11
distribute, sublicense, and/or sell copies of the Software, and to
12
permit persons to whom the Software is furnished to do so, subject to
13
the following conditions:
14
15
The above copyright notice and this permission notice shall be included
16
in all copies or substantial portions of the Software.
17
18
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26
*/
27
28
// Some conventions:
29
// /* */ indicates verbatim text from the HTML 5 specification
30
// // indicates regular comments
31
32
class HTML5_InputStream {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
As per PSR2, the opening brace for this class should be on a new line.
Loading history...
33
    /**
34
     * The string data we're parsing.
35
     */
36
    private $data;
37
38
    /**
39
     * The current integer byte position we are in $data
40
     */
41
    private $char;
42
43
    /**
44
     * Length of $data; when $char === $data, we are at the end-of-file.
45
     */
46
    private $EOF;
47
48
    /**
49
     * Parse errors.
50
     */
51
    public $errors = array();
52
53
    /**
54
     * @param $data Data to parse
55
     */
56
    public function __construct($data) {
57
58
        /* Given an encoding, the bytes in the input stream must be
59
        converted to Unicode characters for the tokeniser, as
60
        described by the rules for that encoding, except that the
61
        leading U+FEFF BYTE ORDER MARK character, if any, must not
62
        be stripped by the encoding layer (it is stripped by the rule below).
63
64
        Bytes or sequences of bytes in the original byte stream that
65
        could not be converted to Unicode characters must be converted
66
        to U+FFFD REPLACEMENT CHARACTER code points. */
67
68
        // XXX currently assuming input data is UTF-8; once we
69
        // build encoding detection this will no longer be the case
70
        //
71
        // We previously had an mbstring implementation here, but that
72
        // implementation is heavily non-conforming, so it's been
73
        // omitted.
74
        if (extension_loaded('iconv')) {
75
            // non-conforming
76
            $data = @iconv('UTF-8', 'UTF-8//IGNORE', $data);
77
        } else {
78
            // we can make a conforming native implementation
79
            throw new Exception('Not implemented, please install mbstring or iconv');
80
        }
81
82
        /* One leading U+FEFF BYTE ORDER MARK character must be
83
        ignored if any are present. */
84
        if (substr($data, 0, 3) === "\xEF\xBB\xBF") {
85
            $data = substr($data, 3);
86
        }
87
88
        /* All U+0000 NULL characters in the input must be replaced
89
        by U+FFFD REPLACEMENT CHARACTERs. Any occurrences of such
90
        characters is a parse error. */
91 View Code Duplication
        for ($i = 0, $count = substr_count($data, "\0"); $i < $count; $i++) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
92
            $this->errors[] = array(
93
                'type' => HTML5_Tokenizer::PARSEERROR,
94
                'data' => 'null-character'
95
            );
96
        }
97
        /* U+000D CARRIAGE RETURN (CR) characters and U+000A LINE FEED
98
        (LF) characters are treated specially. Any CR characters
99
        that are followed by LF characters must be removed, and any
100
        CR characters not followed by LF characters must be converted
101
        to LF characters. Thus, newlines in HTML DOMs are represented
102
        by LF characters, and there are never any CR characters in the
103
        input to the tokenization stage. */
104
        $data = str_replace(
105
            array(
106
                "\0",
107
                "\r\n",
108
                "\r"
109
            ),
110
            array(
111
                "\xEF\xBF\xBD",
112
                "\n",
113
                "\n"
114
            ),
115
            $data
116
        );
117
118
        /* Any occurrences of any characters in the ranges U+0001 to
119
        U+0008, U+000B,  U+000E to U+001F,  U+007F  to U+009F,
120
        U+D800 to U+DFFF , U+FDD0 to U+FDEF, and
121
        characters U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, U+2FFFE, U+2FFFF,
122
        U+3FFFE, U+3FFFF, U+4FFFE, U+4FFFF, U+5FFFE, U+5FFFF, U+6FFFE,
123
        U+6FFFF, U+7FFFE, U+7FFFF, U+8FFFE, U+8FFFF, U+9FFFE, U+9FFFF,
124
        U+AFFFE, U+AFFFF, U+BFFFE, U+BFFFF, U+CFFFE, U+CFFFF, U+DFFFE,
125
        U+DFFFF, U+EFFFE, U+EFFFF, U+FFFFE, U+FFFFF, U+10FFFE, and
126
        U+10FFFF are parse errors. (These are all control characters
127
        or permanently undefined Unicode characters.) */
128
        // Check PCRE is loaded.
129
        if (extension_loaded('pcre')) {
130
            $count = preg_match_all(
131
                '/(?:
132
                    [\x01-\x08\x0B\x0E-\x1F\x7F] # U+0001 to U+0008, U+000B,  U+000E to U+001F and U+007F
133
                |
134
                    \xC2[\x80-\x9F] # U+0080 to U+009F
135
                |
136
                    \xED(?:\xA0[\x80-\xFF]|[\xA1-\xBE][\x00-\xFF]|\xBF[\x00-\xBF]) # U+D800 to U+DFFFF
137
                |
138
                    \xEF\xB7[\x90-\xAF] # U+FDD0 to U+FDEF
139
                |
140
                    \xEF\xBF[\xBE\xBF] # U+FFFE and U+FFFF
141
                |
142
                    [\xF0-\xF4][\x8F-\xBF]\xBF[\xBE\xBF] # U+nFFFE and U+nFFFF (1 <= n <= 10_{16})
143
                )/x',
144
                $data,
145
                $matches
146
            );
147 View Code Duplication
            for ($i = 0; $i < $count; $i++) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
148
                $this->errors[] = array(
149
                    'type' => HTML5_Tokenizer::PARSEERROR,
150
                    'data' => 'invalid-codepoint'
151
                );
152
            }
153
        } else {
0 ignored issues
show
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
154
            // XXX: Need non-PCRE impl, probably using substr_count
155
        }
156
157
        $this->data = $data;
158
        $this->char = 0;
159
        $this->EOF  = strlen($data);
160
    }
161
162
    /**
163
     * Returns the current line that the tokenizer is at.
164
     */
165
    public function getCurrentLine() {
166
        // Check the string isn't empty
167
        if($this->EOF) {
168
            // Add one to $this->char because we want the number for the next
169
            // byte to be processed.
170
            return substr_count($this->data, "\n", 0, min($this->char, $this->EOF)) + 1;
171
        } else {
172
            // If the string is empty, we are on the first line (sorta).
173
            return 1;
174
        }
175
    }
176
177
    /**
178
     * Returns the current column of the current line that the tokenizer is at.
179
     */
180
    public function getColumnOffset() {
181
        // strrpos is weird, and the offset needs to be negative for what we
182
        // want (i.e., the last \n before $this->char). This needs to not have
183
        // one (to make it point to the next character, the one we want the
184
        // position of) added to it because strrpos's behaviour includes the
185
        // final offset byte.
186
        $lastLine = strrpos($this->data, "\n", $this->char - 1 - strlen($this->data));
187
188
        // However, for here we want the length up until the next byte to be
189
        // processed, so add one to the current byte ($this->char).
190
        if($lastLine !== false) {
191
            $findLengthOf = substr($this->data, $lastLine + 1, $this->char - 1 - $lastLine);
192
        } else {
193
            $findLengthOf = substr($this->data, 0, $this->char);
194
        }
195
196
        // Get the length for the string we need.
197
        if(extension_loaded('iconv')) {
198
            return iconv_strlen($findLengthOf, 'utf-8');
199
        } elseif(extension_loaded('mbstring')) {
200
            return mb_strlen($findLengthOf, 'utf-8');
201
        } elseif(extension_loaded('xml')) {
202
            return strlen(utf8_decode($findLengthOf));
203
        } else {
204
            $count = count_chars($findLengthOf);
205
            // 0x80 = 0x7F - 0 + 1 (one added to get inclusive range)
206
            // 0x33 = 0xF4 - 0x2C + 1 (one added to get inclusive range)
207
            return array_sum(array_slice($count, 0, 0x80)) +
208
                   array_sum(array_slice($count, 0xC2, 0x33));
209
        }
210
    }
211
212
    /**
213
     * Retrieve the currently consume character.
214
     * @note This performs bounds checking
215
     */
216
    public function char() {
217
        return ($this->char++ < $this->EOF)
218
            ? $this->data[$this->char - 1]
219
            : false;
220
    }
221
222
    /**
223
     * Get all characters until EOF.
224
     * @note This performs bounds checking
225
     */
226
    public function remainingChars() {
227
        if($this->char < $this->EOF) {
228
            $data = substr($this->data, $this->char);
229
            $this->char = $this->EOF;
230
            return $data;
231
        } else {
232
            return false;
233
        }
234
    }
235
236
    /**
237
     * Matches as far as possible until we reach a certain set of bytes
238
     * and returns the matched substring.
239
     * @param $bytes Bytes to match.
240
     */
241 View Code Duplication
    public function charsUntil($bytes, $max = null) {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
242
        if ($this->char < $this->EOF) {
243
            if ($max === 0 || $max) {
244
                $len = strcspn($this->data, $bytes, $this->char, $max);
245
            } else {
246
                $len = strcspn($this->data, $bytes, $this->char);
247
            }
248
            $string = (string) substr($this->data, $this->char, $len);
249
            $this->char += $len;
250
            return $string;
251
        } else {
252
            return false;
253
        }
254
    }
255
256
    /**
257
     * Matches as far as possible with a certain set of bytes
258
     * and returns the matched substring.
259
     * @param $bytes Bytes to match.
260
     */
261 View Code Duplication
    public function charsWhile($bytes, $max = null) {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
262
        if ($this->char < $this->EOF) {
263
            if ($max === 0 || $max) {
264
                $len = strspn($this->data, $bytes, $this->char, $max);
265
            } else {
266
                $len = strspn($this->data, $bytes, $this->char);
267
            }
268
            $string = (string) substr($this->data, $this->char, $len);
269
            $this->char += $len;
270
            return $string;
271
        } else {
272
            return false;
273
        }
274
    }
275
276
    /**
277
     * Unconsume one character.
278
     */
279
    public function unget() {
280
        if ($this->char <= $this->EOF) {
281
            $this->char--;
282
        }
283
    }
284
}
285