XpressEngine Core  1.11.2
 All Classes Namespaces Files Functions Variables Pages
Purifier.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) NAVER <http://www.navercorp.com> */
3 
4 class Purifier
5 {
6 
7  private $_cacheDir;
8  private $_htmlPurifier;
9  private $_config;
10  private $_def;
11 
12  public function __construct()
13  {
14  $this->_checkCacheDir();
15 
16  // purifier setting
17  require_once _XE_PATH_ . 'classes/security/htmlpurifier/library/HTMLPurifier.auto.php';
18  require_once 'HTMLPurifier.func.php';
19 
20  $this->_setConfig();
21  }
22 
23  public function getInstance()
24  {
25  if(!isset($GLOBALS['__PURIFIER_INSTANCE__']))
26  {
27  $GLOBALS['__PURIFIER_INSTANCE__'] = new Purifier();
28  }
29  return $GLOBALS['__PURIFIER_INSTANCE__'];
30  }
31 
32  private function _setConfig()
33  {
34  $whiteDomainRegex = $this->_getWhiteDomainRegx();
35  //$allowdClasses = array('emoticon');
36 
37  $this->_config = HTMLPurifier_Config::createDefault();
38  $this->_config->autoFinalize = false;
39  $this->_config->set('HTML.TidyLevel', 'light');
40  $this->_config->set('Output.FlashCompat', TRUE);
41  $this->_config->set('HTML.SafeObject', TRUE);
42  $this->_config->set('HTML.SafeEmbed', TRUE);
43  $this->_config->set('HTML.SafeIframe', TRUE);
44  $this->_config->set('URI.SafeIframeRegexp', $whiteDomainRegex);
45  $this->_config->set('Cache.SerializerPath', $this->_cacheDir);
46  $this->_config->set('Attr.AllowedFrameTargets', array('_blank'));
47 
48  // @see https://github.com/xpressengine/xe-core/issues/2138
49  $this->_config->set('Attr.IDPrefix', 'user_content_');
50 
51  $this->_def = $this->_config->getHTMLDefinition(TRUE);
52  $this->_def->addAttribute('iframe', 'allowfullscreen', 'Text');
53  }
54 
55  public function setConfig($name, $value)
56  {
57  if($this->_config->isFinalized()) return;
58 
59  $this->_config->set($name, $value);
60  }
61 
62  private function _setDefinition(&$content)
63  {
64  // add attribute for edit component
65  $editComponentAttrs = $this->_searchEditComponent($content);
66  if(is_array($editComponentAttrs))
67  {
68  foreach($editComponentAttrs AS $k => $v)
69  {
70  $this->_def->addAttribute('img', $v, 'CDATA');
71  $this->_def->addAttribute('div', $v, 'CDATA');
72  }
73  }
74 
75  // add attribute for widget component
76  $widgetAttrs = $this->_searchWidget($content);
77  if(is_array($widgetAttrs))
78  {
79  foreach($widgetAttrs AS $k => $v)
80  {
81  $this->_def->addAttribute('img', $v, 'CDATA');
82  }
83  }
84  }
85 
91  private function _searchEditComponent($content)
92  {
93  preg_match_all('!<(?:(div)|img)([^>]*)editor_component=([^>]*)>(?(1)(.*?)</div>)!is', $content, $m);
94 
95  $attributeList = array();
96  if(is_array($m[2]))
97  {
98  foreach($m[2] as $key => $value)
99  {
100  unset($script, $m2);
101  $script = " {$m[2][$key]} editor_component={$m[3][$key]}";
102 
103  if(preg_match_all('/([a-z0-9_-]+)="([^"]+)"/is', $script, $m2))
104  {
105  foreach($m2[1] as $value2)
106  {
107  //SECISSUE check style attr
108  if($value2 == 'style')
109  {
110  continue;
111  }
112  $attributeList[] = $value2;
113  }
114  }
115  }
116  }
117 
118  return array_unique($attributeList);
119  }
120 
126  private function _searchWidget(&$content)
127  {
128  preg_match_all('!<(?:(div)|img)([^>]*)class="zbxe_widget_output"([^>]*)>(?(1)(.*?)</div>)!is', $content, $m);
129 
130  $attributeList = array();
131  if(is_array($m[3]))
132  {
133  $content = str_replace('<img class="zbxe_widget_output"', '<img src="" class="zbxe_widget_output"', $content);
134 
135  foreach($m[3] as $key => $value)
136  {
137  if (preg_match_all('/([a-z0-9_-]+)="([^"]+)"/is', $m[3][$key], $m2))
138  {
139  foreach($m2[1] as $value2)
140  {
141  //SECISSUE check style attr
142  if($value2 == 'style')
143  {
144  continue;
145  }
146  $attributeList[] = $value2;
147  }
148  }
149  }
150  }
151  return array_unique($attributeList);
152  }
153 
154  private function _getWhiteDomainRegx()
155  {
156  $oEmbedFilter = EmbedFilter::getInstance();
157  $whiteIframeUrlList = $oEmbedFilter->getWhiteIframeUrlList();
158 
159  $whiteDomain = array();
160  foreach($whiteIframeUrlList as $value)
161  {
162  $whiteDomain[] = preg_quote($value, '%');
163  }
164 
165  $whiteDomainRegex = '%^(' . implode('|', $whiteDomain) . ')%';
166 
167  return $whiteDomainRegex;
168  }
169 
170  private function _checkCacheDir()
171  {
172  // check htmlpurifier cache directory
173  $this->_cacheDir = _XE_PATH_ . 'files/cache/htmlpurifier';
174  FileHandler::makeDir($this->_cacheDir);
175  }
176 
177  public function purify(&$content)
178  {
179  $this->_setDefinition($content);
180  $this->_htmlPurifier = new HTMLPurifier($this->_config);
181 
182  $content = $this->_htmlPurifier->purify($content);
183  }
184 
185 }
186 /* End of file : Purifier.class.php */
187 /* Location: ./classes/security/Purifier.class.php */
if(file_exists(_XE_PATH_. 'config/config.user.inc.php')) if(!defined('__DEBUG__')) if(!defined('__DEBUG_OUTPUT__')) if(!defined('__DEBUG_PROTECT__')) if(!defined('__DEBUG_PROTECT_IP__')) if(!defined('__DEBUG_DB_OUTPUT__')) if(!defined('__LOG_SLOW_QUERY__')) if(!defined('__LOG_SLOW_TRIGGER__')) if(!defined('__LOG_SLOW_ADDON__')) if(!defined('__LOG_SLOW_WIDGET__')) if(!defined('__DEBUG_QUERY__')) if(!defined('__OB_GZHANDLER_ENABLE__')) if(!defined('__ENABLE_PHPUNIT_TEST__')) if(!defined('__PROXY_SERVER__')) if(!defined('__ERROR_LOG__')) if(!defined('__DISABLE_DEFAULT_CSS__')) if(!defined('__AUTO_OPCACHE_INVALIDATE__')) if((__DEBUG_OUTPUT__==2)&&version_compare(PHP_VERSION, '6.0.0')===-1) if(version_compare(PHP_VERSION, '5.3.0') >=0) $GLOBALS['__xe_autoload_file_map']
Definition: config.inc.php:324
setConfig($name, $value)
makeDir($path_string)
const _XE_PATH_
Definition: config.inc.php:49
purify(&$content)