PageRenderTime 95ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 1ms

/system/guard/HTMLPurifier.php

https://github.com/daqing/aeolus
PHP | 7165 lines | 7140 code | 11 blank | 14 comment | 1389 complexity | b19b343e79634ba3a38a8d8cb07b31a0 MD5 | raw file
Possible License(s): BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. class HTMLPurifier
  3. {
  4. public $version = '3.1.0';
  5. const VERSION = '3.1.0';
  6. public $config;
  7. private $filters = array();
  8. private static $instance;
  9. protected $strategy, $generator;
  10. public $context;
  11. public function __construct($config = null) {
  12. $this->config = HTMLPurifier_Config::create($config);
  13. $this->strategy = new HTMLPurifier_Strategy_Core();
  14. }
  15. public function addFilter($filter) {
  16. trigger_error('HTMLPurifier->addFilter() is deprecated, use configuration directives in the Filter namespace or Filter.Custom', E_USER_WARNING);
  17. $this->filters[] = $filter;
  18. }
  19. public function purify($html, $config = null) {
  20. $config = $config ? HTMLPurifier_Config::create($config) : $this->config;
  21. $lexer = HTMLPurifier_Lexer::create($config);
  22. $context = new HTMLPurifier_Context();
  23. $this->generator = new HTMLPurifier_Generator($config, $context);
  24. $context->register('Generator', $this->generator);
  25. if ($config->get('Core', 'CollectErrors')) {
  26. $language_factory = HTMLPurifier_LanguageFactory::instance();
  27. $language = $language_factory->create($config, $context);
  28. $context->register('Locale', $language);
  29. $error_collector = new HTMLPurifier_ErrorCollector($context);
  30. $context->register('ErrorCollector', $error_collector);
  31. }
  32. $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context);
  33. $context->register('IDAccumulator', $id_accumulator);
  34. $html = HTMLPurifier_Encoder::convertToUTF8($html, $config, $context);
  35. $filter_flags = $config->getBatch('Filter');
  36. $custom_filters = $filter_flags['Custom'];
  37. unset($filter_flags['Custom']);
  38. $filters = array();
  39. foreach ($filter_flags as $filter => $flag) {
  40. if (!$flag) continue;
  41. $class = "HTMLPurifier_Filter_$filter";
  42. $filters[] = new $class;
  43. }
  44. foreach ($custom_filters as $filter) {
  45. $filters[] = $filter;
  46. }
  47. $filters = array_merge($filters, $this->filters);
  48. for ($i = 0, $filter_size = count($filters); $i < $filter_size; $i++) {
  49. $html = $filters[$i]->preFilter($html, $config, $context);
  50. }
  51. $html =
  52. $this->generator->generateFromTokens(
  53. $this->strategy->execute(
  54. $lexer->tokenizeHTML(
  55. $html, $config, $context
  56. ),
  57. $config, $context
  58. )
  59. );
  60. for ($i = $filter_size - 1; $i >= 0; $i--) {
  61. $html = $filters[$i]->postFilter($html, $config, $context);
  62. }
  63. $html = HTMLPurifier_Encoder::convertFromUTF8($html, $config, $context);
  64. $this->context =& $context;
  65. return $html;
  66. }
  67. public function purifyArray($array_of_html, $config = null) {
  68. $context_array = array();
  69. foreach ($array_of_html as $key => $html) {
  70. $array_of_html[$key] = $this->purify($html, $config);
  71. $context_array[$key] = $this->context;
  72. }
  73. $this->context = $context_array;
  74. return $array_of_html;
  75. }
  76. public static function instance($prototype = null) {
  77. if (!self::$instance || $prototype) {
  78. if ($prototype instanceof HTMLPurifier) {
  79. self::$instance = $prototype;
  80. } elseif ($prototype) {
  81. self::$instance = new HTMLPurifier($prototype);
  82. } else {
  83. self::$instance = new HTMLPurifier();
  84. }
  85. }
  86. return self::$instance;
  87. }
  88. public static function getInstance($prototype = null) {
  89. return HTMLPurifier::instance($prototype);
  90. }
  91. }
  92. class HTMLPurifier_AttrCollections
  93. {
  94. public $info = array();
  95. public function __construct($attr_types, $modules) {
  96. foreach ($modules as $module) {
  97. foreach ($module->attr_collections as $coll_i => $coll) {
  98. if (!isset($this->info[$coll_i])) {
  99. $this->info[$coll_i] = array();
  100. }
  101. foreach ($coll as $attr_i => $attr) {
  102. if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) {
  103. $this->info[$coll_i][$attr_i] = array_merge(
  104. $this->info[$coll_i][$attr_i], $attr);
  105. continue;
  106. }
  107. $this->info[$coll_i][$attr_i] = $attr;
  108. }
  109. }
  110. }
  111. foreach ($this->info as $name => $attr) {
  112. $this->performInclusions($this->info[$name]);
  113. $this->expandIdentifiers($this->info[$name], $attr_types);
  114. }
  115. }
  116. public function performInclusions(&$attr) {
  117. if (!isset($attr[0])) return;
  118. $merge = $attr[0];
  119. $seen = array();
  120. for ($i = 0; isset($merge[$i]); $i++) {
  121. if (isset($seen[$merge[$i]])) continue;
  122. $seen[$merge[$i]] = true;
  123. if (!isset($this->info[$merge[$i]])) continue;
  124. foreach ($this->info[$merge[$i]] as $key => $value) {
  125. if (isset($attr[$key])) continue;
  126. $attr[$key] = $value;
  127. }
  128. if (isset($this->info[$merge[$i]][0])) {
  129. $merge = array_merge($merge, $this->info[$merge[$i]][0]);
  130. }
  131. }
  132. unset($attr[0]);
  133. }
  134. public function expandIdentifiers(&$attr, $attr_types) {
  135. $processed = array();
  136. foreach ($attr as $def_i => $def) {
  137. if ($def_i === 0) continue;
  138. if (isset($processed[$def_i])) continue;
  139. if ($required = (strpos($def_i, '*') !== false)) {
  140. unset($attr[$def_i]);
  141. $def_i = trim($def_i, '*');
  142. $attr[$def_i] = $def;
  143. }
  144. $processed[$def_i] = true;
  145. if (is_object($def)) {
  146. $attr[$def_i]->required = ($required || $attr[$def_i]->required);
  147. continue;
  148. }
  149. if ($def === false) {
  150. unset($attr[$def_i]);
  151. continue;
  152. }
  153. if ($t = $attr_types->get($def)) {
  154. $attr[$def_i] = $t;
  155. $attr[$def_i]->required = $required;
  156. } else {
  157. unset($attr[$def_i]);
  158. }
  159. }
  160. }
  161. }
  162. abstract class HTMLPurifier_AttrDef
  163. {
  164. public $minimized = false;
  165. public $required = false;
  166. abstract public function validate($string, $config, $context);
  167. public function parseCDATA($string) {
  168. $string = trim($string);
  169. $string = str_replace("\n", '', $string);
  170. $string = str_replace(array("\r", "\t"), ' ', $string);
  171. return $string;
  172. }
  173. public function make($string) {
  174. return $this;
  175. }
  176. protected function mungeRgb($string) {
  177. return preg_replace('/rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\)/', 'rgb(\1,\2,\3)', $string);
  178. }
  179. }
  180. abstract class HTMLPurifier_AttrTransform
  181. {
  182. abstract public function transform($attr, $config, $context);
  183. public function prependCSS(&$attr, $css) {
  184. $attr['style'] = isset($attr['style']) ? $attr['style'] : '';
  185. $attr['style'] = $css . $attr['style'];
  186. }
  187. public function confiscateAttr(&$attr, $key) {
  188. if (!isset($attr[$key])) return null;
  189. $value = $attr[$key];
  190. unset($attr[$key]);
  191. return $value;
  192. }
  193. }
  194. class HTMLPurifier_AttrTypes
  195. {
  196. protected $info = array();
  197. public function __construct() {
  198. $this->info['Enum'] = new HTMLPurifier_AttrDef_Enum();
  199. $this->info['Bool'] = new HTMLPurifier_AttrDef_HTML_Bool();
  200. $this->info['CDATA'] = new HTMLPurifier_AttrDef_Text();
  201. $this->info['ID'] = new HTMLPurifier_AttrDef_HTML_ID();
  202. $this->info['Length'] = new HTMLPurifier_AttrDef_HTML_Length();
  203. $this->info['MultiLength'] = new HTMLPurifier_AttrDef_HTML_MultiLength();
  204. $this->info['NMTOKENS'] = new HTMLPurifier_AttrDef_HTML_Nmtokens();
  205. $this->info['Pixels'] = new HTMLPurifier_AttrDef_HTML_Pixels();
  206. $this->info['Text'] = new HTMLPurifier_AttrDef_Text();
  207. $this->info['URI'] = new HTMLPurifier_AttrDef_URI();
  208. $this->info['LanguageCode'] = new HTMLPurifier_AttrDef_Lang();
  209. $this->info['Color'] = new HTMLPurifier_AttrDef_HTML_Color();
  210. $this->info['ContentType'] = new HTMLPurifier_AttrDef_Text();
  211. $this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true);
  212. }
  213. public function get($type) {
  214. if (strpos($type, '#') !== false) list($type, $string) = explode('#', $type, 2);
  215. else $string = '';
  216. if (!isset($this->info[$type])) {
  217. trigger_error('Cannot retrieve undefined attribute type ' . $type, E_USER_ERROR);
  218. return;
  219. }
  220. return $this->info[$type]->make($string);
  221. }
  222. public function set($type, $impl) {
  223. $this->info[$type] = $impl;
  224. }
  225. }
  226. class HTMLPurifier_AttrValidator
  227. {
  228. public function validateToken(&$token, &$config, $context) {
  229. $definition = $config->getHTMLDefinition();
  230. $e =& $context->get('ErrorCollector', true);
  231. $ok =& $context->get('IDAccumulator', true);
  232. if (!$ok) {
  233. $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context);
  234. $context->register('IDAccumulator', $id_accumulator);
  235. }
  236. $current_token =& $context->get('CurrentToken', true);
  237. if (!$current_token) $context->register('CurrentToken', $token);
  238. if (
  239. !$token instanceof HTMLPurifier_Token_Start &&
  240. !$token instanceof HTMLPurifier_Token_Empty
  241. ) return $token;
  242. $d_defs = $definition->info_global_attr;
  243. $attr =& $token->attr;
  244. foreach ($definition->info_attr_transform_pre as $transform) {
  245. $attr = $transform->transform($o = $attr, $config, $context);
  246. if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
  247. }
  248. foreach ($definition->info[$token->name]->attr_transform_pre as $transform) {
  249. $attr = $transform->transform($o = $attr, $config, $context);
  250. if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
  251. }
  252. $defs = $definition->info[$token->name]->attr;
  253. $attr_key = false;
  254. $context->register('CurrentAttr', $attr_key);
  255. foreach ($attr as $attr_key => $value) {
  256. if ( isset($defs[$attr_key]) ) {
  257. if ($defs[$attr_key] === false) {
  258. $result = false;
  259. } else {
  260. $result = $defs[$attr_key]->validate(
  261. $value, $config, $context
  262. );
  263. }
  264. } elseif ( isset($d_defs[$attr_key]) ) {
  265. $result = $d_defs[$attr_key]->validate(
  266. $value, $config, $context
  267. );
  268. } else {
  269. $result = false;
  270. }
  271. if ($result === false || $result === null) {
  272. if ($e) $e->send(E_ERROR, 'AttrValidator: Attribute removed');
  273. unset($attr[$attr_key]);
  274. } elseif (is_string($result)) {
  275. $attr[$attr_key] = $result;
  276. }
  277. }
  278. $context->destroy('CurrentAttr');
  279. foreach ($definition->info_attr_transform_post as $transform) {
  280. $attr = $transform->transform($o = $attr, $config, $context);
  281. if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
  282. }
  283. foreach ($definition->info[$token->name]->attr_transform_post as $transform) {
  284. $attr = $transform->transform($o = $attr, $config, $context);
  285. if ($e && ($attr != $o)) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
  286. }
  287. if (!$current_token) $context->destroy('CurrentToken');
  288. }
  289. }
  290. if (!defined('HTMLPURIFIER_PREFIX')) {
  291. define('HTMLPURIFIER_PREFIX', dirname(__FILE__));
  292. set_include_path(HTMLPURIFIER_PREFIX . PATH_SEPARATOR . get_include_path());
  293. }
  294. if (!defined('PHP_EOL')) {
  295. switch (strtoupper(substr(PHP_OS, 0, 3))) {
  296. case 'WIN':
  297. define('PHP_EOL', "\r\n");
  298. break;
  299. case 'DAR':
  300. define('PHP_EOL', "\r");
  301. break;
  302. default:
  303. define('PHP_EOL', "\n");
  304. }
  305. }
  306. class HTMLPurifier_Bootstrap
  307. {
  308. public static function autoload($class) {
  309. $file = HTMLPurifier_Bootstrap::getPath($class);
  310. if (!$file) return false;
  311. require HTMLPURIFIER_PREFIX . '/' . $file;
  312. return true;
  313. }
  314. public static function getPath($class) {
  315. if (strncmp('HTMLPurifier', $class, 12) !== 0) return false;
  316. if (strncmp('HTMLPurifier_Language_', $class, 22) === 0) {
  317. $code = str_replace('_', '-', substr($class, 22));
  318. $file = 'HTMLPurifier/Language/classes/' . $code . '.php';
  319. } else {
  320. $file = str_replace('_', '/', $class) . '.php';
  321. }
  322. if (!file_exists(HTMLPURIFIER_PREFIX . '/' . $file)) return false;
  323. return $file;
  324. }
  325. public static function registerAutoload() {
  326. $autoload = array('HTMLPurifier_Bootstrap', 'autoload');
  327. if ( ($funcs = spl_autoload_functions()) === false ) {
  328. spl_autoload_register($autoload);
  329. } elseif (function_exists('spl_autoload_unregister')) {
  330. $compat = version_compare(PHP_VERSION, '5.1.2', '<=') &&
  331. version_compare(PHP_VERSION, '5.1.0', '>=');
  332. foreach ($funcs as $func) {
  333. if (is_array($func)) {
  334. $reflector = new ReflectionMethod($func[0], $func[1]);
  335. if (!$reflector->isStatic()) {
  336. throw new Exception('
  337. HTML Purifier autoloader registrar is not compatible
  338. with non-static object methods due to PHP Bug #44144;
  339. Please do not use HTMLPurifier.autoload.php (or any
  340. file that includes this file); instead, place the code:
  341. spl_autoload_register(array(\'HTMLPurifier_Bootstrap\', \'autoload\'))
  342. after your own autoloaders.
  343. ');
  344. }
  345. if ($compat) $func = implode('::', $func);
  346. }
  347. spl_autoload_unregister($func);
  348. }
  349. spl_autoload_register($autoload);
  350. foreach ($funcs as $func) spl_autoload_register($func);
  351. }
  352. }
  353. }
  354. abstract class HTMLPurifier_Definition
  355. {
  356. public $setup = false;
  357. public $type;
  358. abstract protected function doSetup($config);
  359. public function setup($config) {
  360. if ($this->setup) return;
  361. $this->setup = true;
  362. $this->doSetup($config);
  363. }
  364. }
  365. class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
  366. {
  367. public $type = 'CSS';
  368. public $info = array();
  369. protected function doSetup($config) {
  370. $this->info['text-align'] = new HTMLPurifier_AttrDef_Enum(
  371. array('left', 'right', 'center', 'justify'), false);
  372. $border_style =
  373. $this->info['border-bottom-style'] =
  374. $this->info['border-right-style'] =
  375. $this->info['border-left-style'] =
  376. $this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum(
  377. array('none', 'hidden', 'dotted', 'dashed', 'solid', 'double',
  378. 'groove', 'ridge', 'inset', 'outset'), false);
  379. $this->info['border-style'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_style);
  380. $this->info['clear'] = new HTMLPurifier_AttrDef_Enum(
  381. array('none', 'left', 'right', 'both'), false);
  382. $this->info['float'] = new HTMLPurifier_AttrDef_Enum(
  383. array('none', 'left', 'right'), false);
  384. $this->info['font-style'] = new HTMLPurifier_AttrDef_Enum(
  385. array('normal', 'italic', 'oblique'), false);
  386. $this->info['font-variant'] = new HTMLPurifier_AttrDef_Enum(
  387. array('normal', 'small-caps'), false);
  388. $uri_or_none = new HTMLPurifier_AttrDef_CSS_Composite(
  389. array(
  390. new HTMLPurifier_AttrDef_Enum(array('none')),
  391. new HTMLPurifier_AttrDef_CSS_URI()
  392. )
  393. );
  394. $this->info['list-style-position'] = new HTMLPurifier_AttrDef_Enum(
  395. array('inside', 'outside'), false);
  396. $this->info['list-style-type'] = new HTMLPurifier_AttrDef_Enum(
  397. array('disc', 'circle', 'square', 'decimal', 'lower-roman',
  398. 'upper-roman', 'lower-alpha', 'upper-alpha', 'none'), false);
  399. $this->info['list-style-image'] = $uri_or_none;
  400. $this->info['list-style'] = new HTMLPurifier_AttrDef_CSS_ListStyle($config);
  401. $this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum(
  402. array('capitalize', 'uppercase', 'lowercase', 'none'), false);
  403. $this->info['color'] = new HTMLPurifier_AttrDef_CSS_Color();
  404. $this->info['background-image'] = $uri_or_none;
  405. $this->info['background-repeat'] = new HTMLPurifier_AttrDef_Enum(
  406. array('repeat', 'repeat-x', 'repeat-y', 'no-repeat')
  407. );
  408. $this->info['background-attachment'] = new HTMLPurifier_AttrDef_Enum(
  409. array('scroll', 'fixed')
  410. );
  411. $this->info['background-position'] = new HTMLPurifier_AttrDef_CSS_BackgroundPosition();
  412. $border_color =
  413. $this->info['border-top-color'] =
  414. $this->info['border-bottom-color'] =
  415. $this->info['border-left-color'] =
  416. $this->info['border-right-color'] =
  417. $this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
  418. new HTMLPurifier_AttrDef_Enum(array('transparent')),
  419. new HTMLPurifier_AttrDef_CSS_Color()
  420. ));
  421. $this->info['background'] = new HTMLPurifier_AttrDef_CSS_Background($config);
  422. $this->info['border-color'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_color);
  423. $border_width =
  424. $this->info['border-top-width'] =
  425. $this->info['border-bottom-width'] =
  426. $this->info['border-left-width'] =
  427. $this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
  428. new HTMLPurifier_AttrDef_Enum(array('thin', 'medium', 'thick')),
  429. new HTMLPurifier_AttrDef_CSS_Length(true)
  430. ));
  431. $this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width);
  432. $this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
  433. new HTMLPurifier_AttrDef_Enum(array('normal')),
  434. new HTMLPurifier_AttrDef_CSS_Length()
  435. ));
  436. $this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
  437. new HTMLPurifier_AttrDef_Enum(array('normal')),
  438. new HTMLPurifier_AttrDef_CSS_Length()
  439. ));
  440. $this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
  441. new HTMLPurifier_AttrDef_Enum(array('xx-small', 'x-small',
  442. 'small', 'medium', 'large', 'x-large', 'xx-large',
  443. 'larger', 'smaller')),
  444. new HTMLPurifier_AttrDef_CSS_Percentage(),
  445. new HTMLPurifier_AttrDef_CSS_Length()
  446. ));
  447. $this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
  448. new HTMLPurifier_AttrDef_Enum(array('normal')),
  449. new HTMLPurifier_AttrDef_CSS_Number(true),
  450. new HTMLPurifier_AttrDef_CSS_Length(true),
  451. new HTMLPurifier_AttrDef_CSS_Percentage(true)
  452. ));
  453. $margin =
  454. $this->info['margin-top'] =
  455. $this->info['margin-bottom'] =
  456. $this->info['margin-left'] =
  457. $this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
  458. new HTMLPurifier_AttrDef_CSS_Length(),
  459. new HTMLPurifier_AttrDef_CSS_Percentage(),
  460. new HTMLPurifier_AttrDef_Enum(array('auto'))
  461. ));
  462. $this->info['margin'] = new HTMLPurifier_AttrDef_CSS_Multiple($margin);
  463. $padding =
  464. $this->info['padding-top'] =
  465. $this->info['padding-bottom'] =
  466. $this->info['padding-left'] =
  467. $this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
  468. new HTMLPurifier_AttrDef_CSS_Length(true),
  469. new HTMLPurifier_AttrDef_CSS_Percentage(true)
  470. ));
  471. $this->info['padding'] = new HTMLPurifier_AttrDef_CSS_Multiple($padding);
  472. $this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
  473. new HTMLPurifier_AttrDef_CSS_Length(),
  474. new HTMLPurifier_AttrDef_CSS_Percentage()
  475. ));
  476. $this->info['width'] =
  477. $this->info['height'] =
  478. new HTMLPurifier_AttrDef_CSS_DenyElementDecorator(
  479. new HTMLPurifier_AttrDef_CSS_Composite(array(
  480. new HTMLPurifier_AttrDef_CSS_Length(true),
  481. new HTMLPurifier_AttrDef_CSS_Percentage(true),
  482. new HTMLPurifier_AttrDef_Enum(array('auto'))
  483. )), 'img');
  484. $this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration();
  485. $this->info['font-family'] = new HTMLPurifier_AttrDef_CSS_FontFamily();
  486. $this->info['font-weight'] = new HTMLPurifier_AttrDef_Enum(
  487. array('normal', 'bold', 'bolder', 'lighter', '100', '200', '300',
  488. '400', '500', '600', '700', '800', '900'), false);
  489. $this->info['font'] = new HTMLPurifier_AttrDef_CSS_Font($config);
  490. $this->info['border'] =
  491. $this->info['border-bottom'] =
  492. $this->info['border-top'] =
  493. $this->info['border-left'] =
  494. $this->info['border-right'] = new HTMLPurifier_AttrDef_CSS_Border($config);
  495. $this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum(array(
  496. 'collapse', 'separate'));
  497. $this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum(array(
  498. 'top', 'bottom'));
  499. $this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum(array(
  500. 'auto', 'fixed'));
  501. $this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
  502. new HTMLPurifier_AttrDef_Enum(array('baseline', 'sub', 'super',
  503. 'top', 'text-top', 'middle', 'bottom', 'text-bottom')),
  504. new HTMLPurifier_AttrDef_CSS_Length(),
  505. new HTMLPurifier_AttrDef_CSS_Percentage()
  506. ));
  507. $this->info['border-spacing'] = new HTMLPurifier_AttrDef_CSS_Multiple(new HTMLPurifier_AttrDef_CSS_Length(), 2);
  508. $this->info['white-space'] = new HTMLPurifier_AttrDef_Enum(array('nowrap'));
  509. if ($config->get('CSS', 'Proprietary')) {
  510. $this->doSetupProprietary($config);
  511. }
  512. if ($config->get('CSS', 'AllowTricky')) {
  513. $this->doSetupTricky($config);
  514. }
  515. $allow_important = $config->get('CSS', 'AllowImportant');
  516. foreach ($this->info as $k => $v) {
  517. $this->info[$k] = new HTMLPurifier_AttrDef_CSS_ImportantDecorator($v, $allow_important);
  518. }
  519. $this->setupConfigStuff($config);
  520. }
  521. protected function doSetupProprietary($config) {
  522. $this->info['scrollbar-arrow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
  523. $this->info['scrollbar-base-color'] = new HTMLPurifier_AttrDef_CSS_Color();
  524. $this->info['scrollbar-darkshadow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
  525. $this->info['scrollbar-face-color'] = new HTMLPurifier_AttrDef_CSS_Color();
  526. $this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color();
  527. $this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
  528. $this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
  529. $this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
  530. $this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
  531. $this->info['filter'] = new HTMLPurifier_AttrDef_CSS_Filter();
  532. }
  533. protected function doSetupTricky($config) {
  534. $this->info['display'] = new HTMLPurifier_AttrDef_Enum(array(
  535. 'inline', 'block', 'list-item', 'run-in', 'compact',
  536. 'marker', 'table', 'inline-table', 'table-row-group',
  537. 'table-header-group', 'table-footer-group', 'table-row',
  538. 'table-column-group', 'table-column', 'table-cell', 'table-caption', 'none'
  539. ));
  540. $this->info['visibility'] = new HTMLPurifier_AttrDef_Enum(array(
  541. 'visible', 'hidden', 'collapse'
  542. ));
  543. }
  544. protected function setupConfigStuff($config) {
  545. $support = "(for information on implementing this, see the ".
  546. "support forums) ";
  547. $allowed_attributes = $config->get('CSS', 'AllowedProperties');
  548. if ($allowed_attributes !== null) {
  549. foreach ($this->info as $name => $d) {
  550. if(!isset($allowed_attributes[$name])) unset($this->info[$name]);
  551. unset($allowed_attributes[$name]);
  552. }
  553. foreach ($allowed_attributes as $name => $d) {
  554. $name = htmlspecialchars($name);
  555. trigger_error("Style attribute '$name' is not supported $support", E_USER_WARNING);
  556. }
  557. }
  558. }
  559. }
  560. abstract class HTMLPurifier_ChildDef
  561. {
  562. public $type;
  563. public $allow_empty;
  564. public $elements = array();
  565. abstract public function validateChildren($tokens_of_children, $config, $context);
  566. }
  567. class HTMLPurifier_Config
  568. {
  569. public $version = '3.1.0';
  570. public $autoFinalize = true;
  571. protected $serials = array();
  572. protected $serial;
  573. protected $conf;
  574. protected $parser;
  575. public $def;
  576. protected $definitions;
  577. protected $finalized = false;
  578. public function __construct($definition) {
  579. $this->conf = $definition->defaults;
  580. $this->def = $definition;
  581. $this->parser = new HTMLPurifier_VarParser_Flexible();
  582. }
  583. public static function create($config, $schema = null) {
  584. if ($config instanceof HTMLPurifier_Config) {
  585. return $config;
  586. }
  587. if (!$schema) {
  588. $ret = HTMLPurifier_Config::createDefault();
  589. } else {
  590. $ret = new HTMLPurifier_Config($schema);
  591. }
  592. if (is_string($config)) $ret->loadIni($config);
  593. elseif (is_array($config)) $ret->loadArray($config);
  594. return $ret;
  595. }
  596. public static function createDefault() {
  597. $definition = HTMLPurifier_ConfigSchema::instance();
  598. $config = new HTMLPurifier_Config($definition);
  599. return $config;
  600. }
  601. public function get($namespace, $key) {
  602. if (!$this->finalized && $this->autoFinalize) $this->finalize();
  603. if (!isset($this->def->info[$namespace][$key])) {
  604. trigger_error('Cannot retrieve value of undefined directive ' . htmlspecialchars("$namespace.$key"),
  605. E_USER_WARNING);
  606. return;
  607. }
  608. if ($this->def->info[$namespace][$key]->class == 'alias') {
  609. $d = $this->def->info[$namespace][$key];
  610. trigger_error('Cannot get value from aliased directive, use real name ' . $d->namespace . '.' . $d->name,
  611. E_USER_ERROR);
  612. return;
  613. }
  614. return $this->conf[$namespace][$key];
  615. }
  616. public function getBatch($namespace) {
  617. if (!$this->finalized && $this->autoFinalize) $this->finalize();
  618. if (!isset($this->def->info[$namespace])) {
  619. trigger_error('Cannot retrieve undefined namespace ' . htmlspecialchars($namespace),
  620. E_USER_WARNING);
  621. return;
  622. }
  623. return $this->conf[$namespace];
  624. }
  625. public function getBatchSerial($namespace) {
  626. if (empty($this->serials[$namespace])) {
  627. $batch = $this->getBatch($namespace);
  628. unset($batch['DefinitionRev']);
  629. $this->serials[$namespace] = md5(serialize($batch));
  630. }
  631. return $this->serials[$namespace];
  632. }
  633. public function getSerial() {
  634. if (empty($this->serial)) {
  635. $this->serial = md5(serialize($this->getAll()));
  636. }
  637. return $this->serial;
  638. }
  639. public function getAll() {
  640. if (!$this->finalized && $this->autoFinalize) $this->finalize();
  641. return $this->conf;
  642. }
  643. public function set($namespace, $key, $value, $from_alias = false) {
  644. if ($this->isFinalized('Cannot set directive after finalization')) return;
  645. if (!isset($this->def->info[$namespace][$key])) {
  646. trigger_error('Cannot set undefined directive ' . htmlspecialchars("$namespace.$key") . ' to value',
  647. E_USER_WARNING);
  648. return;
  649. }
  650. if ($this->def->info[$namespace][$key]->class == 'alias') {
  651. if ($from_alias) {
  652. trigger_error('Double-aliases not allowed, please fix '.
  653. 'ConfigSchema bug with' . "$namespace.$key", E_USER_ERROR);
  654. return;
  655. }
  656. $this->set($new_ns = $this->def->info[$namespace][$key]->namespace,
  657. $new_dir = $this->def->info[$namespace][$key]->name,
  658. $value, true);
  659. trigger_error("$namespace.$key is an alias, preferred directive name is $new_ns.$new_dir", E_USER_NOTICE);
  660. return;
  661. }
  662. try {
  663. $value = $this->parser->parse(
  664. $value,
  665. $type = $this->def->info[$namespace][$key]->type,
  666. $this->def->info[$namespace][$key]->allow_null
  667. );
  668. } catch (HTMLPurifier_VarParserException $e) {
  669. trigger_error('Value for ' . "$namespace.$key" . ' is of invalid type, should be ' . $type, E_USER_WARNING);
  670. return;
  671. }
  672. if (is_string($value)) {
  673. if (isset($this->def->info[$namespace][$key]->aliases[$value])) {
  674. $value = $this->def->info[$namespace][$key]->aliases[$value];
  675. }
  676. if ($this->def->info[$namespace][$key]->allowed !== true) {
  677. if (!isset($this->def->info[$namespace][$key]->allowed[$value])) {
  678. trigger_error('Value not supported, valid values are: ' .
  679. $this->_listify($this->def->info[$namespace][$key]->allowed), E_USER_WARNING);
  680. return;
  681. }
  682. }
  683. }
  684. $this->conf[$namespace][$key] = $value;
  685. if ($namespace == 'HTML' || $namespace == 'CSS') {
  686. $this->definitions[$namespace] = null;
  687. }
  688. $this->serials[$namespace] = false;
  689. }
  690. private function _listify($lookup) {
  691. $list = array();
  692. foreach ($lookup as $name => $b) $list[] = $name;
  693. return implode(', ', $list);
  694. }
  695. public function getHTMLDefinition($raw = false) {
  696. return $this->getDefinition('HTML', $raw);
  697. }
  698. public function getCSSDefinition($raw = false) {
  699. return $this->getDefinition('CSS', $raw);
  700. }
  701. public function getDefinition($type, $raw = false) {
  702. if (!$this->finalized && $this->autoFinalize) $this->finalize();
  703. $factory = HTMLPurifier_DefinitionCacheFactory::instance();
  704. $cache = $factory->create($type, $this);
  705. if (!$raw) {
  706. if (!empty($this->definitions[$type])) {
  707. if (!$this->definitions[$type]->setup) {
  708. $this->definitions[$type]->setup($this);
  709. $cache->set($this->definitions[$type], $this);
  710. }
  711. return $this->definitions[$type];
  712. }
  713. $this->definitions[$type] = $cache->get($this);
  714. if ($this->definitions[$type]) {
  715. return $this->definitions[$type];
  716. }
  717. } elseif (
  718. !empty($this->definitions[$type]) &&
  719. !$this->definitions[$type]->setup
  720. ) {
  721. return $this->definitions[$type];
  722. }
  723. if ($type == 'HTML') {
  724. $this->definitions[$type] = new HTMLPurifier_HTMLDefinition();
  725. } elseif ($type == 'CSS') {
  726. $this->definitions[$type] = new HTMLPurifier_CSSDefinition();
  727. } elseif ($type == 'URI') {
  728. $this->definitions[$type] = new HTMLPurifier_URIDefinition();
  729. } else {
  730. throw new HTMLPurifier_Exception("Definition of $type type not supported");
  731. }
  732. if ($raw) {
  733. if (is_null($this->get($type, 'DefinitionID'))) {
  734. throw new HTMLPurifier_Exception("Cannot retrieve raw version without specifying %$type.DefinitionID");
  735. }
  736. return $this->definitions[$type];
  737. }
  738. $this->definitions[$type]->setup($this);
  739. $cache->set($this->definitions[$type], $this);
  740. return $this->definitions[$type];
  741. }
  742. public function loadArray($config_array) {
  743. if ($this->isFinalized('Cannot load directives after finalization')) return;
  744. foreach ($config_array as $key => $value) {
  745. $key = str_replace('_', '.', $key);
  746. if (strpos($key, '.') !== false) {
  747. list($namespace, $directive) = explode('.', $key);
  748. $this->set($namespace, $directive, $value);
  749. } else {
  750. $namespace = $key;
  751. $namespace_values = $value;
  752. foreach ($namespace_values as $directive => $value) {
  753. $this->set($namespace, $directive, $value);
  754. }
  755. }
  756. }
  757. }
  758. public static function getAllowedDirectivesForForm($allowed, $schema = null) {
  759. if (!$schema) {
  760. $schema = HTMLPurifier_ConfigSchema::instance();
  761. }
  762. if ($allowed !== true) {
  763. if (is_string($allowed)) $allowed = array($allowed);
  764. $allowed_ns = array();
  765. $allowed_directives = array();
  766. $blacklisted_directives = array();
  767. foreach ($allowed as $ns_or_directive) {
  768. if (strpos($ns_or_directive, '.') !== false) {
  769. if ($ns_or_directive[0] == '-') {
  770. $blacklisted_directives[substr($ns_or_directive, 1)] = true;
  771. } else {
  772. $allowed_directives[$ns_or_directive] = true;
  773. }
  774. } else {
  775. $allowed_ns[$ns_or_directive] = true;
  776. }
  777. }
  778. }
  779. $ret = array();
  780. foreach ($schema->info as $ns => $keypairs) {
  781. foreach ($keypairs as $directive => $def) {
  782. if ($allowed !== true) {
  783. if (isset($blacklisted_directives["$ns.$directive"])) continue;
  784. if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) continue;
  785. }
  786. if ($def->class == 'alias') continue;
  787. if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') continue;
  788. $ret[] = array($ns, $directive);
  789. }
  790. }
  791. return $ret;
  792. }
  793. public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) {
  794. $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema);
  795. $config = HTMLPurifier_Config::create($ret, $schema);
  796. return $config;
  797. }
  798. public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true) {
  799. $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def);
  800. $this->loadArray($ret);
  801. }
  802. public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) {
  803. if ($index !== false) $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array();
  804. $mq = $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc();
  805. $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema);
  806. $ret = array();
  807. foreach ($allowed as $key) {
  808. list($ns, $directive) = $key;
  809. $skey = "$ns.$directive";
  810. if (!empty($array["Null_$skey"])) {
  811. $ret[$ns][$directive] = null;
  812. continue;
  813. }
  814. if (!isset($array[$skey])) continue;
  815. $value = $mq ? stripslashes($array[$skey]) : $array[$skey];
  816. $ret[$ns][$directive] = $value;
  817. }
  818. return $ret;
  819. }
  820. public function loadIni($filename) {
  821. if ($this->isFinalized('Cannot load directives after finalization')) return;
  822. $array = parse_ini_file($filename, true);
  823. $this->loadArray($array);
  824. }
  825. public function isFinalized($error = false) {
  826. if ($this->finalized && $error) {
  827. trigger_error($error, E_USER_ERROR);
  828. }
  829. return $this->finalized;
  830. }
  831. public function autoFinalize() {
  832. if (!$this->finalized && $this->autoFinalize) $this->finalize();
  833. }
  834. public function finalize() {
  835. $this->finalized = true;
  836. }
  837. }
  838. abstract class HTMLPurifier_ConfigDef {
  839. public $class = false;
  840. }
  841. class HTMLPurifier_ConfigSchema {
  842. public $defaults = array();
  843. public $info = array();
  844. static protected $singleton;
  845. protected $parser;
  846. public function __construct() {
  847. $this->parser = new HTMLPurifier_VarParser_Flexible();
  848. }
  849. public static function makeFromSerial() {
  850. return unserialize(file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema.ser'));
  851. }
  852. public static function instance($prototype = null) {
  853. if ($prototype !== null) {
  854. HTMLPurifier_ConfigSchema::$singleton = $prototype;
  855. } elseif (HTMLPurifier_ConfigSchema::$singleton === null || $prototype === true) {
  856. HTMLPurifier_ConfigSchema::$singleton = HTMLPurifier_ConfigSchema::makeFromSerial();
  857. }
  858. return HTMLPurifier_ConfigSchema::$singleton;
  859. }
  860. public function add($namespace, $name, $default, $type, $allow_null) {
  861. $default = $this->parser->parse($default, $type, $allow_null);
  862. $this->info[$namespace][$name] = new HTMLPurifier_ConfigDef_Directive();
  863. $this->info[$namespace][$name]->type = $type;
  864. $this->info[$namespace][$name]->allow_null = $allow_null;
  865. $this->defaults[$namespace][$name] = $default;
  866. }
  867. public function addNamespace($namespace) {
  868. $this->info[$namespace] = array();
  869. $this->defaults[$namespace] = array();
  870. }
  871. public function addValueAliases($namespace, $name, $aliases) {
  872. foreach ($aliases as $alias => $real) {
  873. $this->info[$namespace][$name]->aliases[$alias] = $real;
  874. }
  875. }
  876. public function addAllowedValues($namespace, $name, $allowed) {
  877. $type = $this->info[$namespace][$name]->type;
  878. $this->info[$namespace][$name]->allowed = $allowed;
  879. }
  880. public function addAlias($namespace, $name, $new_namespace, $new_name) {
  881. $this->info[$namespace][$name] = new HTMLPurifier_ConfigDef_DirectiveAlias($new_namespace, $new_name);
  882. }
  883. /** @see HTMLPurifier_ConfigSchema->set() */
  884. public static function define($namespace, $name, $default, $type, $description) {
  885. HTMLPurifier_ConfigSchema::deprecated(__METHOD__);
  886. $type_values = explode('/', $type, 2);
  887. $type = $type_values[0];
  888. $modifier = isset($type_values[1]) ? $type_values[1] : false;
  889. $allow_null = ($modifier === 'null');
  890. $def = HTMLPurifier_ConfigSchema::instance();
  891. $def->add($namespace, $name, $default, $type, $allow_null);
  892. }
  893. /** @see HTMLPurifier_ConfigSchema->addNamespace() */
  894. public static function defineNamespace($namespace, $description) {
  895. HTMLPurifier_ConfigSchema::deprecated(__METHOD__);
  896. $def = HTMLPurifier_ConfigSchema::instance();
  897. $def->addNamespace($namespace);
  898. }
  899. /** @see HTMLPurifier_ConfigSchema->addValueAliases() */
  900. public static function defineValueAliases($namespace, $name, $aliases) {
  901. HTMLPurifier_ConfigSchema::deprecated(__METHOD__);
  902. $def = HTMLPurifier_ConfigSchema::instance();
  903. $def->addValueAliases($namespace, $name, $aliases);
  904. }
  905. /** @see HTMLPurifier_ConfigSchema->addAllowedValues() */
  906. public static function defineAllowedValues($namespace, $name, $allowed_values) {
  907. HTMLPurifier_ConfigSchema::deprecated(__METHOD__);
  908. $allowed = array();
  909. foreach ($allowed_values as $value) {
  910. $allowed[$value] = true;
  911. }
  912. $def = HTMLPurifier_ConfigSchema::instance();
  913. $def->addAllowedValues($namespace, $name, $allowed);
  914. }
  915. /** @see HTMLPurifier_ConfigSchema->addAlias() */
  916. public static function defineAlias($namespace, $name, $new_namespace, $new_name) {
  917. HTMLPurifier_ConfigSchema::deprecated(__METHOD__);
  918. $def = HTMLPurifier_ConfigSchema::instance();
  919. $def->addAlias($namespace, $name, $new_namespace, $new_name);
  920. }
  921. /** @deprecated, use HTMLPurifier_VarParser->parse() */
  922. public function validate($a, $b, $c = false) {
  923. trigger_error("HTMLPurifier_ConfigSchema->validate deprecated, use HTMLPurifier_VarParser->parse instead", E_USER_NOTICE);
  924. return $this->parser->parse($a, $b, $c);
  925. }
  926. private static function deprecated($method) {
  927. trigger_error("Static HTMLPurifier_ConfigSchema::$method deprecated, use add*() method instead", E_USER_NOTICE);
  928. }
  929. }
  930. class HTMLPurifier_ContentSets
  931. {
  932. public $info = array();
  933. public $lookup = array();
  934. protected $keys = array();
  935. protected $values = array();
  936. public function __construct($modules) {
  937. if (!is_array($modules)) $modules = array($modules);
  938. foreach ($modules as $module_i => $module) {
  939. foreach ($module->content_sets as $key => $value) {
  940. if (isset($this->info[$key])) {
  941. $this->info[$key] = $this->info[$key] . ' | ' . $value;
  942. } else {
  943. $this->info[$key] = $value;
  944. }
  945. }
  946. }
  947. $this->keys = array_keys($this->info);
  948. foreach ($this->info as $i => $set) {
  949. $this->info[$i] =
  950. str_replace(
  951. $this->keys,
  952. array_values($this->info),
  953. $set);
  954. }
  955. $this->values = array_values($this->info);
  956. foreach ($this->info as $name => $set) {
  957. $this->lookup[$name] = $this->convertToLookup($set);
  958. }
  959. }
  960. public function generateChildDef(&$def, $module) {
  961. if (!empty($def->child)) return;
  962. $content_model = $def->content_model;
  963. if (is_string($content_model)) {
  964. $def->content_model = str_replace(
  965. $this->keys, $this->values, $content_model);
  966. }
  967. $def->child = $this->getChildDef($def, $module);
  968. }
  969. public function getChildDef($def, $module) {
  970. $value = $def->content_model;
  971. if (is_object($value)) {
  972. trigger_error(
  973. 'Literal object child definitions should be stored in '.
  974. 'ElementDef->child not ElementDef->content_model',
  975. E_USER_NOTICE
  976. );
  977. return $value;
  978. }
  979. switch ($def->content_model_type) {
  980. case 'required':
  981. return new HTMLPurifier_ChildDef_Required($value);
  982. case 'optional':
  983. return new HTMLPurifier_ChildDef_Optional($value);
  984. case 'empty':
  985. return new HTMLPurifier_ChildDef_Empty();
  986. case 'custom':
  987. return new HTMLPurifier_ChildDef_Custom($value);
  988. }
  989. $return = false;
  990. if ($module->defines_child_def) {
  991. $return = $module->getChildDef($def);
  992. }
  993. if ($return !== false) return $return;
  994. trigger_error(
  995. 'Could not determine which ChildDef class to instantiate',
  996. E_USER_ERROR
  997. );
  998. return false;
  999. }
  1000. protected function convertToLookup($string) {
  1001. $array = explode('|', str_replace(' ', '', $string));
  1002. $ret = array();
  1003. foreach ($array as $i => $k) {
  1004. $ret[$k] = true;
  1005. }
  1006. return $ret;
  1007. }
  1008. }
  1009. class HTMLPurifier_Context
  1010. {
  1011. private $_storage = array();
  1012. public function register($name, &$ref) {
  1013. if (isset($this->_storage[$name])) {
  1014. trigger_error("Name $name produces collision, cannot re-register",
  1015. E_USER_ERROR);
  1016. return;
  1017. }
  1018. $this->_storage[$name] =& $ref;
  1019. }
  1020. public function &get($name, $ignore_error = false) {
  1021. if (!isset($this->_storage[$name])) {
  1022. if (!$ignore_error) {
  1023. trigger_error("Attempted to retrieve non-existent variable $name",
  1024. E_USER_ERROR);
  1025. }
  1026. $var = null;
  1027. return $var;
  1028. }
  1029. return $this->_storage[$name];
  1030. }
  1031. public function destroy($name) {
  1032. if (!isset($this->_storage[$name])) {
  1033. trigger_error("Attempted to destroy non-existent variable $name",
  1034. E_USER_ERROR);
  1035. return;
  1036. }
  1037. unset($this->_storage[$name]);
  1038. }
  1039. public function exists($name) {
  1040. return isset($this->_storage[$name]);
  1041. }
  1042. public function loadArray($context_array) {
  1043. foreach ($context_array as $key => $discard) {
  1044. $this->register($key, $context_array[$key]);
  1045. }
  1046. }
  1047. }
  1048. abstract class HTMLPurifier_DefinitionCache
  1049. {
  1050. public $type;
  1051. public function __construct($type) {
  1052. $this->type = $type;
  1053. }
  1054. public function generateKey($config) {
  1055. return $config->version . ',' .
  1056. $config->getBatchSerial($this->type) . ',' .
  1057. $config->get($this->type, 'DefinitionRev');
  1058. }
  1059. public function isOld($key, $config) {
  1060. if (substr_count($key, ',') < 2) return true;
  1061. list($version, $hash, $revision) = explode(',', $key, 3);
  1062. $compare = version_compare($version, $config->version);
  1063. if ($compare != 0) return true;
  1064. if (
  1065. $hash == $config->getBatchSerial($this->type) &&
  1066. $revision < $config->get($this->type, 'DefinitionRev')
  1067. ) return true;
  1068. return false;
  1069. }
  1070. public function checkDefType($def) {
  1071. if ($def->type !== $this->type) {
  1072. trigger_error("Cannot use definition of type {$def->type} in cache for {$this->type}");
  1073. return false;
  1074. }
  1075. return true;
  1076. }
  1077. abstract public function add($def, $config);
  1078. abstract public function set($def, $config);
  1079. abstract public function replace($def, $config);
  1080. abstract public function get($config);
  1081. abstract public function remove($config);
  1082. abstract public function flush($config);
  1083. abstract public function cleanup($config);
  1084. }
  1085. class HTMLPurifier_DefinitionCacheFactory
  1086. {
  1087. protected $caches = array('Serializer' => array());
  1088. protected $implementations = array();
  1089. protected $decorators = array();
  1090. public function setup() {
  1091. $this->addDecorator('Cleanup');
  1092. }
  1093. public static function instance($prototype = null) {
  1094. static $instance;
  1095. if ($prototype !== null) {
  1096. $instance = $prototype;
  1097. } elseif ($instance === null || $prototype === true) {
  1098. $instance = new HTMLPurifier_DefinitionCacheFactory();
  1099. $instance->setup();
  1100. }
  1101. return $instance;
  1102. }
  1103. public function register($short, $long) {
  1104. $this->implementations[$short] = $long;
  1105. }
  1106. public function create($type, $config) {
  1107. $method = $config->get('Cache', 'DefinitionImpl');
  1108. if ($method === null) {
  1109. return new HTMLPurifier_DefinitionCache_Null($type);
  1110. }
  1111. if (!empty($this->caches[$method][$type])) {
  1112. return $this->caches[$method][$type];
  1113. }
  1114. if (
  1115. isset($this->implementations[$method]) &&
  1116. class_exists($class = $this->implementations[$method], false)
  1117. ) {
  1118. $cache = new $class($type);
  1119. } else {
  1120. if ($method != 'Serializer') {
  1121. trigger_error("Unrecognized DefinitionCache $method, using Serializer instead", E_USER_WARNING);
  1122. }
  1123. $cache = new HTMLPurifier_DefinitionCache_Serializer($type);
  1124. }
  1125. foreach ($this->decorators as $decorator) {
  1126. $new_cache = $decorator->decorate($cache);
  1127. unset($cache);
  1128. $cache = $new_cache;
  1129. }
  1130. $this->caches[$method][$type] = $cache;
  1131. return $this->caches[$method][$type];
  1132. }
  1133. public function addDecorator($decorator) {
  1134. if (is_string($decorator)) {
  1135. $class = "HTMLPurifier_DefinitionCache_Decorator_$decorator";
  1136. $decorator = new $class;
  1137. }
  1138. $this->decorators[$decorator->name] = $decorator;
  1139. }
  1140. }
  1141. class HTMLPurifier_Doctype
  1142. {
  1143. public $name;
  1144. public $modules = array();
  1145. public $tidyModules = array();
  1146. public $xml = true;
  1147. public $aliases = array();
  1148. public $dtdPublic;
  1149. public $dtdSystem;
  1150. public function __construct($name = null, $xml = true, $modules = array(),
  1151. $tidyModules = array(), $aliases = array(), $dtd_public = null, $dtd_system = null
  1152. ) {
  1153. $this->name = $name;
  1154. $this->xml = $xml;
  1155. $this->modules = $modules;
  1156. $this->tidyModules = $tidyModules;
  1157. $this->aliases = $aliases;
  1158. $this->dtdPublic = $dtd_public;
  1159. $this->dtdSystem =

Large files files are truncated, but you can click here to view the full file