File indexing completed on 2024-12-22 05:36:21
0001 <?php 0002 0003 /** 0004 * Configuration object that triggers customizable behavior. 0005 * 0006 * @warning This class is strongly defined: that means that the class 0007 * will fail if an undefined directive is retrieved or set. 0008 * 0009 * @note Many classes that could (although many times don't) use the 0010 * configuration object make it a mandatory parameter. This is 0011 * because a configuration object should always be forwarded, 0012 * otherwise, you run the risk of missing a parameter and then 0013 * being stumped when a configuration directive doesn't work. 0014 * 0015 * @todo Reconsider some of the public member variables 0016 */ 0017 class HTMLPurifier_Config 0018 { 0019 0020 /** 0021 * HTML Purifier's version 0022 * @type string 0023 */ 0024 public $version = '4.9.3'; 0025 0026 /** 0027 * Whether or not to automatically finalize 0028 * the object if a read operation is done. 0029 * @type bool 0030 */ 0031 public $autoFinalize = true; 0032 0033 // protected member variables 0034 0035 /** 0036 * Namespace indexed array of serials for specific namespaces. 0037 * @see getSerial() for more info. 0038 * @type string[] 0039 */ 0040 protected $serials = array(); 0041 0042 /** 0043 * Serial for entire configuration object. 0044 * @type string 0045 */ 0046 protected $serial; 0047 0048 /** 0049 * Parser for variables. 0050 * @type HTMLPurifier_VarParser_Flexible 0051 */ 0052 protected $parser = null; 0053 0054 /** 0055 * Reference HTMLPurifier_ConfigSchema for value checking. 0056 * @type HTMLPurifier_ConfigSchema 0057 * @note This is public for introspective purposes. Please don't 0058 * abuse! 0059 */ 0060 public $def; 0061 0062 /** 0063 * Indexed array of definitions. 0064 * @type HTMLPurifier_Definition[] 0065 */ 0066 protected $definitions; 0067 0068 /** 0069 * Whether or not config is finalized. 0070 * @type bool 0071 */ 0072 protected $finalized = false; 0073 0074 /** 0075 * Property list containing configuration directives. 0076 * @type array 0077 */ 0078 protected $plist; 0079 0080 /** 0081 * Whether or not a set is taking place due to an alias lookup. 0082 * @type bool 0083 */ 0084 private $aliasMode; 0085 0086 /** 0087 * Set to false if you do not want line and file numbers in errors. 0088 * (useful when unit testing). This will also compress some errors 0089 * and exceptions. 0090 * @type bool 0091 */ 0092 public $chatty = true; 0093 0094 /** 0095 * Current lock; only gets to this namespace are allowed. 0096 * @type string 0097 */ 0098 private $lock; 0099 0100 /** 0101 * Constructor 0102 * @param HTMLPurifier_ConfigSchema $definition ConfigSchema that defines 0103 * what directives are allowed. 0104 * @param HTMLPurifier_PropertyList $parent 0105 */ 0106 public function __construct($definition, $parent = null) 0107 { 0108 $parent = $parent ? $parent : $definition->defaultPlist; 0109 $this->plist = new HTMLPurifier_PropertyList($parent); 0110 $this->def = $definition; // keep a copy around for checking 0111 $this->parser = new HTMLPurifier_VarParser_Flexible(); 0112 } 0113 0114 /** 0115 * Convenience constructor that creates a config object based on a mixed var 0116 * @param mixed $config Variable that defines the state of the config 0117 * object. Can be: a HTMLPurifier_Config() object, 0118 * an array of directives based on loadArray(), 0119 * or a string filename of an ini file. 0120 * @param HTMLPurifier_ConfigSchema $schema Schema object 0121 * @return HTMLPurifier_Config Configured object 0122 */ 0123 public static function create($config, $schema = null) 0124 { 0125 if ($config instanceof HTMLPurifier_Config) { 0126 // pass-through 0127 return $config; 0128 } 0129 if (!$schema) { 0130 $ret = HTMLPurifier_Config::createDefault(); 0131 } else { 0132 $ret = new HTMLPurifier_Config($schema); 0133 } 0134 if (is_string($config)) { 0135 $ret->loadIni($config); 0136 } elseif (is_array($config)) $ret->loadArray($config); 0137 return $ret; 0138 } 0139 0140 /** 0141 * Creates a new config object that inherits from a previous one. 0142 * @param HTMLPurifier_Config $config Configuration object to inherit from. 0143 * @return HTMLPurifier_Config object with $config as its parent. 0144 */ 0145 public static function inherit(HTMLPurifier_Config $config) 0146 { 0147 return new HTMLPurifier_Config($config->def, $config->plist); 0148 } 0149 0150 /** 0151 * Convenience constructor that creates a default configuration object. 0152 * @return HTMLPurifier_Config default object. 0153 */ 0154 public static function createDefault() 0155 { 0156 $definition = HTMLPurifier_ConfigSchema::instance(); 0157 $config = new HTMLPurifier_Config($definition); 0158 return $config; 0159 } 0160 0161 /** 0162 * Retrieves a value from the configuration. 0163 * 0164 * @param string $key String key 0165 * @param mixed $a 0166 * 0167 * @return mixed 0168 */ 0169 public function get($key, $a = null) 0170 { 0171 if ($a !== null) { 0172 $this->triggerError( 0173 "Using deprecated API: use \$config->get('$key.$a') instead", 0174 E_USER_WARNING 0175 ); 0176 $key = "$key.$a"; 0177 } 0178 if (!$this->finalized) { 0179 $this->autoFinalize(); 0180 } 0181 if (!isset($this->def->info[$key])) { 0182 // can't add % due to SimpleTest bug 0183 $this->triggerError( 0184 'Cannot retrieve value of undefined directive ' . htmlspecialchars($key), 0185 E_USER_WARNING 0186 ); 0187 return; 0188 } 0189 if (isset($this->def->info[$key]->isAlias)) { 0190 $d = $this->def->info[$key]; 0191 $this->triggerError( 0192 'Cannot get value from aliased directive, use real name ' . $d->key, 0193 E_USER_ERROR 0194 ); 0195 return; 0196 } 0197 if ($this->lock) { 0198 list($ns) = explode('.', $key); 0199 if ($ns !== $this->lock) { 0200 $this->triggerError( 0201 'Cannot get value of namespace ' . $ns . ' when lock for ' . 0202 $this->lock . 0203 ' is active, this probably indicates a Definition setup method ' . 0204 'is accessing directives that are not within its namespace', 0205 E_USER_ERROR 0206 ); 0207 return; 0208 } 0209 } 0210 return $this->plist->get($key); 0211 } 0212 0213 /** 0214 * Retrieves an array of directives to values from a given namespace 0215 * 0216 * @param string $namespace String namespace 0217 * 0218 * @return array 0219 */ 0220 public function getBatch($namespace) 0221 { 0222 if (!$this->finalized) { 0223 $this->autoFinalize(); 0224 } 0225 $full = $this->getAll(); 0226 if (!isset($full[$namespace])) { 0227 $this->triggerError( 0228 'Cannot retrieve undefined namespace ' . 0229 htmlspecialchars($namespace), 0230 E_USER_WARNING 0231 ); 0232 return; 0233 } 0234 return $full[$namespace]; 0235 } 0236 0237 /** 0238 * Returns a SHA-1 signature of a segment of the configuration object 0239 * that uniquely identifies that particular configuration 0240 * 0241 * @param string $namespace Namespace to get serial for 0242 * 0243 * @return string 0244 * @note Revision is handled specially and is removed from the batch 0245 * before processing! 0246 */ 0247 public function getBatchSerial($namespace) 0248 { 0249 if (empty($this->serials[$namespace])) { 0250 $batch = $this->getBatch($namespace); 0251 unset($batch['DefinitionRev']); 0252 $this->serials[$namespace] = sha1(serialize($batch)); 0253 } 0254 return $this->serials[$namespace]; 0255 } 0256 0257 /** 0258 * Returns a SHA-1 signature for the entire configuration object 0259 * that uniquely identifies that particular configuration 0260 * 0261 * @return string 0262 */ 0263 public function getSerial() 0264 { 0265 if (empty($this->serial)) { 0266 $this->serial = sha1(serialize($this->getAll())); 0267 } 0268 return $this->serial; 0269 } 0270 0271 /** 0272 * Retrieves all directives, organized by namespace 0273 * 0274 * @warning This is a pretty inefficient function, avoid if you can 0275 */ 0276 public function getAll() 0277 { 0278 if (!$this->finalized) { 0279 $this->autoFinalize(); 0280 } 0281 $ret = array(); 0282 foreach ($this->plist->squash() as $name => $value) { 0283 list($ns, $key) = explode('.', $name, 2); 0284 $ret[$ns][$key] = $value; 0285 } 0286 return $ret; 0287 } 0288 0289 /** 0290 * Sets a value to configuration. 0291 * 0292 * @param string $key key 0293 * @param mixed $value value 0294 * @param mixed $a 0295 */ 0296 public function set($key, $value, $a = null) 0297 { 0298 if (strpos($key, '.') === false) { 0299 $namespace = $key; 0300 $directive = $value; 0301 $value = $a; 0302 $key = "$key.$directive"; 0303 $this->triggerError("Using deprecated API: use \$config->set('$key', ...) instead", E_USER_NOTICE); 0304 } else { 0305 list($namespace) = explode('.', $key); 0306 } 0307 if ($this->isFinalized('Cannot set directive after finalization')) { 0308 return; 0309 } 0310 if (!isset($this->def->info[$key])) { 0311 $this->triggerError( 0312 'Cannot set undefined directive ' . htmlspecialchars($key) . ' to value', 0313 E_USER_WARNING 0314 ); 0315 return; 0316 } 0317 $def = $this->def->info[$key]; 0318 0319 if (isset($def->isAlias)) { 0320 if ($this->aliasMode) { 0321 $this->triggerError( 0322 'Double-aliases not allowed, please fix '. 0323 'ConfigSchema bug with' . $key, 0324 E_USER_ERROR 0325 ); 0326 return; 0327 } 0328 $this->aliasMode = true; 0329 $this->set($def->key, $value); 0330 $this->aliasMode = false; 0331 $this->triggerError("$key is an alias, preferred directive name is {$def->key}", E_USER_NOTICE); 0332 return; 0333 } 0334 0335 // Raw type might be negative when using the fully optimized form 0336 // of stdClass, which indicates allow_null == true 0337 $rtype = is_int($def) ? $def : $def->type; 0338 if ($rtype < 0) { 0339 $type = -$rtype; 0340 $allow_null = true; 0341 } else { 0342 $type = $rtype; 0343 $allow_null = isset($def->allow_null); 0344 } 0345 0346 try { 0347 $value = $this->parser->parse($value, $type, $allow_null); 0348 } catch (HTMLPurifier_VarParserException $e) { 0349 $this->triggerError( 0350 'Value for ' . $key . ' is of invalid type, should be ' . 0351 HTMLPurifier_VarParser::getTypeName($type), 0352 E_USER_WARNING 0353 ); 0354 return; 0355 } 0356 if (is_string($value) && is_object($def)) { 0357 // resolve value alias if defined 0358 if (isset($def->aliases[$value])) { 0359 $value = $def->aliases[$value]; 0360 } 0361 // check to see if the value is allowed 0362 if (isset($def->allowed) && !isset($def->allowed[$value])) { 0363 $this->triggerError( 0364 'Value not supported, valid values are: ' . 0365 $this->_listify($def->allowed), 0366 E_USER_WARNING 0367 ); 0368 return; 0369 } 0370 } 0371 $this->plist->set($key, $value); 0372 0373 // reset definitions if the directives they depend on changed 0374 // this is a very costly process, so it's discouraged 0375 // with finalization 0376 if ($namespace == 'HTML' || $namespace == 'CSS' || $namespace == 'URI') { 0377 $this->definitions[$namespace] = null; 0378 } 0379 0380 $this->serials[$namespace] = false; 0381 } 0382 0383 /** 0384 * Convenience function for error reporting 0385 * 0386 * @param array $lookup 0387 * 0388 * @return string 0389 */ 0390 private function _listify($lookup) 0391 { 0392 $list = array(); 0393 foreach ($lookup as $name => $b) { 0394 $list[] = $name; 0395 } 0396 return implode(', ', $list); 0397 } 0398 0399 /** 0400 * Retrieves object reference to the HTML definition. 0401 * 0402 * @param bool $raw Return a copy that has not been setup yet. Must be 0403 * called before it's been setup, otherwise won't work. 0404 * @param bool $optimized If true, this method may return null, to 0405 * indicate that a cached version of the modified 0406 * definition object is available and no further edits 0407 * are necessary. Consider using 0408 * maybeGetRawHTMLDefinition, which is more explicitly 0409 * named, instead. 0410 * 0411 * @return HTMLPurifier_HTMLDefinition 0412 */ 0413 public function getHTMLDefinition($raw = false, $optimized = false) 0414 { 0415 return $this->getDefinition('HTML', $raw, $optimized); 0416 } 0417 0418 /** 0419 * Retrieves object reference to the CSS definition 0420 * 0421 * @param bool $raw Return a copy that has not been setup yet. Must be 0422 * called before it's been setup, otherwise won't work. 0423 * @param bool $optimized If true, this method may return null, to 0424 * indicate that a cached version of the modified 0425 * definition object is available and no further edits 0426 * are necessary. Consider using 0427 * maybeGetRawCSSDefinition, which is more explicitly 0428 * named, instead. 0429 * 0430 * @return HTMLPurifier_CSSDefinition 0431 */ 0432 public function getCSSDefinition($raw = false, $optimized = false) 0433 { 0434 return $this->getDefinition('CSS', $raw, $optimized); 0435 } 0436 0437 /** 0438 * Retrieves object reference to the URI definition 0439 * 0440 * @param bool $raw Return a copy that has not been setup yet. Must be 0441 * called before it's been setup, otherwise won't work. 0442 * @param bool $optimized If true, this method may return null, to 0443 * indicate that a cached version of the modified 0444 * definition object is available and no further edits 0445 * are necessary. Consider using 0446 * maybeGetRawURIDefinition, which is more explicitly 0447 * named, instead. 0448 * 0449 * @return HTMLPurifier_URIDefinition 0450 */ 0451 public function getURIDefinition($raw = false, $optimized = false) 0452 { 0453 return $this->getDefinition('URI', $raw, $optimized); 0454 } 0455 0456 /** 0457 * Retrieves a definition 0458 * 0459 * @param string $type Type of definition: HTML, CSS, etc 0460 * @param bool $raw Whether or not definition should be returned raw 0461 * @param bool $optimized Only has an effect when $raw is true. Whether 0462 * or not to return null if the result is already present in 0463 * the cache. This is off by default for backwards 0464 * compatibility reasons, but you need to do things this 0465 * way in order to ensure that caching is done properly. 0466 * Check out enduser-customize.html for more details. 0467 * We probably won't ever change this default, as much as the 0468 * maybe semantics is the "right thing to do." 0469 * 0470 * @throws HTMLPurifier_Exception 0471 * @return HTMLPurifier_Definition 0472 */ 0473 public function getDefinition($type, $raw = false, $optimized = false) 0474 { 0475 if ($optimized && !$raw) { 0476 throw new HTMLPurifier_Exception("Cannot set optimized = true when raw = false"); 0477 } 0478 if (!$this->finalized) { 0479 $this->autoFinalize(); 0480 } 0481 // temporarily suspend locks, so we can handle recursive definition calls 0482 $lock = $this->lock; 0483 $this->lock = null; 0484 $factory = HTMLPurifier_DefinitionCacheFactory::instance(); 0485 $cache = $factory->create($type, $this); 0486 $this->lock = $lock; 0487 if (!$raw) { 0488 // full definition 0489 // --------------- 0490 // check if definition is in memory 0491 if (!empty($this->definitions[$type])) { 0492 $def = $this->definitions[$type]; 0493 // check if the definition is setup 0494 if ($def->setup) { 0495 return $def; 0496 } else { 0497 $def->setup($this); 0498 if ($def->optimized) { 0499 $cache->add($def, $this); 0500 } 0501 return $def; 0502 } 0503 } 0504 // check if definition is in cache 0505 $def = $cache->get($this); 0506 if ($def) { 0507 // definition in cache, save to memory and return it 0508 $this->definitions[$type] = $def; 0509 return $def; 0510 } 0511 // initialize it 0512 $def = $this->initDefinition($type); 0513 // set it up 0514 $this->lock = $type; 0515 $def->setup($this); 0516 $this->lock = null; 0517 // save in cache 0518 $cache->add($def, $this); 0519 // return it 0520 return $def; 0521 } else { 0522 // raw definition 0523 // -------------- 0524 // check preconditions 0525 $def = null; 0526 if ($optimized) { 0527 if (is_null($this->get($type . '.DefinitionID'))) { 0528 // fatally error out if definition ID not set 0529 throw new HTMLPurifier_Exception( 0530 "Cannot retrieve raw version without specifying %$type.DefinitionID" 0531 ); 0532 } 0533 } 0534 if (!empty($this->definitions[$type])) { 0535 $def = $this->definitions[$type]; 0536 if ($def->setup && !$optimized) { 0537 $extra = $this->chatty ? 0538 " (try moving this code block earlier in your initialization)" : 0539 ""; 0540 throw new HTMLPurifier_Exception( 0541 "Cannot retrieve raw definition after it has already been setup" . 0542 $extra 0543 ); 0544 } 0545 if ($def->optimized === null) { 0546 $extra = $this->chatty ? " (try flushing your cache)" : ""; 0547 throw new HTMLPurifier_Exception( 0548 "Optimization status of definition is unknown" . $extra 0549 ); 0550 } 0551 if ($def->optimized !== $optimized) { 0552 $msg = $optimized ? "optimized" : "unoptimized"; 0553 $extra = $this->chatty ? 0554 " (this backtrace is for the first inconsistent call, which was for a $msg raw definition)" 0555 : ""; 0556 throw new HTMLPurifier_Exception( 0557 "Inconsistent use of optimized and unoptimized raw definition retrievals" . $extra 0558 ); 0559 } 0560 } 0561 // check if definition was in memory 0562 if ($def) { 0563 if ($def->setup) { 0564 // invariant: $optimized === true (checked above) 0565 return null; 0566 } else { 0567 return $def; 0568 } 0569 } 0570 // if optimized, check if definition was in cache 0571 // (because we do the memory check first, this formulation 0572 // is prone to cache slamming, but I think 0573 // guaranteeing that either /all/ of the raw 0574 // setup code or /none/ of it is run is more important.) 0575 if ($optimized) { 0576 // This code path only gets run once; once we put 0577 // something in $definitions (which is guaranteed by the 0578 // trailing code), we always short-circuit above. 0579 $def = $cache->get($this); 0580 if ($def) { 0581 // save the full definition for later, but don't 0582 // return it yet 0583 $this->definitions[$type] = $def; 0584 return null; 0585 } 0586 } 0587 // check invariants for creation 0588 if (!$optimized) { 0589 if (!is_null($this->get($type . '.DefinitionID'))) { 0590 if ($this->chatty) { 0591 $this->triggerError( 0592 'Due to a documentation error in previous version of HTML Purifier, your ' . 0593 'definitions are not being cached. If this is OK, you can remove the ' . 0594 '%$type.DefinitionRev and %$type.DefinitionID declaration. Otherwise, ' . 0595 'modify your code to use maybeGetRawDefinition, and test if the returned ' . 0596 'value is null before making any edits (if it is null, that means that a ' . 0597 'cached version is available, and no raw operations are necessary). See ' . 0598 '<a href="http://htmlpurifier.org/docs/enduser-customize.html#optimized">' . 0599 'Customize</a> for more details', 0600 E_USER_WARNING 0601 ); 0602 } else { 0603 $this->triggerError( 0604 "Useless DefinitionID declaration", 0605 E_USER_WARNING 0606 ); 0607 } 0608 } 0609 } 0610 // initialize it 0611 $def = $this->initDefinition($type); 0612 $def->optimized = $optimized; 0613 return $def; 0614 } 0615 throw new HTMLPurifier_Exception("The impossible happened!"); 0616 } 0617 0618 /** 0619 * Initialise definition 0620 * 0621 * @param string $type What type of definition to create 0622 * 0623 * @return HTMLPurifier_CSSDefinition|HTMLPurifier_HTMLDefinition|HTMLPurifier_URIDefinition 0624 * @throws HTMLPurifier_Exception 0625 */ 0626 private function initDefinition($type) 0627 { 0628 // quick checks failed, let's create the object 0629 if ($type == 'HTML') { 0630 $def = new HTMLPurifier_HTMLDefinition(); 0631 } elseif ($type == 'CSS') { 0632 $def = new HTMLPurifier_CSSDefinition(); 0633 } elseif ($type == 'URI') { 0634 $def = new HTMLPurifier_URIDefinition(); 0635 } else { 0636 throw new HTMLPurifier_Exception( 0637 "Definition of $type type not supported" 0638 ); 0639 } 0640 $this->definitions[$type] = $def; 0641 return $def; 0642 } 0643 0644 public function maybeGetRawDefinition($name) 0645 { 0646 return $this->getDefinition($name, true, true); 0647 } 0648 0649 /** 0650 * @return HTMLPurifier_HTMLDefinition 0651 */ 0652 public function maybeGetRawHTMLDefinition() 0653 { 0654 return $this->getDefinition('HTML', true, true); 0655 } 0656 0657 /** 0658 * @return HTMLPurifier_CSSDefinition 0659 */ 0660 public function maybeGetRawCSSDefinition() 0661 { 0662 return $this->getDefinition('CSS', true, true); 0663 } 0664 0665 /** 0666 * @return HTMLPurifier_URIDefinition 0667 */ 0668 public function maybeGetRawURIDefinition() 0669 { 0670 return $this->getDefinition('URI', true, true); 0671 } 0672 0673 /** 0674 * Loads configuration values from an array with the following structure: 0675 * Namespace.Directive => Value 0676 * 0677 * @param array $config_array Configuration associative array 0678 */ 0679 public function loadArray($config_array) 0680 { 0681 if ($this->isFinalized('Cannot load directives after finalization')) { 0682 return; 0683 } 0684 foreach ($config_array as $key => $value) { 0685 $key = str_replace('_', '.', $key); 0686 if (strpos($key, '.') !== false) { 0687 $this->set($key, $value); 0688 } else { 0689 $namespace = $key; 0690 $namespace_values = $value; 0691 foreach ($namespace_values as $directive => $value2) { 0692 $this->set($namespace .'.'. $directive, $value2); 0693 } 0694 } 0695 } 0696 } 0697 0698 /** 0699 * Returns a list of array(namespace, directive) for all directives 0700 * that are allowed in a web-form context as per an allowed 0701 * namespaces/directives list. 0702 * 0703 * @param array $allowed List of allowed namespaces/directives 0704 * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy 0705 * 0706 * @return array 0707 */ 0708 public static function getAllowedDirectivesForForm($allowed, $schema = null) 0709 { 0710 if (!$schema) { 0711 $schema = HTMLPurifier_ConfigSchema::instance(); 0712 } 0713 if ($allowed !== true) { 0714 if (is_string($allowed)) { 0715 $allowed = array($allowed); 0716 } 0717 $allowed_ns = array(); 0718 $allowed_directives = array(); 0719 $blacklisted_directives = array(); 0720 foreach ($allowed as $ns_or_directive) { 0721 if (strpos($ns_or_directive, '.') !== false) { 0722 // directive 0723 if ($ns_or_directive[0] == '-') { 0724 $blacklisted_directives[substr($ns_or_directive, 1)] = true; 0725 } else { 0726 $allowed_directives[$ns_or_directive] = true; 0727 } 0728 } else { 0729 // namespace 0730 $allowed_ns[$ns_or_directive] = true; 0731 } 0732 } 0733 } 0734 $ret = array(); 0735 foreach ($schema->info as $key => $def) { 0736 list($ns, $directive) = explode('.', $key, 2); 0737 if ($allowed !== true) { 0738 if (isset($blacklisted_directives["$ns.$directive"])) { 0739 continue; 0740 } 0741 if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) { 0742 continue; 0743 } 0744 } 0745 if (isset($def->isAlias)) { 0746 continue; 0747 } 0748 if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') { 0749 continue; 0750 } 0751 $ret[] = array($ns, $directive); 0752 } 0753 return $ret; 0754 } 0755 0756 /** 0757 * Loads configuration values from $_GET/$_POST that were posted 0758 * via ConfigForm 0759 * 0760 * @param array $array $_GET or $_POST array to import 0761 * @param string|bool $index Index/name that the config variables are in 0762 * @param array|bool $allowed List of allowed namespaces/directives 0763 * @param bool $mq_fix Boolean whether or not to enable magic quotes fix 0764 * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy 0765 * 0766 * @return mixed 0767 */ 0768 public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) 0769 { 0770 $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema); 0771 $config = HTMLPurifier_Config::create($ret, $schema); 0772 return $config; 0773 } 0774 0775 /** 0776 * Merges in configuration values from $_GET/$_POST to object. NOT STATIC. 0777 * 0778 * @param array $array $_GET or $_POST array to import 0779 * @param string|bool $index Index/name that the config variables are in 0780 * @param array|bool $allowed List of allowed namespaces/directives 0781 * @param bool $mq_fix Boolean whether or not to enable magic quotes fix 0782 */ 0783 public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true) 0784 { 0785 $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def); 0786 $this->loadArray($ret); 0787 } 0788 0789 /** 0790 * Prepares an array from a form into something usable for the more 0791 * strict parts of HTMLPurifier_Config 0792 * 0793 * @param array $array $_GET or $_POST array to import 0794 * @param string|bool $index Index/name that the config variables are in 0795 * @param array|bool $allowed List of allowed namespaces/directives 0796 * @param bool $mq_fix Boolean whether or not to enable magic quotes fix 0797 * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy 0798 * 0799 * @return array 0800 */ 0801 public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) 0802 { 0803 if ($index !== false) { 0804 $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array(); 0805 } 0806 $mq = $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc(); 0807 0808 $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema); 0809 $ret = array(); 0810 foreach ($allowed as $key) { 0811 list($ns, $directive) = $key; 0812 $skey = "$ns.$directive"; 0813 if (!empty($array["Null_$skey"])) { 0814 $ret[$ns][$directive] = null; 0815 continue; 0816 } 0817 if (!isset($array[$skey])) { 0818 continue; 0819 } 0820 $value = $mq ? stripslashes($array[$skey]) : $array[$skey]; 0821 $ret[$ns][$directive] = $value; 0822 } 0823 return $ret; 0824 } 0825 0826 /** 0827 * Loads configuration values from an ini file 0828 * 0829 * @param string $filename Name of ini file 0830 */ 0831 public function loadIni($filename) 0832 { 0833 if ($this->isFinalized('Cannot load directives after finalization')) { 0834 return; 0835 } 0836 $array = parse_ini_file($filename, true); 0837 $this->loadArray($array); 0838 } 0839 0840 /** 0841 * Checks whether or not the configuration object is finalized. 0842 * 0843 * @param string|bool $error String error message, or false for no error 0844 * 0845 * @return bool 0846 */ 0847 public function isFinalized($error = false) 0848 { 0849 if ($this->finalized && $error) { 0850 $this->triggerError($error, E_USER_ERROR); 0851 } 0852 return $this->finalized; 0853 } 0854 0855 /** 0856 * Finalizes configuration only if auto finalize is on and not 0857 * already finalized 0858 */ 0859 public function autoFinalize() 0860 { 0861 if ($this->autoFinalize) { 0862 $this->finalize(); 0863 } else { 0864 $this->plist->squash(true); 0865 } 0866 } 0867 0868 /** 0869 * Finalizes a configuration object, prohibiting further change 0870 */ 0871 public function finalize() 0872 { 0873 $this->finalized = true; 0874 $this->parser = null; 0875 } 0876 0877 /** 0878 * Produces a nicely formatted error message by supplying the 0879 * stack frame information OUTSIDE of HTMLPurifier_Config. 0880 * 0881 * @param string $msg An error message 0882 * @param int $no An error number 0883 */ 0884 protected function triggerError($msg, $no) 0885 { 0886 // determine previous stack frame 0887 $extra = ''; 0888 if ($this->chatty) { 0889 $trace = debug_backtrace(); 0890 // zip(tail(trace), trace) -- but PHP is not Haskell har har 0891 for ($i = 0, $c = count($trace); $i < $c - 1; $i++) { 0892 // XXX this is not correct on some versions of HTML Purifier 0893 if ($trace[$i + 1]['class'] === 'HTMLPurifier_Config') { 0894 continue; 0895 } 0896 $frame = $trace[$i]; 0897 $extra = " invoked on line {$frame['line']} in file {$frame['file']}"; 0898 break; 0899 } 0900 } 0901 trigger_error($msg . $extra, $no); 0902 } 0903 0904 /** 0905 * Returns a serialized form of the configuration object that can 0906 * be reconstituted. 0907 * 0908 * @return string 0909 */ 0910 public function serialize() 0911 { 0912 $this->getDefinition('HTML'); 0913 $this->getDefinition('CSS'); 0914 $this->getDefinition('URI'); 0915 return serialize($this); 0916 } 0917 0918 } 0919 0920 // vim: et sw=4 sts=4