RemoveEmpty.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. <?php
  2. class HTMLPurifier_Injector_RemoveEmpty extends HTMLPurifier_Injector
  3. {
  4. /**
  5. * @type HTMLPurifier_Context
  6. */
  7. private $context;
  8. /**
  9. * @type HTMLPurifier_Config
  10. */
  11. private $config;
  12. /**
  13. * @type HTMLPurifier_AttrValidator
  14. */
  15. private $attrValidator;
  16. /**
  17. * @type bool
  18. */
  19. private $removeNbsp;
  20. /**
  21. * @type bool
  22. */
  23. private $removeNbspExceptions;
  24. /**
  25. * Cached contents of %AutoFormat.RemoveEmpty.Predicate
  26. * @type array
  27. */
  28. private $exclude;
  29. /**
  30. * @param HTMLPurifier_Config $config
  31. * @param HTMLPurifier_Context $context
  32. * @return void
  33. */
  34. public function prepare($config, $context)
  35. {
  36. parent::prepare($config, $context);
  37. $this->config = $config;
  38. $this->context = $context;
  39. $this->removeNbsp = $config->get('AutoFormat.RemoveEmpty.RemoveNbsp');
  40. $this->removeNbspExceptions = $config->get('AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions');
  41. $this->exclude = $config->get('AutoFormat.RemoveEmpty.Predicate');
  42. foreach ($this->exclude as $key => $attrs) {
  43. if (!is_array($attrs)) {
  44. // HACK, see HTMLPurifier/Printer/ConfigForm.php
  45. $this->exclude[$key] = explode(';', $attrs);
  46. }
  47. }
  48. $this->attrValidator = new HTMLPurifier_AttrValidator();
  49. }
  50. /**
  51. * @param HTMLPurifier_Token $token
  52. */
  53. public function handleElement(&$token)
  54. {
  55. if (!$token instanceof HTMLPurifier_Token_Start) {
  56. return;
  57. }
  58. $next = false;
  59. $deleted = 1; // the current tag
  60. for ($i = count($this->inputZipper->back) - 1; $i >= 0; $i--, $deleted++) {
  61. $next = $this->inputZipper->back[$i];
  62. if ($next instanceof HTMLPurifier_Token_Text) {
  63. if ($next->is_whitespace) {
  64. continue;
  65. }
  66. if ($this->removeNbsp && !isset($this->removeNbspExceptions[$token->name])) {
  67. $plain = str_replace("\xC2\xA0", "", $next->data);
  68. $isWsOrNbsp = $plain === '' || ctype_space($plain);
  69. if ($isWsOrNbsp) {
  70. continue;
  71. }
  72. }
  73. }
  74. break;
  75. }
  76. if (!$next || ($next instanceof HTMLPurifier_Token_End && $next->name == $token->name)) {
  77. $this->attrValidator->validateToken($token, $this->config, $this->context);
  78. $token->armor['ValidateAttributes'] = true;
  79. if (isset($this->exclude[$token->name])) {
  80. $r = true;
  81. foreach ($this->exclude[$token->name] as $elem) {
  82. if (!isset($token->attr[$elem])) $r = false;
  83. }
  84. if ($r) return;
  85. }
  86. if (isset($token->attr['id']) || isset($token->attr['name'])) {
  87. return;
  88. }
  89. $token = $deleted + 1;
  90. for ($b = 0, $c = count($this->inputZipper->front); $b < $c; $b++) {
  91. $prev = $this->inputZipper->front[$b];
  92. if ($prev instanceof HTMLPurifier_Token_Text && $prev->is_whitespace) {
  93. continue;
  94. }
  95. break;
  96. }
  97. // This is safe because we removed the token that triggered this.
  98. $this->rewindOffset($b+$deleted);
  99. return;
  100. }
  101. }
  102. }
  103. // vim: et sw=4 sts=4