3 require_once 'HTMLPurifier/ConfigSchema.php';
6 require_once 'HTMLPurifier/HTMLDefinition.php';
7 require_once 'HTMLPurifier/CSSDefinition.php';
8 require_once 'HTMLPurifier/Doctype.php';
9 require_once 'HTMLPurifier/DefinitionCacheFactory.php';
11 // accomodations for versions earlier than 4.3.10 and 5.0.2
12 // borrowed from PHP_Compat, LGPL licensed, by Aidan Lister <aidan@php.net>
13 if (!defined('PHP_EOL')) {
14 switch (strtoupper(substr(PHP_OS
, 0, 3))) {
16 define('PHP_EOL', "\r\n");
19 define('PHP_EOL', "\r");
22 define('PHP_EOL', "\n");
27 * Configuration object that triggers customizable behavior.
29 * @warning This class is strongly defined: that means that the class
30 * will fail if an undefined directive is retrieved or set.
32 * @note Many classes that could (although many times don't) use the
33 * configuration object make it a mandatory parameter. This is
34 * because a configuration object should always be forwarded,
35 * otherwise, you run the risk of missing a parameter and then
36 * being stumped when a configuration directive doesn't work.
38 class HTMLPurifier_Config
42 * HTML Purifier's version
44 var $version = '2.0.0';
47 * Two-level associative array of configuration directives
52 * Reference HTMLPurifier_ConfigSchema for value checking
57 * Indexed array of definitions
62 * Bool indicator whether or not config is finalized
64 var $finalized = false;
67 * Bool indicator whether or not to automatically finalize
68 * the object if a read operation is done
70 var $autoFinalize = true;
73 * Namespace indexed array of serials for specific namespaces (see
74 * getSerial for more info).
76 var $serials = array();
79 * @param $definition HTMLPurifier_ConfigSchema that defines what directives
82 function HTMLPurifier_Config(&$definition) {
83 $this->conf
= $definition->defaults
; // set up, copy in defaults
84 $this->def
= $definition; // keep a copy around for checking
88 * Convenience constructor that creates a config object based on a mixed var
90 * @param mixed $config Variable that defines the state of the config
91 * object. Can be: a HTMLPurifier_Config() object,
92 * an array of directives based on loadArray(),
93 * or a string filename of an ini file.
94 * @return Configured HTMLPurifier_Config object
96 function create($config) {
97 if (is_a($config, 'HTMLPurifier_Config')) {
101 $ret = HTMLPurifier_Config
::createDefault();
102 if (is_string($config)) $ret->loadIni($config);
103 elseif (is_array($config)) $ret->loadArray($config);
104 if (isset($revision)) $ret->revision
= $revision;
109 * Convenience constructor that creates a default configuration object.
111 * @return Default HTMLPurifier_Config object.
113 function createDefault() {
114 $definition =& HTMLPurifier_ConfigSchema
::instance();
115 $config = new HTMLPurifier_Config($definition);
120 * Retreives a value from the configuration.
121 * @param $namespace String namespace
122 * @param $key String key
124 function get($namespace, $key, $from_alias = false) {
125 if (!$this->finalized
&& $this->autoFinalize
) $this->finalize();
126 if (!isset($this->def
->info
[$namespace][$key])) {
127 // can't add % due to SimpleTest bug
128 trigger_error('Cannot retrieve value of undefined directive ' . htmlspecialchars("$namespace.$key"),
132 if ($this->def
->info
[$namespace][$key]->class == 'alias') {
133 $d = $this->def
->info
[$namespace][$key];
134 trigger_error('Cannot get value from aliased directive, use real name ' . $d->namespace . '.' . $d->name
,
138 return $this->conf
[$namespace][$key];
142 * Retreives an array of directives to values from a given namespace
143 * @param $namespace String namespace
145 function getBatch($namespace) {
146 if (!$this->finalized
&& $this->autoFinalize
) $this->finalize();
147 if (!isset($this->def
->info
[$namespace])) {
148 trigger_error('Cannot retrieve undefined namespace ' . htmlspecialchars($namespace),
152 return $this->conf
[$namespace];
156 * Returns a md5 signature of a segment of the configuration object
157 * that uniquely identifies that particular configuration
158 * @param $namespace Namespace to get serial for
160 function getBatchSerial($namespace) {
161 if (empty($this->serials
[$namespace])) {
162 $this->serials
[$namespace] = md5(serialize($this->getBatch($namespace)));
164 return $this->serials
[$namespace];
168 * Retrieves all directives, organized by namespace
171 if (!$this->finalized
&& $this->autoFinalize
) $this->finalize();
176 * Sets a value to configuration.
177 * @param $namespace String namespace
178 * @param $key String key
179 * @param $value Mixed value
181 function set($namespace, $key, $value, $from_alias = false) {
182 if ($this->isFinalized('Cannot set directive after finalization')) return;
183 if (!isset($this->def
->info
[$namespace][$key])) {
184 trigger_error('Cannot set undefined directive ' . htmlspecialchars("$namespace.$key") . ' to value',
188 if ($this->def
->info
[$namespace][$key]->class == 'alias') {
190 trigger_error('Double-aliases not allowed, please fix '.
191 'ConfigSchema bug with' . "$namespace.$key");
193 $this->set($this->def
->info
[$namespace][$key]->namespace,
194 $this->def
->info
[$namespace][$key]->name
,
198 $value = $this->def
->validate(
200 $type = $this->def
->info
[$namespace][$key]->type
,
201 $this->def
->info
[$namespace][$key]->allow_null
203 if (is_string($value)) {
204 // resolve value alias if defined
205 if (isset($this->def
->info
[$namespace][$key]->aliases
[$value])) {
206 $value = $this->def
->info
[$namespace][$key]->aliases
[$value];
208 if ($this->def
->info
[$namespace][$key]->allowed
!== true) {
209 // check to see if the value is allowed
210 if (!isset($this->def
->info
[$namespace][$key]->allowed
[$value])) {
211 trigger_error('Value not supported, valid values are: ' .
212 $this->_listify($this->def
->info
[$namespace][$key]->allowed
), E_USER_WARNING
);
217 if ($this->def
->isError($value)) {
218 trigger_error('Value for ' . "$namespace.$key" . ' is of invalid type, should be ' . $type, E_USER_WARNING
);
221 $this->conf
[$namespace][$key] = $value;
223 // reset definitions if the directives they depend on changed
224 // this is a very costly process, so it's discouraged
226 if ($namespace == 'HTML' ||
$namespace == 'CSS') {
227 $this->definitions
[$namespace] = null;
230 $this->serials
[$namespace] = false;
234 * Convenience function for error reporting
237 function _listify($lookup) {
239 foreach ($lookup as $name => $b) $list[] = $name;
240 return implode(', ', $list);
244 * Retrieves reference to the HTML definition.
245 * @param $raw Return a copy that has not been setup yet. Must be
246 * called before it's been setup, otherwise won't work.
248 function &getHTMLDefinition($raw = false) {
249 return $this->getDefinition('HTML', $raw);
253 * Retrieves reference to the CSS definition
255 function &getCSSDefinition($raw = false) {
256 return $this->getDefinition('CSS', $raw);
260 * Retrieves a definition
261 * @param $type Type of definition: HTML, CSS, etc
262 * @param $raw Whether or not definition should be returned raw
264 function &getDefinition($type, $raw = false) {
265 if (!$this->finalized
&& $this->autoFinalize
) $this->finalize();
266 $factory = HTMLPurifier_DefinitionCacheFactory
::instance();
267 $cache = $factory->create($type, $this);
269 // see if we can quickly supply a definition
270 if (!empty($this->definitions
[$type])) {
271 if (!$this->definitions
[$type]->setup
) {
272 $this->definitions
[$type]->setup($this);
274 return $this->definitions
[$type];
276 // memory check missed, try cache
277 $this->definitions
[$type] = $cache->get($this);
278 if ($this->definitions
[$type]) {
279 // definition in cache, return it
280 return $this->definitions
[$type];
283 !empty($this->definitions
[$type]) &&
284 !$this->definitions
[$type]->setup
286 // raw requested, raw in memory, quick return
287 return $this->definitions
[$type];
289 // quick checks failed, let's create the object
290 if ($type == 'HTML') {
291 $this->definitions
[$type] = new HTMLPurifier_HTMLDefinition();
292 } elseif ($type == 'CSS') {
293 $this->definitions
[$type] = new HTMLPurifier_CSSDefinition();
295 trigger_error("Definition of $type type not supported");
299 // quick abort if raw
301 if (is_null($this->get($type, 'DefinitionID'))) {
302 // fatally error out if definition ID not set
303 trigger_error("Cannot retrieve raw version without specifying %$type.DefinitionID", E_USER_ERROR
);
307 return $this->definitions
[$type];
310 $this->definitions
[$type]->setup($this);
312 $cache->set($this->definitions
[$type], $this);
313 return $this->definitions
[$type];
317 * Loads configuration values from an array with the following structure:
318 * Namespace.Directive => Value
319 * @param $config_array Configuration associative array
321 function loadArray($config_array) {
322 if ($this->isFinalized('Cannot load directives after finalization')) return;
323 foreach ($config_array as $key => $value) {
324 $key = str_replace('_', '.', $key);
325 if (strpos($key, '.') !== false) {
327 list($namespace, $directive) = explode('.', $key);
328 $this->set($namespace, $directive, $value);
331 $namespace_values = $value;
332 foreach ($namespace_values as $directive => $value) {
333 $this->set($namespace, $directive, $value);
340 * Loads configuration values from $_GET/$_POST that were posted
342 * @param $array $_GET or $_POST array to import
343 * @param $index Index/name that the config variables are in
344 * @param $mq_fix Boolean whether or not to enable magic quotes fix
347 function loadArrayFromForm($array, $index, $mq_fix = true) {
348 $array = (isset($array[$index]) && is_array($array[$index])) ?
$array[$index] : array();
349 $mq = get_magic_quotes_gpc() && $mq_fix;
350 foreach ($array as $key => $value) {
351 if (!strncmp($key, 'Null_', 5) && !empty($value)) {
352 unset($array[substr($key, 5)]);
355 if ($mq) $array[$key] = stripslashes($value);
357 return @HTMLPurifier_Config
::create($array);
361 * Loads configuration values from an ini file
362 * @param $filename Name of ini file
364 function loadIni($filename) {
365 if ($this->isFinalized('Cannot load directives after finalization')) return;
366 $array = parse_ini_file($filename, true);
367 $this->loadArray($array);
371 * Checks whether or not the configuration object is finalized.
372 * @param $error String error message, or false for no error
374 function isFinalized($error = false) {
375 if ($this->finalized
&& $error) {
376 trigger_error($error, E_USER_ERROR
);
378 return $this->finalized
;
382 * Finalizes configuration only if auto finalize is on and not
385 function autoFinalize() {
386 if (!$this->finalized
&& $this->autoFinalize
) $this->finalize();
390 * Finalizes a configuration object, prohibiting further change
392 function finalize() {
393 $this->finalized
= true;