HTMLPurifier/HTMLDefinition.php Quellcode

HTMLDefinition.php
gehe zur Dokumentation dieser Datei
1 <?php
2 
27 {
28 
29  // FULLY-PUBLIC VARIABLES ---------------------------------------------
30 
35  public $info = array();
36 
41  public $info_global_attr = array();
42 
47  public $info_parent = 'div';
48 
55 
61  public $info_block_wrapper = 'p';
62 
67  public $info_tag_transform = array();
68 
73  public $info_attr_transform_pre = array();
74 
79  public $info_attr_transform_post = array();
80 
86  public $info_content_sets = array();
87 
92  public $info_injector = array();
93 
98  public $doctype;
99 
100 
101 
102  // RAW CUSTOMIZATION STUFF --------------------------------------------
103 
113  public function addAttribute($element_name, $attr_name, $def)
114  {
115  $module = $this->getAnonymousModule();
116  if (!isset($module->info[$element_name])) {
117  $element = $module->addBlankElement($element_name);
118  } else {
119  $element = $module->info[$element_name];
120  }
121  $element->attr[$attr_name] = $def;
122  }
123 
129  public function addElement($element_name, $type, $contents, $attr_collections, $attributes = array())
130  {
131  $module = $this->getAnonymousModule();
132  // assume that if the user is calling this, the element
133  // is safe. This may not be a good idea
134  $element = $module->addElement($element_name, $type, $contents, $attr_collections, $attributes);
135  return $element;
136  }
137 
146  public function addBlankElement($element_name)
147  {
148  $module = $this->getAnonymousModule();
149  $element = $module->addBlankElement($element_name);
150  return $element;
151  }
152 
159  public function getAnonymousModule()
160  {
161  if (!$this->_anonModule) {
162  $this->_anonModule = new HTMLPurifier_HTMLModule();
163  $this->_anonModule->name = 'Anonymous';
164  }
165  return $this->_anonModule;
166  }
167 
168  private $_anonModule = null;
169 
170  // PUBLIC BUT INTERNAL VARIABLES --------------------------------------
171 
175  public $type = 'HTML';
176 
180  public $manager;
181 
185  public function __construct()
186  {
187  $this->manager = new HTMLPurifier_HTMLModuleManager();
188  }
189 
193  protected function doSetup($config)
194  {
195  $this->processModules($config);
196  $this->setupConfigStuff($config);
197  unset($this->manager);
198 
199  // cleanup some of the element definitions
200  foreach ($this->info as $k => $v) {
201  unset($this->info[$k]->content_model);
202  unset($this->info[$k]->content_model_type);
203  }
204  }
205 
210  protected function processModules($config)
211  {
212  if ($this->_anonModule) {
213  // for user specific changes
214  // this is late-loaded so we don't have to deal with PHP4
215  // reference wonky-ness
216  $this->manager->addModule($this->_anonModule);
217  unset($this->_anonModule);
218  }
219 
220  $this->manager->setup($config);
221  $this->doctype = $this->manager->doctype;
222 
223  foreach ($this->manager->modules as $module) {
224  foreach ($module->info_tag_transform as $k => $v) {
225  if ($v === false) {
226  unset($this->info_tag_transform[$k]);
227  } else {
228  $this->info_tag_transform[$k] = $v;
229  }
230  }
231  foreach ($module->info_attr_transform_pre as $k => $v) {
232  if ($v === false) {
233  unset($this->info_attr_transform_pre[$k]);
234  } else {
235  $this->info_attr_transform_pre[$k] = $v;
236  }
237  }
238  foreach ($module->info_attr_transform_post as $k => $v) {
239  if ($v === false) {
240  unset($this->info_attr_transform_post[$k]);
241  } else {
242  $this->info_attr_transform_post[$k] = $v;
243  }
244  }
245  foreach ($module->info_injector as $k => $v) {
246  if ($v === false) {
247  unset($this->info_injector[$k]);
248  } else {
249  $this->info_injector[$k] = $v;
250  }
251  }
252  }
253  $this->info = $this->manager->getElements();
254  $this->info_content_sets = $this->manager->contentSets->lookup;
255  }
256 
261  protected function setupConfigStuff($config)
262  {
263  $block_wrapper = $config->get('HTML.BlockWrapper');
264  if (isset($this->info_content_sets['Block'][$block_wrapper])) {
265  $this->info_block_wrapper = $block_wrapper;
266  } else {
267  trigger_error(
268  'Cannot use non-block element as block wrapper',
269  E_USER_ERROR
270  );
271  }
272 
273  $parent = $config->get('HTML.Parent');
274  $def = $this->manager->getElement($parent, true);
275  if ($def) {
276  $this->info_parent = $parent;
277  $this->info_parent_def = $def;
278  } else {
279  trigger_error(
280  'Cannot use unrecognized element as parent',
281  E_USER_ERROR
282  );
283  $this->info_parent_def = $this->manager->getElement($this->info_parent, true);
284  }
285 
286  // support template text
287  $support = "(for information on implementing this, see the support forums) ";
288 
289  // setup allowed elements -----------------------------------------
290 
291  $allowed_elements = $config->get('HTML.AllowedElements');
292  $allowed_attributes = $config->get('HTML.AllowedAttributes'); // retrieve early
293 
294  if (!is_array($allowed_elements) && !is_array($allowed_attributes)) {
295  $allowed = $config->get('HTML.Allowed');
296  if (is_string($allowed)) {
297  list($allowed_elements, $allowed_attributes) = $this->parseTinyMCEAllowedList($allowed);
298  }
299  }
300 
301  if (is_array($allowed_elements)) {
302  foreach ($this->info as $name => $d) {
303  if (!isset($allowed_elements[$name])) {
304  unset($this->info[$name]);
305  }
306  unset($allowed_elements[$name]);
307  }
308  // emit errors
309  foreach ($allowed_elements as $element => $d) {
310  $element = htmlspecialchars($element); // PHP doesn't escape errors, be careful!
311  trigger_error("Element '$element' is not supported $support", E_USER_WARNING);
312  }
313  }
314 
315  // setup allowed attributes ---------------------------------------
316 
317  $allowed_attributes_mutable = $allowed_attributes; // by copy!
318  if (is_array($allowed_attributes)) {
319  // This actually doesn't do anything, since we went away from
320  // global attributes. It's possible that userland code uses
321  // it, but HTMLModuleManager doesn't!
322  foreach ($this->info_global_attr as $attr => $x) {
323  $keys = array($attr, "*@$attr", "*.$attr");
324  $delete = true;
325  foreach ($keys as $key) {
326  if ($delete && isset($allowed_attributes[$key])) {
327  $delete = false;
328  }
329  if (isset($allowed_attributes_mutable[$key])) {
330  unset($allowed_attributes_mutable[$key]);
331  }
332  }
333  if ($delete) {
334  unset($this->info_global_attr[$attr]);
335  }
336  }
337 
338  foreach ($this->info as $tag => $info) {
339  foreach ($info->attr as $attr => $x) {
340  $keys = array("$tag@$attr", $attr, "*@$attr", "$tag.$attr", "*.$attr");
341  $delete = true;
342  foreach ($keys as $key) {
343  if ($delete && isset($allowed_attributes[$key])) {
344  $delete = false;
345  }
346  if (isset($allowed_attributes_mutable[$key])) {
347  unset($allowed_attributes_mutable[$key]);
348  }
349  }
350  if ($delete) {
351  if ($this->info[$tag]->attr[$attr]->required) {
352  trigger_error(
353  "Required attribute '$attr' in element '$tag' " .
354  "was not allowed, which means '$tag' will not be allowed either",
355  E_USER_WARNING
356  );
357  }
358  unset($this->info[$tag]->attr[$attr]);
359  }
360  }
361  }
362  // emit errors
363  foreach ($allowed_attributes_mutable as $elattr => $d) {
364  $bits = preg_split('/[.@]/', $elattr, 2);
365  $c = count($bits);
366  switch ($c) {
367  case 2:
368  if ($bits[0] !== '*') {
369  $element = htmlspecialchars($bits[0]);
370  $attribute = htmlspecialchars($bits[1]);
371  if (!isset($this->info[$element])) {
372  trigger_error(
373  "Cannot allow attribute '$attribute' if element " .
374  "'$element' is not allowed/supported $support"
375  );
376  } else {
377  trigger_error(
378  "Attribute '$attribute' in element '$element' not supported $support",
379  E_USER_WARNING
380  );
381  }
382  break;
383  }
384  // otherwise fall through
385  case 1:
386  $attribute = htmlspecialchars($bits[0]);
387  trigger_error(
388  "Global attribute '$attribute' is not ".
389  "supported in any elements $support",
390  E_USER_WARNING
391  );
392  break;
393  }
394  }
395  }
396 
397  // setup forbidden elements ---------------------------------------
398 
399  $forbidden_elements = $config->get('HTML.ForbiddenElements');
400  $forbidden_attributes = $config->get('HTML.ForbiddenAttributes');
401 
402  foreach ($this->info as $tag => $info) {
403  if (isset($forbidden_elements[$tag])) {
404  unset($this->info[$tag]);
405  continue;
406  }
407  foreach ($info->attr as $attr => $x) {
408  if (isset($forbidden_attributes["$tag@$attr"]) ||
409  isset($forbidden_attributes["*@$attr"]) ||
410  isset($forbidden_attributes[$attr])
411  ) {
412  unset($this->info[$tag]->attr[$attr]);
413  continue;
414  } elseif (isset($forbidden_attributes["$tag.$attr"])) { // this segment might get removed eventually
415  // $tag.$attr are not user supplied, so no worries!
416  trigger_error(
417  "Error with $tag.$attr: tag.attr syntax not supported for " .
418  "HTML.ForbiddenAttributes; use tag@attr instead",
419  E_USER_WARNING
420  );
421  }
422  }
423  }
424  foreach ($forbidden_attributes as $key => $v) {
425  if (strlen($key) < 2) {
426  continue;
427  }
428  if ($key[0] != '*') {
429  continue;
430  }
431  if ($key[1] == '.') {
432  trigger_error(
433  "Error with $key: *.attr syntax not supported for HTML.ForbiddenAttributes; use attr instead",
434  E_USER_WARNING
435  );
436  }
437  }
438 
439  // setup injectors -----------------------------------------------------
440  foreach ($this->info_injector as $i => $injector) {
441  if ($injector->checkNeeded($config) !== false) {
442  // remove injector that does not have it's required
443  // elements/attributes present, and is thus not needed.
444  unset($this->info_injector[$i]);
445  }
446  }
447  }
448 
458  public function parseTinyMCEAllowedList($list)
459  {
460  $list = str_replace(array(' ', "\t"), '', $list);
461 
462  $elements = array();
463  $attributes = array();
464 
465  $chunks = preg_split('/(,|[\n\r]+)/', $list);
466  foreach ($chunks as $chunk) {
467  if (empty($chunk)) {
468  continue;
469  }
470  // remove TinyMCE element control characters
471  if (!strpos($chunk, '[')) {
472  $element = $chunk;
473  $attr = false;
474  } else {
475  list($element, $attr) = explode('[', $chunk);
476  }
477  if ($element !== '*') {
478  $elements[$element] = true;
479  }
480  if (!$attr) {
481  continue;
482  }
483  $attr = substr($attr, 0, strlen($attr) - 1); // remove trailing ]
484  $attr = explode('|', $attr);
485  foreach ($attr as $key) {
486  $attributes["$element.$key"] = true;
487  }
488  }
489  return array($elements, $attributes);
490  }
491 }
492 
493 // vim: et sw=4 sts=4




Korrekturen, Hinweise und Ergänzungen

Bitte scheuen Sie sich nicht und melden Sie, was auf dieser Seite sachlich falsch oder irreführend ist, was ergänzt werden sollte, was fehlt usw. Dazu bitte oben aus dem Menü Seite den Eintrag Support Forum wählen. Es ist eine kostenlose Anmeldung erforderlich, um Anmerkungen zu posten. Unpassende Postings, Spam usw. werden kommentarlos entfernt.