diff options
Diffstat (limited to 'library/HTMLPurifier/Config.php')
-rw-r--r-- | library/HTMLPurifier/Config.php | 681 |
1 files changed, 506 insertions, 175 deletions
diff --git a/library/HTMLPurifier/Config.php b/library/HTMLPurifier/Config.php index 2a334b0d8..7ada59b94 100644 --- a/library/HTMLPurifier/Config.php +++ b/library/HTMLPurifier/Config.php @@ -19,77 +19,92 @@ class HTMLPurifier_Config /** * HTML Purifier's version + * @type string */ - public $version = '4.1.1'; + public $version = '4.6.0'; /** - * Bool indicator whether or not to automatically finalize - * the object if a read operation is done + * Whether or not to automatically finalize + * the object if a read operation is done. + * @type bool */ public $autoFinalize = true; // protected member variables /** - * Namespace indexed array of serials for specific namespaces (see - * getSerial() for more info). + * Namespace indexed array of serials for specific namespaces. + * @see getSerial() for more info. + * @type string[] */ protected $serials = array(); /** - * Serial for entire configuration object + * Serial for entire configuration object. + * @type string */ protected $serial; /** - * Parser for variables + * Parser for variables. + * @type HTMLPurifier_VarParser_Flexible */ - protected $parser; + protected $parser = null; /** - * Reference HTMLPurifier_ConfigSchema for value checking + * Reference HTMLPurifier_ConfigSchema for value checking. + * @type HTMLPurifier_ConfigSchema * @note This is public for introspective purposes. Please don't * abuse! */ public $def; /** - * Indexed array of definitions + * Indexed array of definitions. + * @type HTMLPurifier_Definition[] */ protected $definitions; /** - * Bool indicator whether or not config is finalized + * Whether or not config is finalized. + * @type bool */ protected $finalized = false; /** * Property list containing configuration directives. + * @type array */ protected $plist; /** - * Whether or not a set is taking place due to an - * alias lookup. + * Whether or not a set is taking place due to an alias lookup. + * @type bool */ private $aliasMode; /** - * Set to false if you do not want line and file numbers in errors - * (useful when unit testing) + * Set to false if you do not want line and file numbers in errors. + * (useful when unit testing). This will also compress some errors + * and exceptions. + * @type bool */ public $chatty = true; /** * Current lock; only gets to this namespace are allowed. + * @type string */ private $lock; /** - * @param $definition HTMLPurifier_ConfigSchema that defines what directives - * are allowed. + * Constructor + * @param HTMLPurifier_ConfigSchema $definition ConfigSchema that defines + * what directives are allowed. + * @param HTMLPurifier_PropertyList $parent */ - public function __construct($definition, $parent = null) { + public function __construct($definition, $parent = null) + { $parent = $parent ? $parent : $definition->defaultPlist; $this->plist = new HTMLPurifier_PropertyList($parent); $this->def = $definition; // keep a copy around for checking @@ -102,10 +117,11 @@ class HTMLPurifier_Config * object. Can be: a HTMLPurifier_Config() object, * an array of directives based on loadArray(), * or a string filename of an ini file. - * @param HTMLPurifier_ConfigSchema Schema object - * @return Configured HTMLPurifier_Config object + * @param HTMLPurifier_ConfigSchema $schema Schema object + * @return HTMLPurifier_Config Configured object */ - public static function create($config, $schema = null) { + public static function create($config, $schema = null) + { if ($config instanceof HTMLPurifier_Config) { // pass-through return $config; @@ -115,57 +131,79 @@ class HTMLPurifier_Config } else { $ret = new HTMLPurifier_Config($schema); } - if (is_string($config)) $ret->loadIni($config); - elseif (is_array($config)) $ret->loadArray($config); + if (is_string($config)) { + $ret->loadIni($config); + } elseif (is_array($config)) $ret->loadArray($config); return $ret; } /** * Creates a new config object that inherits from a previous one. - * @param HTMLPurifier_Config $config Configuration object to inherit - * from. + * @param HTMLPurifier_Config $config Configuration object to inherit from. * @return HTMLPurifier_Config object with $config as its parent. */ - public static function inherit(HTMLPurifier_Config $config) { + public static function inherit(HTMLPurifier_Config $config) + { return new HTMLPurifier_Config($config->def, $config->plist); } /** * Convenience constructor that creates a default configuration object. - * @return Default HTMLPurifier_Config object. + * @return HTMLPurifier_Config default object. */ - public static function createDefault() { + public static function createDefault() + { $definition = HTMLPurifier_ConfigSchema::instance(); $config = new HTMLPurifier_Config($definition); return $config; } /** - * Retreives a value from the configuration. - * @param $key String key + * Retrieves a value from the configuration. + * + * @param string $key String key + * @param mixed $a + * + * @return mixed */ - public function get($key, $a = null) { + public function get($key, $a = null) + { if ($a !== null) { - $this->triggerError("Using deprecated API: use \$config->get('$key.$a') instead", E_USER_WARNING); + $this->triggerError( + "Using deprecated API: use \$config->get('$key.$a') instead", + E_USER_WARNING + ); $key = "$key.$a"; } - if (!$this->finalized) $this->autoFinalize(); + if (!$this->finalized) { + $this->autoFinalize(); + } if (!isset($this->def->info[$key])) { // can't add % due to SimpleTest bug - $this->triggerError('Cannot retrieve value of undefined directive ' . htmlspecialchars($key), - E_USER_WARNING); + $this->triggerError( + 'Cannot retrieve value of undefined directive ' . htmlspecialchars($key), + E_USER_WARNING + ); return; } if (isset($this->def->info[$key]->isAlias)) { $d = $this->def->info[$key]; - $this->triggerError('Cannot get value from aliased directive, use real name ' . $d->key, - E_USER_ERROR); + $this->triggerError( + 'Cannot get value from aliased directive, use real name ' . $d->key, + E_USER_ERROR + ); return; } if ($this->lock) { list($ns) = explode('.', $key); if ($ns !== $this->lock) { - $this->triggerError('Cannot get value of namespace ' . $ns . ' when lock for ' . $this->lock . ' is active, this probably indicates a Definition setup method is accessing directives that are not within its namespace', E_USER_ERROR); + $this->triggerError( + 'Cannot get value of namespace ' . $ns . ' when lock for ' . + $this->lock . + ' is active, this probably indicates a Definition setup method ' . + 'is accessing directives that are not within its namespace', + E_USER_ERROR + ); return; } } @@ -173,53 +211,73 @@ class HTMLPurifier_Config } /** - * Retreives an array of directives to values from a given namespace - * @param $namespace String namespace + * Retrieves an array of directives to values from a given namespace + * + * @param string $namespace String namespace + * + * @return array */ - public function getBatch($namespace) { - if (!$this->finalized) $this->autoFinalize(); + public function getBatch($namespace) + { + if (!$this->finalized) { + $this->autoFinalize(); + } $full = $this->getAll(); if (!isset($full[$namespace])) { - $this->triggerError('Cannot retrieve undefined namespace ' . htmlspecialchars($namespace), - E_USER_WARNING); + $this->triggerError( + 'Cannot retrieve undefined namespace ' . + htmlspecialchars($namespace), + E_USER_WARNING + ); return; } return $full[$namespace]; } /** - * Returns a md5 signature of a segment of the configuration object + * Returns a SHA-1 signature of a segment of the configuration object * that uniquely identifies that particular configuration + * + * @param string $namespace Namespace to get serial for + * + * @return string * @note Revision is handled specially and is removed from the batch * before processing! - * @param $namespace Namespace to get serial for */ - public function getBatchSerial($namespace) { + public function getBatchSerial($namespace) + { if (empty($this->serials[$namespace])) { $batch = $this->getBatch($namespace); unset($batch['DefinitionRev']); - $this->serials[$namespace] = md5(serialize($batch)); + $this->serials[$namespace] = sha1(serialize($batch)); } return $this->serials[$namespace]; } /** - * Returns a md5 signature for the entire configuration object + * Returns a SHA-1 signature for the entire configuration object * that uniquely identifies that particular configuration + * + * @return string */ - public function getSerial() { + public function getSerial() + { if (empty($this->serial)) { - $this->serial = md5(serialize($this->getAll())); + $this->serial = sha1(serialize($this->getAll())); } return $this->serial; } /** * Retrieves all directives, organized by namespace + * * @warning This is a pretty inefficient function, avoid if you can */ - public function getAll() { - if (!$this->finalized) $this->autoFinalize(); + public function getAll() + { + if (!$this->finalized) { + $this->autoFinalize(); + } $ret = array(); foreach ($this->plist->squash() as $name => $value) { list($ns, $key) = explode('.', $name, 2); @@ -230,10 +288,13 @@ class HTMLPurifier_Config /** * Sets a value to configuration. - * @param $key String key - * @param $value Mixed value + * + * @param string $key key + * @param mixed $value value + * @param mixed $a */ - public function set($key, $value, $a = null) { + public function set($key, $value, $a = null) + { if (strpos($key, '.') === false) { $namespace = $key; $directive = $value; @@ -243,18 +304,25 @@ class HTMLPurifier_Config } else { list($namespace) = explode('.', $key); } - if ($this->isFinalized('Cannot set directive after finalization')) return; + if ($this->isFinalized('Cannot set directive after finalization')) { + return; + } if (!isset($this->def->info[$key])) { - $this->triggerError('Cannot set undefined directive ' . htmlspecialchars($key) . ' to value', - E_USER_WARNING); + $this->triggerError( + 'Cannot set undefined directive ' . htmlspecialchars($key) . ' to value', + E_USER_WARNING + ); return; } $def = $this->def->info[$key]; if (isset($def->isAlias)) { if ($this->aliasMode) { - $this->triggerError('Double-aliases not allowed, please fix '. - 'ConfigSchema bug with' . $key, E_USER_ERROR); + $this->triggerError( + 'Double-aliases not allowed, please fix '. + 'ConfigSchema bug with' . $key, + E_USER_ERROR + ); return; } $this->aliasMode = true; @@ -278,7 +346,11 @@ class HTMLPurifier_Config try { $value = $this->parser->parse($value, $type, $allow_null); } catch (HTMLPurifier_VarParserException $e) { - $this->triggerError('Value for ' . $key . ' is of invalid type, should be ' . HTMLPurifier_VarParser::getTypeName($type), E_USER_WARNING); + $this->triggerError( + 'Value for ' . $key . ' is of invalid type, should be ' . + HTMLPurifier_VarParser::getTypeName($type), + E_USER_WARNING + ); return; } if (is_string($value) && is_object($def)) { @@ -288,8 +360,11 @@ class HTMLPurifier_Config } // check to see if the value is allowed if (isset($def->allowed) && !isset($def->allowed[$value])) { - $this->triggerError('Value not supported, valid values are: ' . - $this->_listify($def->allowed), E_USER_WARNING); + $this->triggerError( + 'Value not supported, valid values are: ' . + $this->_listify($def->allowed), + E_USER_WARNING + ); return; } } @@ -307,38 +382,102 @@ class HTMLPurifier_Config /** * Convenience function for error reporting + * + * @param array $lookup + * + * @return string */ - private function _listify($lookup) { + private function _listify($lookup) + { $list = array(); - foreach ($lookup as $name => $b) $list[] = $name; + foreach ($lookup as $name => $b) { + $list[] = $name; + } return implode(', ', $list); } /** * Retrieves object reference to the HTML definition. - * @param $raw Return a copy that has not been setup yet. Must be + * + * @param bool $raw Return a copy that has not been setup yet. Must be * called before it's been setup, otherwise won't work. - */ - public function getHTMLDefinition($raw = false) { - return $this->getDefinition('HTML', $raw); + * @param bool $optimized If true, this method may return null, to + * indicate that a cached version of the modified + * definition object is available and no further edits + * are necessary. Consider using + * maybeGetRawHTMLDefinition, which is more explicitly + * named, instead. + * + * @return HTMLPurifier_HTMLDefinition + */ + public function getHTMLDefinition($raw = false, $optimized = false) + { + return $this->getDefinition('HTML', $raw, $optimized); } /** * Retrieves object reference to the CSS definition - * @param $raw Return a copy that has not been setup yet. Must be + * + * @param bool $raw Return a copy that has not been setup yet. Must be * called before it's been setup, otherwise won't work. - */ - public function getCSSDefinition($raw = false) { - return $this->getDefinition('CSS', $raw); + * @param bool $optimized If true, this method may return null, to + * indicate that a cached version of the modified + * definition object is available and no further edits + * are necessary. Consider using + * maybeGetRawCSSDefinition, which is more explicitly + * named, instead. + * + * @return HTMLPurifier_CSSDefinition + */ + public function getCSSDefinition($raw = false, $optimized = false) + { + return $this->getDefinition('CSS', $raw, $optimized); + } + + /** + * Retrieves object reference to the URI definition + * + * @param bool $raw Return a copy that has not been setup yet. Must be + * called before it's been setup, otherwise won't work. + * @param bool $optimized If true, this method may return null, to + * indicate that a cached version of the modified + * definition object is available and no further edits + * are necessary. Consider using + * maybeGetRawURIDefinition, which is more explicitly + * named, instead. + * + * @return HTMLPurifier_URIDefinition + */ + public function getURIDefinition($raw = false, $optimized = false) + { + return $this->getDefinition('URI', $raw, $optimized); } /** * Retrieves a definition - * @param $type Type of definition: HTML, CSS, etc - * @param $raw Whether or not definition should be returned raw - */ - public function getDefinition($type, $raw = false) { - if (!$this->finalized) $this->autoFinalize(); + * + * @param string $type Type of definition: HTML, CSS, etc + * @param bool $raw Whether or not definition should be returned raw + * @param bool $optimized Only has an effect when $raw is true. Whether + * or not to return null if the result is already present in + * the cache. This is off by default for backwards + * compatibility reasons, but you need to do things this + * way in order to ensure that caching is done properly. + * Check out enduser-customize.html for more details. + * We probably won't ever change this default, as much as the + * maybe semantics is the "right thing to do." + * + * @throws HTMLPurifier_Exception + * @return HTMLPurifier_Definition + */ + public function getDefinition($type, $raw = false, $optimized = false) + { + if ($optimized && !$raw) { + throw new HTMLPurifier_Exception("Cannot set optimized = true when raw = false"); + } + if (!$this->finalized) { + $this->autoFinalize(); + } // temporarily suspend locks, so we can handle recursive definition calls $lock = $this->lock; $this->lock = null; @@ -346,61 +485,193 @@ class HTMLPurifier_Config $cache = $factory->create($type, $this); $this->lock = $lock; if (!$raw) { - // see if we can quickly supply a definition + // full definition + // --------------- + // check if definition is in memory + if (!empty($this->definitions[$type])) { + $def = $this->definitions[$type]; + // check if the definition is setup + if ($def->setup) { + return $def; + } else { + $def->setup($this); + if ($def->optimized) { + $cache->add($def, $this); + } + return $def; + } + } + // check if definition is in cache + $def = $cache->get($this); + if ($def) { + // definition in cache, save to memory and return it + $this->definitions[$type] = $def; + return $def; + } + // initialize it + $def = $this->initDefinition($type); + // set it up + $this->lock = $type; + $def->setup($this); + $this->lock = null; + // save in cache + $cache->add($def, $this); + // return it + return $def; + } else { + // raw definition + // -------------- + // check preconditions + $def = null; + if ($optimized) { + if (is_null($this->get($type . '.DefinitionID'))) { + // fatally error out if definition ID not set + throw new HTMLPurifier_Exception( + "Cannot retrieve raw version without specifying %$type.DefinitionID" + ); + } + } if (!empty($this->definitions[$type])) { - if (!$this->definitions[$type]->setup) { - $this->definitions[$type]->setup($this); - $cache->set($this->definitions[$type], $this); + $def = $this->definitions[$type]; + if ($def->setup && !$optimized) { + $extra = $this->chatty ? + " (try moving this code block earlier in your initialization)" : + ""; + throw new HTMLPurifier_Exception( + "Cannot retrieve raw definition after it has already been setup" . + $extra + ); + } + if ($def->optimized === null) { + $extra = $this->chatty ? " (try flushing your cache)" : ""; + throw new HTMLPurifier_Exception( + "Optimization status of definition is unknown" . $extra + ); + } + if ($def->optimized !== $optimized) { + $msg = $optimized ? "optimized" : "unoptimized"; + $extra = $this->chatty ? + " (this backtrace is for the first inconsistent call, which was for a $msg raw definition)" + : ""; + throw new HTMLPurifier_Exception( + "Inconsistent use of optimized and unoptimized raw definition retrievals" . $extra + ); } - return $this->definitions[$type]; } - // memory check missed, try cache - $this->definitions[$type] = $cache->get($this); - if ($this->definitions[$type]) { - // definition in cache, return it - return $this->definitions[$type]; + // check if definition was in memory + if ($def) { + if ($def->setup) { + // invariant: $optimized === true (checked above) + return null; + } else { + return $def; + } } - } elseif ( - !empty($this->definitions[$type]) && - !$this->definitions[$type]->setup - ) { - // raw requested, raw in memory, quick return - return $this->definitions[$type]; + // if optimized, check if definition was in cache + // (because we do the memory check first, this formulation + // is prone to cache slamming, but I think + // guaranteeing that either /all/ of the raw + // setup code or /none/ of it is run is more important.) + if ($optimized) { + // This code path only gets run once; once we put + // something in $definitions (which is guaranteed by the + // trailing code), we always short-circuit above. + $def = $cache->get($this); + if ($def) { + // save the full definition for later, but don't + // return it yet + $this->definitions[$type] = $def; + return null; + } + } + // check invariants for creation + if (!$optimized) { + if (!is_null($this->get($type . '.DefinitionID'))) { + if ($this->chatty) { + $this->triggerError( + 'Due to a documentation error in previous version of HTML Purifier, your ' . + 'definitions are not being cached. If this is OK, you can remove the ' . + '%$type.DefinitionRev and %$type.DefinitionID declaration. Otherwise, ' . + 'modify your code to use maybeGetRawDefinition, and test if the returned ' . + 'value is null before making any edits (if it is null, that means that a ' . + 'cached version is available, and no raw operations are necessary). See ' . + '<a href="http://htmlpurifier.org/docs/enduser-customize.html#optimized">' . + 'Customize</a> for more details', + E_USER_WARNING + ); + } else { + $this->triggerError( + "Useless DefinitionID declaration", + E_USER_WARNING + ); + } + } + } + // initialize it + $def = $this->initDefinition($type); + $def->optimized = $optimized; + return $def; } + throw new HTMLPurifier_Exception("The impossible happened!"); + } + + /** + * Initialise definition + * + * @param string $type What type of definition to create + * + * @return HTMLPurifier_CSSDefinition|HTMLPurifier_HTMLDefinition|HTMLPurifier_URIDefinition + * @throws HTMLPurifier_Exception + */ + private function initDefinition($type) + { // quick checks failed, let's create the object if ($type == 'HTML') { - $this->definitions[$type] = new HTMLPurifier_HTMLDefinition(); + $def = new HTMLPurifier_HTMLDefinition(); } elseif ($type == 'CSS') { - $this->definitions[$type] = new HTMLPurifier_CSSDefinition(); + $def = new HTMLPurifier_CSSDefinition(); } elseif ($type == 'URI') { - $this->definitions[$type] = new HTMLPurifier_URIDefinition(); + $def = new HTMLPurifier_URIDefinition(); } else { - throw new HTMLPurifier_Exception("Definition of $type type not supported"); + throw new HTMLPurifier_Exception( + "Definition of $type type not supported" + ); } - // quick abort if raw - if ($raw) { - if (is_null($this->get($type . '.DefinitionID'))) { - // fatally error out if definition ID not set - throw new HTMLPurifier_Exception("Cannot retrieve raw version without specifying %$type.DefinitionID"); - } - return $this->definitions[$type]; - } - // set it up - $this->lock = $type; - $this->definitions[$type]->setup($this); - $this->lock = null; - // save in cache - $cache->set($this->definitions[$type], $this); - return $this->definitions[$type]; + $this->definitions[$type] = $def; + return $def; + } + + public function maybeGetRawDefinition($name) + { + return $this->getDefinition($name, true, true); + } + + public function maybeGetRawHTMLDefinition() + { + return $this->getDefinition('HTML', true, true); + } + + public function maybeGetRawCSSDefinition() + { + return $this->getDefinition('CSS', true, true); + } + + public function maybeGetRawURIDefinition() + { + return $this->getDefinition('URI', true, true); } /** * Loads configuration values from an array with the following structure: * Namespace.Directive => Value - * @param $config_array Configuration associative array + * + * @param array $config_array Configuration associative array */ - public function loadArray($config_array) { - if ($this->isFinalized('Cannot load directives after finalization')) return; + public function loadArray($config_array) + { + if ($this->isFinalized('Cannot load directives after finalization')) { + return; + } foreach ($config_array as $key => $value) { $key = str_replace('_', '.', $key); if (strpos($key, '.') !== false) { @@ -408,8 +679,8 @@ class HTMLPurifier_Config } else { $namespace = $key; $namespace_values = $value; - foreach ($namespace_values as $directive => $value) { - $this->set($namespace .'.'. $directive, $value); + foreach ($namespace_values as $directive => $value2) { + $this->set($namespace .'.'. $directive, $value2); } } } @@ -419,40 +690,55 @@ class HTMLPurifier_Config * Returns a list of array(namespace, directive) for all directives * that are allowed in a web-form context as per an allowed * namespaces/directives list. - * @param $allowed List of allowed namespaces/directives - */ - public static function getAllowedDirectivesForForm($allowed, $schema = null) { + * + * @param array $allowed List of allowed namespaces/directives + * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy + * + * @return array + */ + public static function getAllowedDirectivesForForm($allowed, $schema = null) + { if (!$schema) { $schema = HTMLPurifier_ConfigSchema::instance(); } if ($allowed !== true) { - if (is_string($allowed)) $allowed = array($allowed); - $allowed_ns = array(); - $allowed_directives = array(); - $blacklisted_directives = array(); - foreach ($allowed as $ns_or_directive) { - if (strpos($ns_or_directive, '.') !== false) { - // directive - if ($ns_or_directive[0] == '-') { - $blacklisted_directives[substr($ns_or_directive, 1)] = true; - } else { - $allowed_directives[$ns_or_directive] = true; - } - } else { - // namespace - $allowed_ns[$ns_or_directive] = true; - } - } + if (is_string($allowed)) { + $allowed = array($allowed); + } + $allowed_ns = array(); + $allowed_directives = array(); + $blacklisted_directives = array(); + foreach ($allowed as $ns_or_directive) { + if (strpos($ns_or_directive, '.') !== false) { + // directive + if ($ns_or_directive[0] == '-') { + $blacklisted_directives[substr($ns_or_directive, 1)] = true; + } else { + $allowed_directives[$ns_or_directive] = true; + } + } else { + // namespace + $allowed_ns[$ns_or_directive] = true; + } + } } $ret = array(); foreach ($schema->info as $key => $def) { list($ns, $directive) = explode('.', $key, 2); if ($allowed !== true) { - if (isset($blacklisted_directives["$ns.$directive"])) continue; - if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) continue; + if (isset($blacklisted_directives["$ns.$directive"])) { + continue; + } + if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) { + continue; + } + } + if (isset($def->isAlias)) { + continue; + } + if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') { + continue; } - if (isset($def->isAlias)) continue; - if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') continue; $ret[] = array($ns, $directive); } return $ret; @@ -461,13 +747,17 @@ class HTMLPurifier_Config /** * Loads configuration values from $_GET/$_POST that were posted * via ConfigForm - * @param $array $_GET or $_POST array to import - * @param $index Index/name that the config variables are in - * @param $allowed List of allowed namespaces/directives - * @param $mq_fix Boolean whether or not to enable magic quotes fix - * @param $schema Instance of HTMLPurifier_ConfigSchema to use, if not global copy - */ - public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) { + * + * @param array $array $_GET or $_POST array to import + * @param string|bool $index Index/name that the config variables are in + * @param array|bool $allowed List of allowed namespaces/directives + * @param bool $mq_fix Boolean whether or not to enable magic quotes fix + * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy + * + * @return mixed + */ + public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) + { $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema); $config = HTMLPurifier_Config::create($ret, $schema); return $config; @@ -475,9 +765,14 @@ class HTMLPurifier_Config /** * Merges in configuration values from $_GET/$_POST to object. NOT STATIC. - * @note Same parameters as loadArrayFromForm - */ - public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true) { + * + * @param array $array $_GET or $_POST array to import + * @param string|bool $index Index/name that the config variables are in + * @param array|bool $allowed List of allowed namespaces/directives + * @param bool $mq_fix Boolean whether or not to enable magic quotes fix + */ + public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true) + { $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def); $this->loadArray($ret); } @@ -485,9 +780,20 @@ class HTMLPurifier_Config /** * Prepares an array from a form into something usable for the more * strict parts of HTMLPurifier_Config - */ - public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) { - if ($index !== false) $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array(); + * + * @param array $array $_GET or $_POST array to import + * @param string|bool $index Index/name that the config variables are in + * @param array|bool $allowed List of allowed namespaces/directives + * @param bool $mq_fix Boolean whether or not to enable magic quotes fix + * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy + * + * @return array + */ + public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) + { + if ($index !== false) { + $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array(); + } $mq = $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc(); $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema); @@ -499,7 +805,9 @@ class HTMLPurifier_Config $ret[$ns][$directive] = null; continue; } - if (!isset($array[$skey])) continue; + if (!isset($array[$skey])) { + continue; + } $value = $mq ? stripslashes($array[$skey]) : $array[$skey]; $ret[$ns][$directive] = $value; } @@ -508,19 +816,27 @@ class HTMLPurifier_Config /** * Loads configuration values from an ini file - * @param $filename Name of ini file + * + * @param string $filename Name of ini file */ - public function loadIni($filename) { - if ($this->isFinalized('Cannot load directives after finalization')) return; + public function loadIni($filename) + { + if ($this->isFinalized('Cannot load directives after finalization')) { + return; + } $array = parse_ini_file($filename, true); $this->loadArray($array); } /** * Checks whether or not the configuration object is finalized. - * @param $error String error message, or false for no error + * + * @param string|bool $error String error message, or false for no error + * + * @return bool */ - public function isFinalized($error = false) { + public function isFinalized($error = false) + { if ($this->finalized && $error) { $this->triggerError($error, E_USER_ERROR); } @@ -531,7 +847,8 @@ class HTMLPurifier_Config * Finalizes configuration only if auto finalize is on and not * already finalized */ - public function autoFinalize() { + public function autoFinalize() + { if ($this->autoFinalize) { $this->finalize(); } else { @@ -542,24 +859,35 @@ class HTMLPurifier_Config /** * Finalizes a configuration object, prohibiting further change */ - public function finalize() { + public function finalize() + { $this->finalized = true; - unset($this->parser); + $this->parser = null; } /** * Produces a nicely formatted error message by supplying the - * stack frame information from two levels up and OUTSIDE of - * HTMLPurifier_Config. + * stack frame information OUTSIDE of HTMLPurifier_Config. + * + * @param string $msg An error message + * @param int $no An error number */ - protected function triggerError($msg, $no) { + protected function triggerError($msg, $no) + { // determine previous stack frame - $backtrace = debug_backtrace(); - if ($this->chatty && isset($backtrace[1])) { - $frame = $backtrace[1]; - $extra = " on line {$frame['line']} in file {$frame['file']}"; - } else { - $extra = ''; + $extra = ''; + if ($this->chatty) { + $trace = debug_backtrace(); + // zip(tail(trace), trace) -- but PHP is not Haskell har har + for ($i = 0, $c = count($trace); $i < $c - 1; $i++) { + // XXX this is not correct on some versions of HTML Purifier + if ($trace[$i + 1]['class'] === 'HTMLPurifier_Config') { + continue; + } + $frame = $trace[$i]; + $extra = " invoked on line {$frame['line']} in file {$frame['file']}"; + break; + } } trigger_error($msg . $extra, $no); } @@ -567,8 +895,11 @@ class HTMLPurifier_Config /** * Returns a serialized form of the configuration object that can * be reconstituted. + * + * @return string */ - public function serialize() { + public function serialize() + { $this->getDefinition('HTML'); $this->getDefinition('CSS'); $this->getDefinition('URI'); |