root/afridex/plugins/Flutter/purifier_lib/HTMLPurifier/Config.php @ 23

Revision 21, 18.2 kB (checked in by admin, 18 years ago)
Line 
1<?php
2
3/**
4 * Configuration object that triggers customizable behavior.
5 *
6 * @warning This class is strongly defined: that means that the class
7 *          will fail if an undefined directive is retrieved or set.
8 *
9 * @note Many classes that could (although many times don't) use the
10 *       configuration object make it a mandatory parameter.  This is
11 *       because a configuration object should always be forwarded,
12 *       otherwise, you run the risk of missing a parameter and then
13 *       being stumped when a configuration directive doesn't work.
14 *
15 * @todo Reconsider some of the public member variables
16 */
17class HTMLPurifier_Config
18{
19   
20    /**
21     * HTML Purifier's version
22     */
23    public $version = '3.1.0';
24   
25    /**
26     * Bool indicator whether or not to automatically finalize
27     * the object if a read operation is done
28     */
29    public $autoFinalize = true;
30   
31    // protected member variables
32   
33    /**
34     * Namespace indexed array of serials for specific namespaces (see
35     * getSerial() for more info).
36     */
37    protected $serials = array();
38   
39    /**
40     * Serial for entire configuration object
41     */
42    protected $serial;
43   
44    /**
45     * Two-level associative array of configuration directives
46     */
47    protected $conf;
48   
49    /**
50     * Parser for variables
51     */
52    protected $parser;
53   
54    /**
55     * Reference HTMLPurifier_ConfigSchema for value checking
56     * @note This is public for introspective purposes. Please don't
57     *       abuse!
58     */
59    public $def;
60   
61    /**
62     * Indexed array of definitions
63     */
64    protected $definitions;
65   
66    /**
67     * Bool indicator whether or not config is finalized
68     */
69    protected $finalized = false;
70   
71    /**
72     * @param $definition HTMLPurifier_ConfigSchema that defines what directives
73     *                    are allowed.
74     */
75    public function __construct($definition) {
76        $this->conf = $definition->defaults; // set up, copy in defaults
77        $this->def  = $definition; // keep a copy around for checking
78        $this->parser = new HTMLPurifier_VarParser_Flexible();
79    }
80   
81    /**
82     * Convenience constructor that creates a config object based on a mixed var
83     * @param mixed $config Variable that defines the state of the config
84     *                      object. Can be: a HTMLPurifier_Config() object,
85     *                      an array of directives based on loadArray(),
86     *                      or a string filename of an ini file.
87     * @param HTMLPurifier_ConfigSchema Schema object
88     * @return Configured HTMLPurifier_Config object
89     */
90    public static function create($config, $schema = null) {
91        if ($config instanceof HTMLPurifier_Config) {
92            // pass-through
93            return $config;
94        }
95        if (!$schema) {
96            $ret = HTMLPurifier_Config::createDefault();
97        } else {
98            $ret = new HTMLPurifier_Config($schema);
99        }
100        if (is_string($config)) $ret->loadIni($config);
101        elseif (is_array($config)) $ret->loadArray($config);
102        return $ret;
103    }
104   
105    /**
106     * Convenience constructor that creates a default configuration object.
107     * @return Default HTMLPurifier_Config object.
108     */
109    public static function createDefault() {
110        $definition = HTMLPurifier_ConfigSchema::instance();
111        $config = new HTMLPurifier_Config($definition);
112        return $config;
113    }
114   
115    /**
116     * Retreives a value from the configuration.
117     * @param $namespace String namespace
118     * @param $key String key
119     */
120    public function get($namespace, $key) {
121        if (!$this->finalized && $this->autoFinalize) $this->finalize();
122        if (!isset($this->def->info[$namespace][$key])) {
123            // can't add % due to SimpleTest bug
124            trigger_error('Cannot retrieve value of undefined directive ' . htmlspecialchars("$namespace.$key"),
125                E_USER_WARNING);
126            return;
127        }
128        if ($this->def->info[$namespace][$key]->class == 'alias') {
129            $d = $this->def->info[$namespace][$key];
130            trigger_error('Cannot get value from aliased directive, use real name ' . $d->namespace . '.' . $d->name,
131                E_USER_ERROR);
132            return;
133        }
134        return $this->conf[$namespace][$key];
135    }
136   
137    /**
138     * Retreives an array of directives to values from a given namespace
139     * @param $namespace String namespace
140     */
141    public function getBatch($namespace) {
142        if (!$this->finalized && $this->autoFinalize) $this->finalize();
143        if (!isset($this->def->info[$namespace])) {
144            trigger_error('Cannot retrieve undefined namespace ' . htmlspecialchars($namespace),
145                E_USER_WARNING);
146            return;
147        }
148        return $this->conf[$namespace];
149    }
150   
151    /**
152     * Returns a md5 signature of a segment of the configuration object
153     * that uniquely identifies that particular configuration
154     * @note Revision is handled specially and is removed from the batch
155     *       before processing!
156     * @param $namespace Namespace to get serial for
157     */
158    public function getBatchSerial($namespace) {
159        if (empty($this->serials[$namespace])) {
160            $batch = $this->getBatch($namespace);
161            unset($batch['DefinitionRev']);
162            $this->serials[$namespace] = md5(serialize($batch));
163        }
164        return $this->serials[$namespace];
165    }
166   
167    /**
168     * Returns a md5 signature for the entire configuration object
169     * that uniquely identifies that particular configuration
170     */
171    public function getSerial() {
172        if (empty($this->serial)) {
173            $this->serial = md5(serialize($this->getAll()));
174        }
175        return $this->serial;
176    }
177   
178    /**
179     * Retrieves all directives, organized by namespace
180     */
181    public function getAll() {
182        if (!$this->finalized && $this->autoFinalize) $this->finalize();
183        return $this->conf;
184    }
185   
186    /**
187     * Sets a value to configuration.
188     * @param $namespace String namespace
189     * @param $key String key
190     * @param $value Mixed value
191     */
192    public function set($namespace, $key, $value, $from_alias = false) {
193        if ($this->isFinalized('Cannot set directive after finalization')) return;
194        if (!isset($this->def->info[$namespace][$key])) {
195            trigger_error('Cannot set undefined directive ' . htmlspecialchars("$namespace.$key") . ' to value',
196                E_USER_WARNING);
197            return;
198        }
199        if ($this->def->info[$namespace][$key]->class == 'alias') {
200            if ($from_alias) {
201                trigger_error('Double-aliases not allowed, please fix '.
202                    'ConfigSchema bug with' . "$namespace.$key", E_USER_ERROR);
203                return;
204            }
205            $this->set($new_ns = $this->def->info[$namespace][$key]->namespace,
206                       $new_dir = $this->def->info[$namespace][$key]->name,
207                       $value, true);
208            trigger_error("$namespace.$key is an alias, preferred directive name is $new_ns.$new_dir", E_USER_NOTICE);
209            return;
210        }
211        try {
212            $value = $this->parser->parse(
213                        $value,
214                        $type = $this->def->info[$namespace][$key]->type,
215                        $this->def->info[$namespace][$key]->allow_null
216                     );
217        } catch (HTMLPurifier_VarParserException $e) {
218            trigger_error('Value for ' . "$namespace.$key" . ' is of invalid type, should be ' . $type, E_USER_WARNING);
219            return;
220        }
221        if (is_string($value)) {
222            // resolve value alias if defined
223            if (isset($this->def->info[$namespace][$key]->aliases[$value])) {
224                $value = $this->def->info[$namespace][$key]->aliases[$value];
225            }
226            if ($this->def->info[$namespace][$key]->allowed !== true) {
227                // check to see if the value is allowed
228                if (!isset($this->def->info[$namespace][$key]->allowed[$value])) {
229                    trigger_error('Value not supported, valid values are: ' .
230                        $this->_listify($this->def->info[$namespace][$key]->allowed), E_USER_WARNING);
231                    return;
232                }
233            }
234        }
235        $this->conf[$namespace][$key] = $value;
236       
237        // reset definitions if the directives they depend on changed
238        // this is a very costly process, so it's discouraged
239        // with finalization
240        if ($namespace == 'HTML' || $namespace == 'CSS') {
241            $this->definitions[$namespace] = null;
242        }
243       
244        $this->serials[$namespace] = false;
245    }
246   
247    /**
248     * Convenience function for error reporting
249     */
250    private function _listify($lookup) {
251        $list = array();
252        foreach ($lookup as $name => $b) $list[] = $name;
253        return implode(', ', $list);
254    }
255   
256    /**
257     * Retrieves object reference to the HTML definition.
258     * @param $raw Return a copy that has not been setup yet. Must be
259     *             called before it's been setup, otherwise won't work.
260     */
261    public function getHTMLDefinition($raw = false) {
262        return $this->getDefinition('HTML', $raw);
263    }
264   
265    /**
266     * Retrieves object reference to the CSS definition
267     * @param $raw Return a copy that has not been setup yet. Must be
268     *             called before it's been setup, otherwise won't work.
269     */
270    public function getCSSDefinition($raw = false) {
271        return $this->getDefinition('CSS', $raw);
272    }
273   
274    /**
275     * Retrieves a definition
276     * @param $type Type of definition: HTML, CSS, etc
277     * @param $raw  Whether or not definition should be returned raw
278     */
279    public function getDefinition($type, $raw = false) {
280        if (!$this->finalized && $this->autoFinalize) $this->finalize();
281        $factory = HTMLPurifier_DefinitionCacheFactory::instance();
282        $cache = $factory->create($type, $this);
283        if (!$raw) {
284            // see if we can quickly supply a definition
285            if (!empty($this->definitions[$type])) {
286                if (!$this->definitions[$type]->setup) {
287                    $this->definitions[$type]->setup($this);
288                    $cache->set($this->definitions[$type], $this);
289                }
290                return $this->definitions[$type];
291            }
292            // memory check missed, try cache
293            $this->definitions[$type] = $cache->get($this);
294            if ($this->definitions[$type]) {
295                // definition in cache, return it
296                return $this->definitions[$type];
297            }
298        } elseif (
299            !empty($this->definitions[$type]) &&
300            !$this->definitions[$type]->setup
301        ) {
302            // raw requested, raw in memory, quick return
303            return $this->definitions[$type];
304        }
305        // quick checks failed, let's create the object
306        if ($type == 'HTML') {
307            $this->definitions[$type] = new HTMLPurifier_HTMLDefinition();
308        } elseif ($type == 'CSS') {
309            $this->definitions[$type] = new HTMLPurifier_CSSDefinition();
310        } elseif ($type == 'URI') {
311            $this->definitions[$type] = new HTMLPurifier_URIDefinition();
312        } else {
313            throw new HTMLPurifier_Exception("Definition of $type type not supported");
314        }
315        // quick abort if raw
316        if ($raw) {
317            if (is_null($this->get($type, 'DefinitionID'))) {
318                // fatally error out if definition ID not set
319                throw new HTMLPurifier_Exception("Cannot retrieve raw version without specifying %$type.DefinitionID");
320            }
321            return $this->definitions[$type];
322        }
323        // set it up
324        $this->definitions[$type]->setup($this);
325        // save in cache
326        $cache->set($this->definitions[$type], $this);
327        return $this->definitions[$type];
328    }
329   
330    /**
331     * Loads configuration values from an array with the following structure:
332     * Namespace.Directive => Value
333     * @param $config_array Configuration associative array
334     */
335    public function loadArray($config_array) {
336        if ($this->isFinalized('Cannot load directives after finalization')) return;
337        foreach ($config_array as $key => $value) {
338            $key = str_replace('_', '.', $key);
339            if (strpos($key, '.') !== false) {
340                // condensed form
341                list($namespace, $directive) = explode('.', $key);
342                $this->set($namespace, $directive, $value);
343            } else {
344                $namespace = $key;
345                $namespace_values = $value;
346                foreach ($namespace_values as $directive => $value) {
347                    $this->set($namespace, $directive, $value);
348                }
349            }
350        }
351    }
352   
353    /**
354     * Returns a list of array(namespace, directive) for all directives
355     * that are allowed in a web-form context as per an allowed
356     * namespaces/directives list.
357     * @param $allowed List of allowed namespaces/directives
358     */
359    public static function getAllowedDirectivesForForm($allowed, $schema = null) {
360        if (!$schema) {
361            $schema = HTMLPurifier_ConfigSchema::instance();
362        }
363        if ($allowed !== true) {
364             if (is_string($allowed)) $allowed = array($allowed);
365             $allowed_ns = array();
366             $allowed_directives = array();
367             $blacklisted_directives = array();
368             foreach ($allowed as $ns_or_directive) {
369                 if (strpos($ns_or_directive, '.') !== false) {
370                     // directive
371                     if ($ns_or_directive[0] == '-') {
372                         $blacklisted_directives[substr($ns_or_directive, 1)] = true;
373                     } else {
374                         $allowed_directives[$ns_or_directive] = true;
375                     }
376                 } else {
377                     // namespace
378                     $allowed_ns[$ns_or_directive] = true;
379                 }
380             }
381        }
382        $ret = array();
383        foreach ($schema->info as $ns => $keypairs) {
384            foreach ($keypairs as $directive => $def) {
385                if ($allowed !== true) {
386                    if (isset($blacklisted_directives["$ns.$directive"])) continue;
387                    if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) continue;
388                }
389                if ($def->class == 'alias') continue;
390                if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') continue;
391                $ret[] = array($ns, $directive);
392            }
393        }
394        return $ret;
395    }
396   
397    /**
398     * Loads configuration values from $_GET/$_POST that were posted
399     * via ConfigForm
400     * @param $array $_GET or $_POST array to import
401     * @param $index Index/name that the config variables are in
402     * @param $allowed List of allowed namespaces/directives
403     * @param $mq_fix Boolean whether or not to enable magic quotes fix
404     * @param $schema Instance of HTMLPurifier_ConfigSchema to use, if not global copy
405     */
406    public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) {
407        $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema);
408        $config = HTMLPurifier_Config::create($ret, $schema);
409        return $config;
410    }
411   
412    /**
413     * Merges in configuration values from $_GET/$_POST to object. NOT STATIC.
414     * @note Same parameters as loadArrayFromForm
415     */
416    public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true) {
417         $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def);
418         $this->loadArray($ret);
419    }
420   
421    /**
422     * Prepares an array from a form into something usable for the more
423     * strict parts of HTMLPurifier_Config
424     */
425    public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) {
426        if ($index !== false) $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array();
427        $mq = $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc();
428       
429        $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema);
430        $ret = array();
431        foreach ($allowed as $key) {
432            list($ns, $directive) = $key;
433            $skey = "$ns.$directive";
434            if (!empty($array["Null_$skey"])) {
435                $ret[$ns][$directive] = null;
436                continue;
437            }
438            if (!isset($array[$skey])) continue;
439            $value = $mq ? stripslashes($array[$skey]) : $array[$skey];
440            $ret[$ns][$directive] = $value;
441        }
442        return $ret;
443    }
444   
445    /**
446     * Loads configuration values from an ini file
447     * @param $filename Name of ini file
448     */
449    public function loadIni($filename) {
450        if ($this->isFinalized('Cannot load directives after finalization')) return;
451        $array = parse_ini_file($filename, true);
452        $this->loadArray($array);
453    }
454   
455    /**
456     * Checks whether or not the configuration object is finalized.
457     * @param $error String error message, or false for no error
458     */
459    public function isFinalized($error = false) {
460        if ($this->finalized && $error) {
461            trigger_error($error, E_USER_ERROR);
462        }
463        return $this->finalized;
464    }
465   
466    /**
467     * Finalizes configuration only if auto finalize is on and not
468     * already finalized
469     */
470    public function autoFinalize() {
471        if (!$this->finalized && $this->autoFinalize) $this->finalize();
472    }
473   
474    /**
475     * Finalizes a configuration object, prohibiting further change
476     */
477    public function finalize() {
478        $this->finalized = true;
479    }
480   
481}
482
483
484
Note: See TracBrowser for help on using the browser.