PageRenderTime 35ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/plugins/vjCommentPlugin/lib/tools/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php

https://bitbucket.org/Kudlaty/360kdw
PHP | 135 lines | 89 code | 8 blank | 38 comment | 17 complexity | 739249b8ed7c1e1ff906931b13d477f6 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * This filter extracts <style> blocks from input HTML, cleans them up
  4. * using CSSTidy, and then places them in $purifier->context->get('StyleBlocks')
  5. * so they can be used elsewhere in the document.
  6. *
  7. * @note
  8. * See tests/HTMLPurifier/Filter/ExtractStyleBlocksTest.php for
  9. * sample usage.
  10. *
  11. * @note
  12. * This filter can also be used on stylesheets not included in the
  13. * document--something purists would probably prefer. Just directly
  14. * call HTMLPurifier_Filter_ExtractStyleBlocks->cleanCSS()
  15. */
  16. class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
  17. {
  18. public $name = 'ExtractStyleBlocks';
  19. private $_styleMatches = array();
  20. private $_tidy;
  21. public function __construct() {
  22. $this->_tidy = new csstidy();
  23. }
  24. /**
  25. * Save the contents of CSS blocks to style matches
  26. * @param $matches preg_replace style $matches array
  27. */
  28. protected function styleCallback($matches) {
  29. $this->_styleMatches[] = $matches[1];
  30. }
  31. /**
  32. * Removes inline <style> tags from HTML, saves them for later use
  33. * @todo Extend to indicate non-text/css style blocks
  34. */
  35. public function preFilter($html, $config, $context) {
  36. $tidy = $config->get('Filter.ExtractStyleBlocks.TidyImpl');
  37. if ($tidy !== null) $this->_tidy = $tidy;
  38. $html = preg_replace_callback('#<style(?:\s.*)?>(.+)</style>#isU', array($this, 'styleCallback'), $html);
  39. $style_blocks = $this->_styleMatches;
  40. $this->_styleMatches = array(); // reset
  41. $context->register('StyleBlocks', $style_blocks); // $context must not be reused
  42. if ($this->_tidy) {
  43. foreach ($style_blocks as &$style) {
  44. $style = $this->cleanCSS($style, $config, $context);
  45. }
  46. }
  47. return $html;
  48. }
  49. /**
  50. * Takes CSS (the stuff found in <style>) and cleans it.
  51. * @warning Requires CSSTidy <http://csstidy.sourceforge.net/>
  52. * @param $css CSS styling to clean
  53. * @param $config Instance of HTMLPurifier_Config
  54. * @param $context Instance of HTMLPurifier_Context
  55. * @return Cleaned CSS
  56. */
  57. public function cleanCSS($css, $config, $context) {
  58. // prepare scope
  59. $scope = $config->get('Filter.ExtractStyleBlocks.Scope');
  60. if ($scope !== null) {
  61. $scopes = array_map('trim', explode(',', $scope));
  62. } else {
  63. $scopes = array();
  64. }
  65. // remove comments from CSS
  66. $css = trim($css);
  67. if (strncmp('<!--', $css, 4) === 0) {
  68. $css = substr($css, 4);
  69. }
  70. if (strlen($css) > 3 && substr($css, -3) == '-->') {
  71. $css = substr($css, 0, -3);
  72. }
  73. $css = trim($css);
  74. $this->_tidy->parse($css);
  75. $css_definition = $config->getDefinition('CSS');
  76. foreach ($this->_tidy->css as $k => $decls) {
  77. // $decls are all CSS declarations inside an @ selector
  78. $new_decls = array();
  79. foreach ($decls as $selector => $style) {
  80. $selector = trim($selector);
  81. if ($selector === '') continue; // should not happen
  82. if ($selector[0] === '+') {
  83. if ($selector !== '' && $selector[0] === '+') continue;
  84. }
  85. if (!empty($scopes)) {
  86. $new_selector = array(); // because multiple ones are possible
  87. $selectors = array_map('trim', explode(',', $selector));
  88. foreach ($scopes as $s1) {
  89. foreach ($selectors as $s2) {
  90. $new_selector[] = "$s1 $s2";
  91. }
  92. }
  93. $selector = implode(', ', $new_selector); // now it's a string
  94. }
  95. foreach ($style as $name => $value) {
  96. if (!isset($css_definition->info[$name])) {
  97. unset($style[$name]);
  98. continue;
  99. }
  100. $def = $css_definition->info[$name];
  101. $ret = $def->validate($value, $config, $context);
  102. if ($ret === false) unset($style[$name]);
  103. else $style[$name] = $ret;
  104. }
  105. $new_decls[$selector] = $style;
  106. }
  107. $this->_tidy->css[$k] = $new_decls;
  108. }
  109. // remove stuff that shouldn't be used, could be reenabled
  110. // after security risks are analyzed
  111. $this->_tidy->import = array();
  112. $this->_tidy->charset = null;
  113. $this->_tidy->namespace = null;
  114. $css = $this->_tidy->print->plain();
  115. // we are going to escape any special characters <>& to ensure
  116. // that no funny business occurs (i.e. </style> in a font-family prop).
  117. if ($config->get('Filter.ExtractStyleBlocks.Escaping')) {
  118. $css = str_replace(
  119. array('<', '>', '&'),
  120. array('\3C ', '\3E ', '\26 '),
  121. $css
  122. );
  123. }
  124. return $css;
  125. }
  126. }
  127. // vim: et sw=4 sts=4