28 return $matches[1] . htmlspecialchars($matches[2], ENT_COMPAT,
'UTF-8') . $matches[3];
36 if (
$config->get(
'HTML.Trusted')) {
37 $html = preg_replace_callback(
'#(<script[^>]*>)(\s*[^<].+?)(</script>)#si',
38 array($this,
'scriptCallback'), $html);
48 $maintain_line_numbers =
$config->get(
'Core.MaintainLineNumbers');
50 if ($maintain_line_numbers === null) {
53 $maintain_line_numbers =
$config->get(
'Core.CollectErrors');
56 if ($maintain_line_numbers) {
59 $length = strlen($html);
61 $current_line =
false;
65 $context->register(
'CurrentLine', $current_line);
66 $context->register(
'CurrentCol', $current_col);
70 $synchronize_interval =
$config->get(
'Core.DirectLexLineNumberSyncInterval');
73 if (
$config->get(
'Core.CollectErrors')) {
74 $e =& $context->get(
'ErrorCollector');
86 if ($maintain_line_numbers) {
89 $rcursor = $cursor - (int) $inside_tag;
95 $nl_pos = strrpos($html, $nl, $rcursor - $length);
96 $current_col = $rcursor - (is_bool($nl_pos) ? 0 : $nl_pos + 1);
100 $synchronize_interval &&
102 $loops % $synchronize_interval === 0
104 $current_line = 1 + $this->
substrCount($html, $nl, 0, $cursor);
109 $position_next_lt = strpos($html,
'<', $cursor);
110 $position_next_gt = strpos($html,
'>', $cursor);
114 if ($position_next_lt === $cursor) {
119 if (!$inside_tag && $position_next_lt !==
false) {
125 $html, $cursor, $position_next_lt - $cursor
129 if ($maintain_line_numbers) {
130 $token->rawPosition($current_line, $current_col);
131 $current_line += $this->
substrCount($html, $nl, $cursor, $position_next_lt - $cursor);
134 $cursor = $position_next_lt + 1;
137 } elseif (!$inside_tag) {
140 if ($cursor === strlen($html))
break;
150 if ($maintain_line_numbers) $token->rawPosition($current_line, $current_col);
153 } elseif ($inside_tag && $position_next_gt !==
false) {
156 $strlen_segment = $position_next_gt - $cursor;
158 if ($strlen_segment < 1) {
165 $segment = substr($html, $cursor, $strlen_segment);
167 if ($segment ===
false) {
175 substr($segment, 0, 3) ===
'!--'
178 $position_comment_end = strpos($html,
'-->', $cursor);
179 if ($position_comment_end ===
false) {
183 if ($e) $e->send(E_WARNING,
'Lexer: Unclosed comment');
184 $position_comment_end = strlen($html);
189 $strlen_segment = $position_comment_end - $cursor;
190 $segment = substr($html, $cursor, $strlen_segment);
194 $segment, 3, $strlen_segment - 3
197 if ($maintain_line_numbers) {
198 $token->rawPosition($current_line, $current_col);
199 $current_line += $this->
substrCount($html, $nl, $cursor, $strlen_segment);
202 $cursor = $end ? $position_comment_end : $position_comment_end + 3;
208 $is_end_tag = (strpos($segment,
'/') === 0);
210 $type = substr($segment, 1);
212 if ($maintain_line_numbers) {
213 $token->rawPosition($current_line, $current_col);
214 $current_line += $this->
substrCount($html, $nl, $cursor, $position_next_gt - $cursor);
218 $cursor = $position_next_gt + 1;
225 if (!ctype_alpha($segment[0])) {
227 if ($e) $e->send(E_NOTICE,
'Lexer: Unescaped lt');
229 if ($maintain_line_numbers) {
230 $token->rawPosition($current_line, $current_col);
231 $current_line += $this->
substrCount($html, $nl, $cursor, $position_next_gt - $cursor);
242 $is_self_closing = (strrpos($segment,
'/') === $strlen_segment-1);
243 if ($is_self_closing) {
245 $segment = substr($segment, 0, $strlen_segment);
249 $position_first_space = strcspn($segment, $this->_whitespace);
251 if ($position_first_space >= $strlen_segment) {
252 if ($is_self_closing) {
257 if ($maintain_line_numbers) {
258 $token->rawPosition($current_line, $current_col);
259 $current_line += $this->
substrCount($html, $nl, $cursor, $position_next_gt - $cursor);
263 $cursor = $position_next_gt + 1;
268 $type = substr($segment, 0, $position_first_space);
272 $segment, $position_first_space
275 if ($attribute_string) {
284 if ($is_self_closing) {
289 if ($maintain_line_numbers) {
290 $token->rawPosition($current_line, $current_col);
291 $current_line += $this->
substrCount($html, $nl, $cursor, $position_next_gt - $cursor);
294 $cursor = $position_next_gt + 1;
299 if ($e) $e->send(E_WARNING,
'Lexer: Missing gt');
304 substr($html, $cursor)
307 if ($maintain_line_numbers) $token->rawPosition($current_line, $current_col);
315 $context->destroy(
'CurrentLine');
316 $context->destroy(
'CurrentCol');
323 protected function substrCount($haystack, $needle, $offset, $length) {
325 if ($oldVersion === null) {
326 $oldVersion = version_compare(PHP_VERSION,
'5.1',
'<');
329 $haystack = substr($haystack, $offset, $length);
330 return substr_count($haystack, $needle);
332 return substr_count($haystack, $needle, $offset, $length);
343 $string = (string) $string;
345 if ($string ==
'')
return array();
348 if (
$config->get(
'Core.CollectErrors')) {
349 $e =& $context->get(
'ErrorCollector');
354 $num_equal = substr_count($string,
'=');
355 $has_space = strpos($string,
' ');
356 if ($num_equal === 0 && !$has_space) {
358 return array($string => $string);
359 } elseif ($num_equal === 1 && !$has_space) {
361 list($key, $quoted_value) = explode(
'=', $string);
362 $quoted_value = trim($quoted_value);
364 if ($e) $e->send(E_ERROR,
'Lexer: Missing attribute key');
367 if (!$quoted_value)
return array($key =>
'');
368 $first_char = @$quoted_value[0];
369 $last_char = @$quoted_value[strlen($quoted_value)-1];
371 $same_quote = ($first_char == $last_char);
372 $open_quote = ($first_char ==
'"' || $first_char ==
"'");
374 if ( $same_quote && $open_quote) {
376 $value = substr($quoted_value, 1, strlen($quoted_value) - 2);
380 if ($e) $e->send(E_ERROR,
'Lexer: Missing end quote');
381 $value = substr($quoted_value, 1);
383 $value = $quoted_value;
386 if ($value ===
false) $value =
'';
387 return array($key => $value);
393 $size = strlen($string);
401 if ($cursor >= $size) {
405 $cursor += ($value = strspn($string, $this->_whitespace, $cursor));
408 $key_begin = $cursor;
411 $cursor += strcspn($string, $this->_whitespace .
'=', $cursor);
415 $key = substr($string, $key_begin, $key_end - $key_begin);
418 if ($e) $e->send(E_ERROR,
'Lexer: Missing attribute key');
419 $cursor += strcspn($string, $this->_whitespace, $cursor + 1);
424 $cursor += strspn($string, $this->_whitespace, $cursor);
426 if ($cursor >= $size) {
433 $first_char = @$string[$cursor];
435 if ($first_char ==
'=') {
439 $cursor += strspn($string, $this->_whitespace, $cursor);
441 if ($cursor ===
false) {
448 $char = @$string[$cursor];
450 if ($char ==
'"' || $char ==
"'") {
453 $value_begin = $cursor;
454 $cursor = strpos($string, $char, $cursor);
455 $value_end = $cursor;
458 $value_begin = $cursor;
459 $cursor += strcspn($string, $this->_whitespace, $cursor);
460 $value_end = $cursor;
464 if ($cursor ===
false) {
466 $value_end = $cursor;
469 $value = substr($string, $value_begin, $value_end - $value_begin);
470 if ($value ===
false) $value =
'';
480 if ($e) $e->send(E_ERROR,
'Lexer: Missing attribute key');