ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
HTMLPurifier_Lexer Class Reference

Forgivingly lexes HTML (SGML-style) markup into tokens. More...

+ Inheritance diagram for HTMLPurifier_Lexer:
+ Collaboration diagram for HTMLPurifier_Lexer:

Public Member Functions

 __construct ()
 
 parseText ($string, $config)
 
 parseAttr ($string, $config)
 
 parseData ($string, $is_attr, $config)
 Parses special entities into the proper characters. More...
 
 tokenizeHTML ($string, $config, $context)
 Lexes an HTML string into tokens. More...
 
 normalize ($html, $config, $context)
 Takes a piece of HTML and normalizes it by converting entities, fixing encoding, extracting bits, and other good stuff. More...
 
 extractBody ($html)
 Takes a string of HTML (fragment or document) and returns the content. More...
 

Static Public Member Functions

static create ($config)
 Retrieves or sets the default Lexer as a Prototype Factory. More...
 

Data Fields

 $tracksLineNumbers = false
 Whether or not this lexer implements line-number/column-number tracking. More...
 

Static Protected Member Functions

static escapeCDATA ($string)
 Translates CDATA sections into regular sections (through escaping). More...
 
static escapeCommentedCDATA ($string)
 Special CDATA case that is especially convoluted for <script> More...
 
static removeIEConditional ($string)
 Special Internet Explorer conditional comments should be removed. More...
 
static CDATACallback ($matches)
 Callback function for escapeCDATA() that does the work. More...
 

Protected Attributes

 $_special_entity2str
 Most common entity to raw value conversion table for special entities. More...
 

Detailed Description

Forgivingly lexes HTML (SGML-style) markup into tokens.

A lexer parses a string of SGML-style markup and converts them into corresponding tokens. It doesn't check for well-formedness, although its internal mechanism may make this automatic (such as the case of HTMLPurifier_Lexer_DOMLex). There are several implementations to choose from.

A lexer is HTML-oriented: it might work with XML, but it's not recommended, as we adhere to a subset of the specification for optimization reasons. This might change in the future. Also, most tokenizers are not expected to handle DTDs or PIs.

This class should not be directly instantiated, but you may use create() to retrieve a default copy of the lexer. Being a supertype, this class does not actually define any implementation, but offers commonly used convenience functions for subclasses.

Note
The unit tests will instantiate this class for testing purposes, as many of the utility functions require a class to be instantiated. This means that, even though this class is not runnable, it will not be declared abstract.
Note
We use tokens rather than create a DOM representation because DOM would:
  1. Require more processing and memory to create,
  2. Is not streamable, and
  3. Has the entire document structure (html and body not needed).
However, DOM is helpful in that it makes it easy to move around nodes without a lot of lookaheads to see when a tag is closed. This is a limitation of the token system and some workarounds would be nice.

Definition at line 42 of file Lexer.php.

Constructor & Destructor Documentation

◆ __construct()

HTMLPurifier_Lexer::__construct ( )

Definition at line 152 of file Lexer.php.

153  {
154  $this->_entity_parser = new HTMLPurifier_EntityParser();
155  }
Handles referencing and derefencing character entities.

Member Function Documentation

◆ CDATACallback()

static HTMLPurifier_Lexer::CDATACallback (   $matches)
staticprotected

Callback function for escapeCDATA() that does the work.

Warning
Though this is public in order to let the callback happen, calling it directly is not recommended.
Parameters
array$matchesPCRE matches array, with index 0 the entire match and 1 the inside of the CDATA section.
Returns
string Escaped internals of the CDATA section.

Definition at line 290 of file Lexer.php.

291  {
292  // not exactly sure why the character set is needed, but whatever
293  return htmlspecialchars($matches[1], ENT_COMPAT, 'UTF-8');
294  }

◆ create()

static HTMLPurifier_Lexer::create (   $config)
static

Retrieves or sets the default Lexer as a Prototype Factory.

By default HTMLPurifier_Lexer_DOMLex will be returned. There are a few exceptions involving special features that only DirectLex implements.

Note
The behavior of this class has changed, rather than accepting a prototype object, it now accepts a configuration object. To specify your own prototype, set Core.LexerImpl to it. This change in behavior de-singletonizes the lexer object.
Parameters
HTMLPurifier_Config$config
Returns
HTMLPurifier_Lexer
Exceptions
HTMLPurifier_Exception

Definition at line 69 of file Lexer.php.

References $config.

Referenced by HTMLPurifier\purify().

70  {
71  if (!($config instanceof HTMLPurifier_Config)) {
72  $lexer = $config;
73  trigger_error(
74  "Passing a prototype to
75  HTMLPurifier_Lexer::create() is deprecated, please instead
76  use %Core.LexerImpl",
77  E_USER_WARNING
78  );
79  } else {
80  $lexer = $config->get('Core.LexerImpl');
81  }
82 
83  $needs_tracking =
84  $config->get('Core.MaintainLineNumbers') ||
85  $config->get('Core.CollectErrors');
86 
87  $inst = null;
88  if (is_object($lexer)) {
89  $inst = $lexer;
90  } else {
91  if (is_null($lexer)) {
92  do {
93  // auto-detection algorithm
94  if ($needs_tracking) {
95  $lexer = 'DirectLex';
96  break;
97  }
98 
99  if (class_exists('DOMDocument', false) &&
100  method_exists('DOMDocument', 'loadHTML') &&
101  !extension_loaded('domxml')
102  ) {
103  // check for DOM support, because while it's part of the
104  // core, it can be disabled compile time. Also, the PECL
105  // domxml extension overrides the default DOM, and is evil
106  // and nasty and we shan't bother to support it
107  $lexer = 'DOMLex';
108  } else {
109  $lexer = 'DirectLex';
110  }
111  } while (0);
112  } // do..while so we can break
113 
114  // instantiate recognized string names
115  switch ($lexer) {
116  case 'DOMLex':
117  $inst = new HTMLPurifier_Lexer_DOMLex();
118  break;
119  case 'DirectLex':
120  $inst = new HTMLPurifier_Lexer_DirectLex();
121  break;
122  case 'PH5P':
123  $inst = new HTMLPurifier_Lexer_PH5P();
124  break;
125  default:
126  throw new HTMLPurifier_Exception(
127  "Cannot instantiate unrecognized Lexer type " .
128  htmlspecialchars($lexer)
129  );
130  }
131  }
132 
133  if (!$inst) {
134  throw new HTMLPurifier_Exception('No lexer was instantiated');
135  }
136 
137  // once PHP DOM implements native line numbers, or we
138  // hack out something using XSLT, remove this stipulation
139  if ($needs_tracking && !$inst->tracksLineNumbers) {
140  throw new HTMLPurifier_Exception(
141  'Cannot use lexer that does not support line numbers with ' .
142  'Core.MaintainLineNumbers or Core.CollectErrors (use DirectLex instead)'
143  );
144  }
145 
146  return $inst;
147 
148  }
$config
Definition: bootstrap.php:15
Experimental HTML5-based parser using Jeroen van der Meer&#39;s PH5P library.
Definition: PH5P.php:13
Parser that uses PHP 5&#39;s DOM extension (part of the core).
Definition: DOMLex.php:27
Our in-house implementation of a parser.
Definition: DirectLex.php:13
Global exception class for HTML Purifier; any exceptions we throw are from here.
Definition: Exception.php:7
Configuration object that triggers customizable behavior.
Definition: Config.php:17
+ Here is the caller graph for this function:

◆ escapeCDATA()

static HTMLPurifier_Lexer::escapeCDATA (   $string)
staticprotected

Translates CDATA sections into regular sections (through escaping).

Parameters
string$stringHTML string to process.
Returns
string HTML with CDATA sections escaped.

Definition at line 244 of file Lexer.php.

Referenced by normalize().

245  {
246  return preg_replace_callback(
247  '/<!\[CDATA\[(.+?)\]\]>/s',
248  array('HTMLPurifier_Lexer', 'CDATACallback'),
249  $string
250  );
251  }
+ Here is the caller graph for this function:

◆ escapeCommentedCDATA()

static HTMLPurifier_Lexer::escapeCommentedCDATA (   $string)
staticprotected

Special CDATA case that is especially convoluted for <script>

Parameters
string$stringHTML string to process.
Returns
string HTML with CDATA sections escaped.

Definition at line 258 of file Lexer.php.

Referenced by normalize().

259  {
260  return preg_replace_callback(
261  '#<!--//--><!\[CDATA\[//><!--(.+?)//--><!\]\]>#s',
262  array('HTMLPurifier_Lexer', 'CDATACallback'),
263  $string
264  );
265  }
+ Here is the caller graph for this function:

◆ extractBody()

HTMLPurifier_Lexer::extractBody (   $html)

Takes a string of HTML (fragment or document) and returns the content.

Todo:
Consider making protected

Definition at line 365 of file Lexer.php.

References $html, and $result.

Referenced by normalize().

366  {
367  $matches = array();
368  $result = preg_match('|(.*?)<body[^>]*>(.*)</body>|is', $html, $matches);
369  if ($result) {
370  // Make sure it's not in a comment
371  $comment_start = strrpos($matches[1], '<!--');
372  $comment_end = strrpos($matches[1], '-->');
373  if ($comment_start === false ||
374  ($comment_end !== false && $comment_end > $comment_start)) {
375  return $matches[2];
376  }
377  }
378  return $html;
379  }
$result
$html
Definition: example_001.php:87
+ Here is the caller graph for this function:

◆ normalize()

HTMLPurifier_Lexer::normalize (   $html,
  $config,
  $context 
)

Takes a piece of HTML and normalizes it by converting entities, fixing encoding, extracting bits, and other good stuff.

Parameters
string$htmlHTML.
HTMLPurifier_Config$config
HTMLPurifier_Context$context
Returns
string
Todo:
Consider making protected

Definition at line 305 of file Lexer.php.

References $config, $context, $html, HTMLPurifier_Encoder\cleanUTF8(), escapeCDATA(), escapeCommentedCDATA(), extractBody(), and removeIEConditional().

Referenced by HTMLPurifier_Lexer_PH5P\tokenizeHTML(), HTMLPurifier_Lexer_DirectLex\tokenizeHTML(), and HTMLPurifier_Lexer_DOMLex\tokenizeHTML().

306  {
307  // normalize newlines to \n
308  if ($config->get('Core.NormalizeNewlines')) {
309  $html = str_replace("\r\n", "\n", $html);
310  $html = str_replace("\r", "\n", $html);
311  }
312 
313  if ($config->get('HTML.Trusted')) {
314  // escape convoluted CDATA
315  $html = $this->escapeCommentedCDATA($html);
316  }
317 
318  // escape CDATA
319  $html = $this->escapeCDATA($html);
320 
321  $html = $this->removeIEConditional($html);
322 
323  // extract body from document if applicable
324  if ($config->get('Core.ConvertDocumentToFragment')) {
325  $e = false;
326  if ($config->get('Core.CollectErrors')) {
327  $e =& $context->get('ErrorCollector');
328  }
329  $new_html = $this->extractBody($html);
330  if ($e && $new_html != $html) {
331  $e->send(E_WARNING, 'Lexer: Extracted body');
332  }
333  $html = $new_html;
334  }
335 
336  // expand entities that aren't the big five
337  if ($config->get('Core.LegacyEntityDecoder')) {
338  $html = $this->_entity_parser->substituteNonSpecialEntities($html);
339  }
340 
341  // clean into wellformed UTF-8 string for an SGML context: this has
342  // to be done after entity expansion because the entities sometimes
343  // represent non-SGML characters (horror, horror!)
345 
346  // if processing instructions are to removed, remove them now
347  if ($config->get('Core.RemoveProcessingInstructions')) {
348  $html = preg_replace('#<\?.+?\?>#s', '', $html);
349  }
350 
351  $hidden_elements = $config->get('Core.HiddenElements');
352  if ($config->get('Core.AggressivelyRemoveScript') &&
353  !($config->get('HTML.Trusted') || !$config->get('Core.RemoveScriptContents')
354  || empty($hidden_elements["script"]))) {
355  $html = preg_replace('#<script[^>]*>.*?</script>#i', '', $html);
356  }
357 
358  return $html;
359  }
static removeIEConditional($string)
Special Internet Explorer conditional comments should be removed.
Definition: Lexer.php:272
$context
Definition: webdav.php:25
$config
Definition: bootstrap.php:15
static cleanUTF8($str, $force_php=false)
Cleans a UTF-8 string for well-formedness and SGML validity.
Definition: Encoder.php:134
static escapeCDATA($string)
Translates CDATA sections into regular sections (through escaping).
Definition: Lexer.php:244
extractBody($html)
Takes a string of HTML (fragment or document) and returns the content.
Definition: Lexer.php:365
static escapeCommentedCDATA($string)
Special CDATA case that is especially convoluted for <script>
Definition: Lexer.php:258
$html
Definition: example_001.php:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parseAttr()

HTMLPurifier_Lexer::parseAttr (   $string,
  $config 
)

Definition at line 176 of file Lexer.php.

References $config, and parseData().

Referenced by HTMLPurifier_Lexer_DirectLex\parseAttributeString().

176  {
177  return $this->parseData($string, true, $config);
178  }
$config
Definition: bootstrap.php:15
parseData($string, $is_attr, $config)
Parses special entities into the proper characters.
Definition: Lexer.php:189
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parseData()

HTMLPurifier_Lexer::parseData (   $string,
  $is_attr,
  $config 
)

Parses special entities into the proper characters.

This string will translate escaped versions of the special characters into the correct ones.

Parameters
string$stringString character data to be parsed.
Returns
string Parsed character data.

Definition at line 189 of file Lexer.php.

References $config.

Referenced by parseAttr(), and parseText().

190  {
191  // following functions require at least one character
192  if ($string === '') {
193  return '';
194  }
195 
196  // subtracts amps that cannot possibly be escaped
197  $num_amp = substr_count($string, '&') - substr_count($string, '& ') -
198  ($string[strlen($string) - 1] === '&' ? 1 : 0);
199 
200  if (!$num_amp) {
201  return $string;
202  } // abort if no entities
203  $num_esc_amp = substr_count($string, '&amp;');
204  $string = strtr($string, $this->_special_entity2str);
205 
206  // code duplication for sake of optimization, see above
207  $num_amp_2 = substr_count($string, '&') - substr_count($string, '& ') -
208  ($string[strlen($string) - 1] === '&' ? 1 : 0);
209 
210  if ($num_amp_2 <= $num_esc_amp) {
211  return $string;
212  }
213 
214  // hmm... now we have some uncommon entities. Use the callback.
215  if ($config->get('Core.LegacyEntityDecoder')) {
216  $string = $this->_entity_parser->substituteSpecialEntities($string);
217  } else {
218  if ($is_attr) {
219  $string = $this->_entity_parser->substituteAttrEntities($string);
220  } else {
221  $string = $this->_entity_parser->substituteTextEntities($string);
222  }
223  }
224  return $string;
225  }
$config
Definition: bootstrap.php:15
+ Here is the caller graph for this function:

◆ parseText()

HTMLPurifier_Lexer::parseText (   $string,
  $config 
)

Definition at line 172 of file Lexer.php.

References $config, and parseData().

Referenced by HTMLPurifier_Lexer_DOMLex\createStartNode(), and HTMLPurifier_Lexer_DirectLex\tokenizeHTML().

172  {
173  return $this->parseData($string, false, $config);
174  }
$config
Definition: bootstrap.php:15
parseData($string, $is_attr, $config)
Parses special entities into the proper characters.
Definition: Lexer.php:189
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ removeIEConditional()

static HTMLPurifier_Lexer::removeIEConditional (   $string)
staticprotected

Special Internet Explorer conditional comments should be removed.

Parameters
string$stringHTML string to process.
Returns
string HTML with conditional comments removed.

Definition at line 272 of file Lexer.php.

Referenced by normalize().

273  {
274  return preg_replace(
275  '#<!--\[if [^>]+\]>.*?<!\[endif\]-->#si', // probably should generalize for all strings
276  '',
277  $string
278  );
279  }
+ Here is the caller graph for this function:

◆ tokenizeHTML()

HTMLPurifier_Lexer::tokenizeHTML (   $string,
  $config,
  $context 
)

Lexes an HTML string into tokens.

Parameters
$stringString HTML.
HTMLPurifier_Config$config
HTMLPurifier_Context$context
Returns
HTMLPurifier_Token[] array representation of HTML.

Definition at line 234 of file Lexer.php.

235  {
236  trigger_error('Call to abstract class', E_USER_ERROR);
237  }

Field Documentation

◆ $_special_entity2str

HTMLPurifier_Lexer::$_special_entity2str
protected
Initial value:
=
array(
'&quot;' => '"',
'&amp;' => '&',
'&lt;' => '<',
'&gt;' => '>',
'&#39;' => "'",
'&#039;' => "'",
'&#x27;' => "'"
)

Most common entity to raw value conversion table for special entities.

array

Definition at line 161 of file Lexer.php.

◆ $tracksLineNumbers

HTMLPurifier_Lexer::$tracksLineNumbers = false

Whether or not this lexer implements line-number/column-number tracking.

If it does, set to true.

Definition at line 49 of file Lexer.php.


The documentation for this class was generated from the following file: