ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
Config.php
Go to the documentation of this file.
1<?php
2
18{
19
24 public $version = '4.7.0';
25
31 public $autoFinalize = true;
32
33 // protected member variables
34
40 protected $serials = array();
41
46 protected $serial;
47
52 protected $parser = null;
53
60 public $def;
61
66 protected $definitions;
67
72 protected $finalized = false;
73
78 protected $plist;
79
84 private $aliasMode;
85
92 public $chatty = true;
93
98 private $lock;
99
106 public function __construct($definition, $parent = null)
107 {
108 $parent = $parent ? $parent : $definition->defaultPlist;
109 $this->plist = new HTMLPurifier_PropertyList($parent);
110 $this->def = $definition; // keep a copy around for checking
111 $this->parser = new HTMLPurifier_VarParser_Flexible();
112 }
113
123 public static function create($config, $schema = null)
124 {
125 if ($config instanceof HTMLPurifier_Config) {
126 // pass-through
127 return $config;
128 }
129 if (!$schema) {
131 } else {
132 $ret = new HTMLPurifier_Config($schema);
133 }
134 if (is_string($config)) {
135 $ret->loadIni($config);
136 } elseif (is_array($config)) $ret->loadArray($config);
137 return $ret;
138 }
139
145 public static function inherit(HTMLPurifier_Config $config)
146 {
147 return new HTMLPurifier_Config($config->def, $config->plist);
148 }
149
154 public static function createDefault()
155 {
157 $config = new HTMLPurifier_Config($definition);
158 return $config;
159 }
160
169 public function get($key, $a = null)
170 {
171 if ($a !== null) {
172 $this->triggerError(
173 "Using deprecated API: use \$config->get('$key.$a') instead",
174 E_USER_WARNING
175 );
176 $key = "$key.$a";
177 }
178 if (!$this->finalized) {
179 $this->autoFinalize();
180 }
181 if (!isset($this->def->info[$key])) {
182 // can't add % due to SimpleTest bug
183 $this->triggerError(
184 'Cannot retrieve value of undefined directive ' . htmlspecialchars($key),
185 E_USER_WARNING
186 );
187 return;
188 }
189 if (isset($this->def->info[$key]->isAlias)) {
190 $d = $this->def->info[$key];
191 $this->triggerError(
192 'Cannot get value from aliased directive, use real name ' . $d->key,
193 E_USER_ERROR
194 );
195 return;
196 }
197 if ($this->lock) {
198 list($ns) = explode('.', $key);
199 if ($ns !== $this->lock) {
200 $this->triggerError(
201 'Cannot get value of namespace ' . $ns . ' when lock for ' .
202 $this->lock .
203 ' is active, this probably indicates a Definition setup method ' .
204 'is accessing directives that are not within its namespace',
205 E_USER_ERROR
206 );
207 return;
208 }
209 }
210 return $this->plist->get($key);
211 }
212
220 public function getBatch($namespace)
221 {
222 if (!$this->finalized) {
223 $this->autoFinalize();
224 }
225 $full = $this->getAll();
226 if (!isset($full[$namespace])) {
227 $this->triggerError(
228 'Cannot retrieve undefined namespace ' .
229 htmlspecialchars($namespace),
230 E_USER_WARNING
231 );
232 return;
233 }
234 return $full[$namespace];
235 }
236
247 public function getBatchSerial($namespace)
248 {
249 if (empty($this->serials[$namespace])) {
250 $batch = $this->getBatch($namespace);
251 unset($batch['DefinitionRev']);
252 $this->serials[$namespace] = sha1(serialize($batch));
253 }
254 return $this->serials[$namespace];
255 }
256
263 public function getSerial()
264 {
265 if (empty($this->serial)) {
266 $this->serial = sha1(serialize($this->getAll()));
267 }
268 return $this->serial;
269 }
270
276 public function getAll()
277 {
278 if (!$this->finalized) {
279 $this->autoFinalize();
280 }
281 $ret = array();
282 foreach ($this->plist->squash() as $name => $value) {
283 list($ns, $key) = explode('.', $name, 2);
284 $ret[$ns][$key] = $value;
285 }
286 return $ret;
287 }
288
296 public function set($key, $value, $a = null)
297 {
298 if (strpos($key, '.') === false) {
299 $namespace = $key;
300 $directive = $value;
301 $value = $a;
302 $key = "$key.$directive";
303 $this->triggerError("Using deprecated API: use \$config->set('$key', ...) instead", E_USER_NOTICE);
304 } else {
305 list($namespace) = explode('.', $key);
306 }
307 if ($this->isFinalized('Cannot set directive after finalization')) {
308 return;
309 }
310 if (!isset($this->def->info[$key])) {
311 $this->triggerError(
312 'Cannot set undefined directive ' . htmlspecialchars($key) . ' to value',
313 E_USER_WARNING
314 );
315 return;
316 }
317 $def = $this->def->info[$key];
318
319 if (isset($def->isAlias)) {
320 if ($this->aliasMode) {
321 $this->triggerError(
322 'Double-aliases not allowed, please fix '.
323 'ConfigSchema bug with' . $key,
324 E_USER_ERROR
325 );
326 return;
327 }
328 $this->aliasMode = true;
329 $this->set($def->key, $value);
330 $this->aliasMode = false;
331 $this->triggerError("$key is an alias, preferred directive name is {$def->key}", E_USER_NOTICE);
332 return;
333 }
334
335 // Raw type might be negative when using the fully optimized form
336 // of stdclass, which indicates allow_null == true
337 $rtype = is_int($def) ? $def : $def->type;
338 if ($rtype < 0) {
339 $type = -$rtype;
340 $allow_null = true;
341 } else {
342 $type = $rtype;
343 $allow_null = isset($def->allow_null);
344 }
345
346 try {
347 $value = $this->parser->parse($value, $type, $allow_null);
349 $this->triggerError(
350 'Value for ' . $key . ' is of invalid type, should be ' .
352 E_USER_WARNING
353 );
354 return;
355 }
356 if (is_string($value) && is_object($def)) {
357 // resolve value alias if defined
358 if (isset($def->aliases[$value])) {
359 $value = $def->aliases[$value];
360 }
361 // check to see if the value is allowed
362 if (isset($def->allowed) && !isset($def->allowed[$value])) {
363 $this->triggerError(
364 'Value not supported, valid values are: ' .
365 $this->_listify($def->allowed),
366 E_USER_WARNING
367 );
368 return;
369 }
370 }
371 $this->plist->set($key, $value);
372
373 // reset definitions if the directives they depend on changed
374 // this is a very costly process, so it's discouraged
375 // with finalization
376 if ($namespace == 'HTML' || $namespace == 'CSS' || $namespace == 'URI') {
377 $this->definitions[$namespace] = null;
378 }
379
380 $this->serials[$namespace] = false;
381 }
382
390 private function _listify($lookup)
391 {
392 $list = array();
393 foreach ($lookup as $name => $b) {
394 $list[] = $name;
395 }
396 return implode(', ', $list);
397 }
398
413 public function getHTMLDefinition($raw = false, $optimized = false)
414 {
415 return $this->getDefinition('HTML', $raw, $optimized);
416 }
417
432 public function getCSSDefinition($raw = false, $optimized = false)
433 {
434 return $this->getDefinition('CSS', $raw, $optimized);
435 }
436
451 public function getURIDefinition($raw = false, $optimized = false)
452 {
453 return $this->getDefinition('URI', $raw, $optimized);
454 }
455
473 public function getDefinition($type, $raw = false, $optimized = false)
474 {
475 if ($optimized && !$raw) {
476 throw new HTMLPurifier_Exception("Cannot set optimized = true when raw = false");
477 }
478 if (!$this->finalized) {
479 $this->autoFinalize();
480 }
481 // temporarily suspend locks, so we can handle recursive definition calls
483 $this->lock = null;
485 $cache = $factory->create($type, $this);
486 $this->lock = $lock;
487 if (!$raw) {
488 // full definition
489 // ---------------
490 // check if definition is in memory
491 if (!empty($this->definitions[$type])) {
492 $def = $this->definitions[$type];
493 // check if the definition is setup
494 if ($def->setup) {
495 return $def;
496 } else {
497 $def->setup($this);
498 if ($def->optimized) {
499 $cache->add($def, $this);
500 }
501 return $def;
502 }
503 }
504 // check if definition is in cache
505 $def = $cache->get($this);
506 if ($def) {
507 // definition in cache, save to memory and return it
508 $this->definitions[$type] = $def;
509 return $def;
510 }
511 // initialize it
512 $def = $this->initDefinition($type);
513 // set it up
514 $this->lock = $type;
515 $def->setup($this);
516 $this->lock = null;
517 // save in cache
518 $cache->add($def, $this);
519 // return it
520 return $def;
521 } else {
522 // raw definition
523 // --------------
524 // check preconditions
525 $def = null;
526 if ($optimized) {
527 if (is_null($this->get($type . '.DefinitionID'))) {
528 // fatally error out if definition ID not set
529 throw new HTMLPurifier_Exception(
530 "Cannot retrieve raw version without specifying %$type.DefinitionID"
531 );
532 }
533 }
534 if (!empty($this->definitions[$type])) {
535 $def = $this->definitions[$type];
536 if ($def->setup && !$optimized) {
537 $extra = $this->chatty ?
538 " (try moving this code block earlier in your initialization)" :
539 "";
540 throw new HTMLPurifier_Exception(
541 "Cannot retrieve raw definition after it has already been setup" .
542 $extra
543 );
544 }
545 if ($def->optimized === null) {
546 $extra = $this->chatty ? " (try flushing your cache)" : "";
547 throw new HTMLPurifier_Exception(
548 "Optimization status of definition is unknown" . $extra
549 );
550 }
551 if ($def->optimized !== $optimized) {
552 $msg = $optimized ? "optimized" : "unoptimized";
553 $extra = $this->chatty ?
554 " (this backtrace is for the first inconsistent call, which was for a $msg raw definition)"
555 : "";
556 throw new HTMLPurifier_Exception(
557 "Inconsistent use of optimized and unoptimized raw definition retrievals" . $extra
558 );
559 }
560 }
561 // check if definition was in memory
562 if ($def) {
563 if ($def->setup) {
564 // invariant: $optimized === true (checked above)
565 return null;
566 } else {
567 return $def;
568 }
569 }
570 // if optimized, check if definition was in cache
571 // (because we do the memory check first, this formulation
572 // is prone to cache slamming, but I think
573 // guaranteeing that either /all/ of the raw
574 // setup code or /none/ of it is run is more important.)
575 if ($optimized) {
576 // This code path only gets run once; once we put
577 // something in $definitions (which is guaranteed by the
578 // trailing code), we always short-circuit above.
579 $def = $cache->get($this);
580 if ($def) {
581 // save the full definition for later, but don't
582 // return it yet
583 $this->definitions[$type] = $def;
584 return null;
585 }
586 }
587 // check invariants for creation
588 if (!$optimized) {
589 if (!is_null($this->get($type . '.DefinitionID'))) {
590 if ($this->chatty) {
591 $this->triggerError(
592 'Due to a documentation error in previous version of HTML Purifier, your ' .
593 'definitions are not being cached. If this is OK, you can remove the ' .
594 '%$type.DefinitionRev and %$type.DefinitionID declaration. Otherwise, ' .
595 'modify your code to use maybeGetRawDefinition, and test if the returned ' .
596 'value is null before making any edits (if it is null, that means that a ' .
597 'cached version is available, and no raw operations are necessary). See ' .
598 '<a href="http://htmlpurifier.org/docs/enduser-customize.html#optimized">' .
599 'Customize</a> for more details',
600 E_USER_WARNING
601 );
602 } else {
603 $this->triggerError(
604 "Useless DefinitionID declaration",
605 E_USER_WARNING
606 );
607 }
608 }
609 }
610 // initialize it
611 $def = $this->initDefinition($type);
612 $def->optimized = $optimized;
613 return $def;
614 }
615 throw new HTMLPurifier_Exception("The impossible happened!");
616 }
617
626 private function initDefinition($type)
627 {
628 // quick checks failed, let's create the object
629 if ($type == 'HTML') {
631 } elseif ($type == 'CSS') {
633 } elseif ($type == 'URI') {
635 } else {
636 throw new HTMLPurifier_Exception(
637 "Definition of $type type not supported"
638 );
639 }
640 $this->definitions[$type] = $def;
641 return $def;
642 }
643
644 public function maybeGetRawDefinition($name)
645 {
646 return $this->getDefinition($name, true, true);
647 }
648
653 {
654 return $this->getDefinition('HTML', true, true);
655 }
656
660 public function maybeGetRawCSSDefinition()
661 {
662 return $this->getDefinition('CSS', true, true);
663 }
664
668 public function maybeGetRawURIDefinition()
669 {
670 return $this->getDefinition('URI', true, true);
671 }
672
679 public function loadArray($config_array)
680 {
681 if ($this->isFinalized('Cannot load directives after finalization')) {
682 return;
683 }
684 foreach ($config_array as $key => $value) {
685 $key = str_replace('_', '.', $key);
686 if (strpos($key, '.') !== false) {
687 $this->set($key, $value);
688 } else {
689 $namespace = $key;
690 $namespace_values = $value;
691 foreach ($namespace_values as $directive => $value2) {
692 $this->set($namespace .'.'. $directive, $value2);
693 }
694 }
695 }
696 }
697
708 public static function getAllowedDirectivesForForm($allowed, $schema = null)
709 {
710 if (!$schema) {
712 }
713 if ($allowed !== true) {
714 if (is_string($allowed)) {
715 $allowed = array($allowed);
716 }
717 $allowed_ns = array();
718 $allowed_directives = array();
719 $blacklisted_directives = array();
720 foreach ($allowed as $ns_or_directive) {
721 if (strpos($ns_or_directive, '.') !== false) {
722 // directive
723 if ($ns_or_directive[0] == '-') {
724 $blacklisted_directives[substr($ns_or_directive, 1)] = true;
725 } else {
726 $allowed_directives[$ns_or_directive] = true;
727 }
728 } else {
729 // namespace
730 $allowed_ns[$ns_or_directive] = true;
731 }
732 }
733 }
734 $ret = array();
735 foreach ($schema->info as $key => $def) {
736 list($ns, $directive) = explode('.', $key, 2);
737 if ($allowed !== true) {
738 if (isset($blacklisted_directives["$ns.$directive"])) {
739 continue;
740 }
741 if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) {
742 continue;
743 }
744 }
745 if (isset($def->isAlias)) {
746 continue;
747 }
748 if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') {
749 continue;
750 }
751 $ret[] = array($ns, $directive);
752 }
753 return $ret;
754 }
755
768 public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null)
769 {
770 $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema);
771 $config = HTMLPurifier_Config::create($ret, $schema);
772 return $config;
773 }
774
783 public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true)
784 {
785 $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def);
786 $this->loadArray($ret);
787 }
788
801 public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null)
802 {
803 if ($index !== false) {
804 $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array();
805 }
806 $mq = $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc();
807
808 $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema);
809 $ret = array();
810 foreach ($allowed as $key) {
811 list($ns, $directive) = $key;
812 $skey = "$ns.$directive";
813 if (!empty($array["Null_$skey"])) {
814 $ret[$ns][$directive] = null;
815 continue;
816 }
817 if (!isset($array[$skey])) {
818 continue;
819 }
820 $value = $mq ? stripslashes($array[$skey]) : $array[$skey];
821 $ret[$ns][$directive] = $value;
822 }
823 return $ret;
824 }
825
831 public function loadIni($filename)
832 {
833 if ($this->isFinalized('Cannot load directives after finalization')) {
834 return;
835 }
836 $array = parse_ini_file($filename, true);
837 $this->loadArray($array);
838 }
839
847 public function isFinalized($error = false)
848 {
849 if ($this->finalized && $error) {
850 $this->triggerError($error, E_USER_ERROR);
851 }
852 return $this->finalized;
853 }
854
859 public function autoFinalize()
860 {
861 if ($this->autoFinalize) {
862 $this->finalize();
863 } else {
864 $this->plist->squash(true);
865 }
866 }
867
871 public function finalize()
872 {
873 $this->finalized = true;
874 $this->parser = null;
875 }
876
884 protected function triggerError($msg, $no)
885 {
886 // determine previous stack frame
887 $extra = '';
888 if ($this->chatty) {
889 $trace = debug_backtrace();
890 // zip(tail(trace), trace) -- but PHP is not Haskell har har
891 for ($i = 0, $c = count($trace); $i < $c - 1; $i++) {
892 // XXX this is not correct on some versions of HTML Purifier
893 if ($trace[$i + 1]['class'] === 'HTMLPurifier_Config') {
894 continue;
895 }
896 $frame = $trace[$i];
897 $extra = " invoked on line {$frame['line']} in file {$frame['file']}";
898 break;
899 }
900 }
901 trigger_error($msg . $extra, $no);
902 }
903
910 public function serialize()
911 {
912 $this->getDefinition('HTML');
913 $this->getDefinition('CSS');
914 $this->getDefinition('URI');
915 return serialize($this);
916 }
917
918}
919
920// vim: et sw=4 sts=4
$filename
Definition: buildRTE.php:89
Defines allowed CSS attributes and what their values are.
static instance($prototype=null)
Retrieves an instance of the application-wide configuration definition.
Configuration object that triggers customizable behavior.
Definition: Config.php:18
static create($config, $schema=null)
Convenience constructor that creates a config object based on a mixed var.
Definition: Config.php:123
static loadArrayFromForm($array, $index=false, $allowed=true, $mq_fix=true, $schema=null)
Loads configuration values from $_GET/$_POST that were posted via ConfigForm.
Definition: Config.php:768
$plist
Property list containing configuration directives.
Definition: Config.php:78
initDefinition($type)
Initialise definition.
Definition: Config.php:626
static createDefault()
Convenience constructor that creates a default configuration object.
Definition: Config.php:154
finalize()
Finalizes a configuration object, prohibiting further change.
Definition: Config.php:871
$aliasMode
Whether or not a set is taking place due to an alias lookup.
Definition: Config.php:84
getURIDefinition($raw=false, $optimized=false)
Retrieves object reference to the URI definition.
Definition: Config.php:451
getBatchSerial($namespace)
Returns a SHA-1 signature of a segment of the configuration object that uniquely identifies that part...
Definition: Config.php:247
static getAllowedDirectivesForForm($allowed, $schema=null)
Returns a list of array(namespace, directive) for all directives that are allowed in a web-form conte...
Definition: Config.php:708
$parser
Parser for variables.
Definition: Config.php:52
getBatch($namespace)
Retrieves an array of directives to values from a given namespace.
Definition: Config.php:220
$lock
Current lock; only gets to this namespace are allowed.
Definition: Config.php:98
_listify($lookup)
Convenience function for error reporting.
Definition: Config.php:390
$serial
Serial for entire configuration object.
Definition: Config.php:46
loadArray($config_array)
Loads configuration values from an array with the following structure: Namespace.Directive => Value.
Definition: Config.php:679
$finalized
Whether or not config is finalized.
Definition: Config.php:72
$definitions
Indexed array of definitions.
Definition: Config.php:66
getCSSDefinition($raw=false, $optimized=false)
Retrieves object reference to the CSS definition.
Definition: Config.php:432
getHTMLDefinition($raw=false, $optimized=false)
Retrieves object reference to the HTML definition.
Definition: Config.php:413
mergeArrayFromForm($array, $index=false, $allowed=true, $mq_fix=true)
Merges in configuration values from $_GET/$_POST to object.
Definition: Config.php:783
autoFinalize()
Finalizes configuration only if auto finalize is on and not already finalized.
Definition: Config.php:859
$version
HTML Purifier's version @type string.
Definition: Config.php:24
$autoFinalize
Whether or not to automatically finalize the object if a read operation is done.
Definition: Config.php:31
maybeGetRawDefinition($name)
Definition: Config.php:644
static inherit(HTMLPurifier_Config $config)
Creates a new config object that inherits from a previous one.
Definition: Config.php:145
__construct($definition, $parent=null)
Constructor.
Definition: Config.php:106
$def
Reference HTMLPurifier_ConfigSchema for value checking.
Definition: Config.php:60
isFinalized($error=false)
Checks whether or not the configuration object is finalized.
Definition: Config.php:847
serialize()
Returns a serialized form of the configuration object that can be reconstituted.
Definition: Config.php:910
triggerError($msg, $no)
Produces a nicely formatted error message by supplying the stack frame information OUTSIDE of HTMLPur...
Definition: Config.php:884
$chatty
Set to false if you do not want line and file numbers in errors.
Definition: Config.php:92
loadIni($filename)
Loads configuration values from an ini file.
Definition: Config.php:831
static prepareArrayFromForm($array, $index=false, $allowed=true, $mq_fix=true, $schema=null)
Prepares an array from a form into something usable for the more strict parts of HTMLPurifier_Config.
Definition: Config.php:801
getAll()
Retrieves all directives, organized by namespace.
Definition: Config.php:276
getDefinition($type, $raw=false, $optimized=false)
Retrieves a definition.
Definition: Config.php:473
getSerial()
Returns a SHA-1 signature for the entire configuration object that uniquely identifies that particula...
Definition: Config.php:263
$serials
Namespace indexed array of serials for specific namespaces.
Definition: Config.php:40
static instance($prototype=null)
Retrieves an instance of global definition cache factory.
Global exception class for HTML Purifier; any exceptions we throw are from here.
Definition: Exception.php:8
Definition of the purified HTML that describes allowed children, attributes, and many other things.
Generic property list implementation.
Definition: PropertyList.php:7
Exception type for HTMLPurifier_VarParser.
Performs safe variable parsing based on types which can be used by users.
Definition: Flexible.php:9
static getTypeName($type)
Definition: VarParser.php:184
if($err=$client->getError()) $namespace