ILIAS  Release_4_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
Config.php
Go to the documentation of this file.
1 <?php
2 
18 {
19 
23  public $version = '4.0.0';
24 
29  public $autoFinalize = true;
30 
31  // protected member variables
32 
37  protected $serials = array();
38 
42  protected $serial;
43 
47  protected $parser;
48 
54  public $def;
55 
59  protected $definitions;
60 
64  protected $finalized = false;
65 
69  protected $plist;
70 
75  private $aliasMode;
76 
81  public $chatty = true;
82 
86  private $lock;
87 
92  public function __construct($definition, $parent = null) {
93  $parent = $parent ? $parent : $definition->defaultPlist;
94  $this->plist = new HTMLPurifier_PropertyList($parent);
95  $this->def = $definition; // keep a copy around for checking
96  $this->parser = new HTMLPurifier_VarParser_Flexible();
97  }
98 
108  public static function create($config, $schema = null) {
109  if ($config instanceof HTMLPurifier_Config) {
110  // pass-through
111  return $config;
112  }
113  if (!$schema) {
115  } else {
116  $ret = new HTMLPurifier_Config($schema);
117  }
118  if (is_string($config)) $ret->loadIni($config);
119  elseif (is_array($config)) $ret->loadArray($config);
120  return $ret;
121  }
122 
129  public static function inherit(HTMLPurifier_Config $config) {
130  return new HTMLPurifier_Config($config->def, $config->plist);
131  }
132 
137  public static function createDefault() {
138  $definition = HTMLPurifier_ConfigSchema::instance();
139  $config = new HTMLPurifier_Config($definition);
140  return $config;
141  }
142 
147  public function get($key, $a = null) {
148  if ($a !== null) {
149  $this->triggerError("Using deprecated API: use \$config->get('$key.$a') instead", E_USER_WARNING);
150  $key = "$key.$a";
151  }
152  if (!$this->finalized) $this->autoFinalize();
153  if (!isset($this->def->info[$key])) {
154  // can't add % due to SimpleTest bug
155  $this->triggerError('Cannot retrieve value of undefined directive ' . htmlspecialchars($key),
156  E_USER_WARNING);
157  return;
158  }
159  if (isset($this->def->info[$key]->isAlias)) {
160  $d = $this->def->info[$key];
161  $this->triggerError('Cannot get value from aliased directive, use real name ' . $d->key,
162  E_USER_ERROR);
163  return;
164  }
165  if ($this->lock) {
166  list($ns) = explode('.', $key);
167  if ($ns !== $this->lock) {
168  $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);
169  return;
170  }
171  }
172  return $this->plist->get($key);
173  }
174 
179  public function getBatch($namespace) {
180  if (!$this->finalized) $this->autoFinalize();
181  $full = $this->getAll();
182  if (!isset($full[$namespace])) {
183  $this->triggerError('Cannot retrieve undefined namespace ' . htmlspecialchars($namespace),
184  E_USER_WARNING);
185  return;
186  }
187  return $full[$namespace];
188  }
189 
197  public function getBatchSerial($namespace) {
198  if (empty($this->serials[$namespace])) {
199  $batch = $this->getBatch($namespace);
200  unset($batch['DefinitionRev']);
201  $this->serials[$namespace] = md5(serialize($batch));
202  }
203  return $this->serials[$namespace];
204  }
205 
210  public function getSerial() {
211  if (empty($this->serial)) {
212  $this->serial = md5(serialize($this->getAll()));
213  }
214  return $this->serial;
215  }
216 
221  public function getAll() {
222  if (!$this->finalized) $this->autoFinalize();
223  $ret = array();
224  foreach ($this->plist->squash() as $name => $value) {
225  list($ns, $key) = explode('.', $name, 2);
226  $ret[$ns][$key] = $value;
227  }
228  return $ret;
229  }
230 
236  public function set($key, $value, $a = null) {
237  if (strpos($key, '.') === false) {
238  $namespace = $key;
239  $directive = $value;
240  $value = $a;
241  $key = "$key.$directive";
242  $this->triggerError("Using deprecated API: use \$config->set('$key', ...) instead", E_USER_NOTICE);
243  } else {
244  list($namespace) = explode('.', $key);
245  }
246  if ($this->isFinalized('Cannot set directive after finalization')) return;
247  if (!isset($this->def->info[$key])) {
248  $this->triggerError('Cannot set undefined directive ' . htmlspecialchars($key) . ' to value',
249  E_USER_WARNING);
250  return;
251  }
252  $def = $this->def->info[$key];
253 
254  if (isset($def->isAlias)) {
255  if ($this->aliasMode) {
256  $this->triggerError('Double-aliases not allowed, please fix '.
257  'ConfigSchema bug with' . $key, E_USER_ERROR);
258  return;
259  }
260  $this->aliasMode = true;
261  $this->set($def->key, $value);
262  $this->aliasMode = false;
263  $this->triggerError("$key is an alias, preferred directive name is {$def->key}", E_USER_NOTICE);
264  return;
265  }
266 
267  // Raw type might be negative when using the fully optimized form
268  // of stdclass, which indicates allow_null == true
269  $rtype = is_int($def) ? $def : $def->type;
270  if ($rtype < 0) {
271  $type = -$rtype;
272  $allow_null = true;
273  } else {
274  $type = $rtype;
275  $allow_null = isset($def->allow_null);
276  }
277 
278  try {
279  $value = $this->parser->parse($value, $type, $allow_null);
280  } catch (HTMLPurifier_VarParserException $e) {
281  $this->triggerError('Value for ' . $key . ' is of invalid type, should be ' . HTMLPurifier_VarParser::getTypeName($type), E_USER_WARNING);
282  return;
283  }
284  if (is_string($value) && is_object($def)) {
285  // resolve value alias if defined
286  if (isset($def->aliases[$value])) {
287  $value = $def->aliases[$value];
288  }
289  // check to see if the value is allowed
290  if (isset($def->allowed) && !isset($def->allowed[$value])) {
291  $this->triggerError('Value not supported, valid values are: ' .
292  $this->_listify($def->allowed), E_USER_WARNING);
293  return;
294  }
295  }
296  $this->plist->set($key, $value);
297 
298  // reset definitions if the directives they depend on changed
299  // this is a very costly process, so it's discouraged
300  // with finalization
301  if ($namespace == 'HTML' || $namespace == 'CSS' || $namespace == 'URI') {
302  $this->definitions[$namespace] = null;
303  }
304 
305  $this->serials[$namespace] = false;
306  }
307 
311  private function _listify($lookup) {
312  $list = array();
313  foreach ($lookup as $name => $b) $list[] = $name;
314  return implode(', ', $list);
315  }
316 
322  public function getHTMLDefinition($raw = false) {
323  return $this->getDefinition('HTML', $raw);
324  }
325 
331  public function getCSSDefinition($raw = false) {
332  return $this->getDefinition('CSS', $raw);
333  }
334 
340  public function getDefinition($type, $raw = false) {
341  if (!$this->finalized) $this->autoFinalize();
342  // temporarily suspend locks, so we can handle recursive definition calls
343  $lock = $this->lock;
344  $this->lock = null;
346  $cache = $factory->create($type, $this);
347  $this->lock = $lock;
348  if (!$raw) {
349  // see if we can quickly supply a definition
350  if (!empty($this->definitions[$type])) {
351  if (!$this->definitions[$type]->setup) {
352  $this->definitions[$type]->setup($this);
353  $cache->set($this->definitions[$type], $this);
354  }
355  return $this->definitions[$type];
356  }
357  // memory check missed, try cache
358  $this->definitions[$type] = $cache->get($this);
359  if ($this->definitions[$type]) {
360  // definition in cache, return it
361  return $this->definitions[$type];
362  }
363  } elseif (
364  !empty($this->definitions[$type]) &&
365  !$this->definitions[$type]->setup
366  ) {
367  // raw requested, raw in memory, quick return
368  return $this->definitions[$type];
369  }
370  // quick checks failed, let's create the object
371  if ($type == 'HTML') {
372  $this->definitions[$type] = new HTMLPurifier_HTMLDefinition();
373  } elseif ($type == 'CSS') {
374  $this->definitions[$type] = new HTMLPurifier_CSSDefinition();
375  } elseif ($type == 'URI') {
376  $this->definitions[$type] = new HTMLPurifier_URIDefinition();
377  } else {
378  throw new HTMLPurifier_Exception("Definition of $type type not supported");
379  }
380  // quick abort if raw
381  if ($raw) {
382  if (is_null($this->get($type . '.DefinitionID'))) {
383  // fatally error out if definition ID not set
384  throw new HTMLPurifier_Exception("Cannot retrieve raw version without specifying %$type.DefinitionID");
385  }
386  return $this->definitions[$type];
387  }
388  // set it up
389  $this->lock = $type;
390  $this->definitions[$type]->setup($this);
391  $this->lock = null;
392  // save in cache
393  $cache->set($this->definitions[$type], $this);
394  return $this->definitions[$type];
395  }
396 
402  public function loadArray($config_array) {
403  if ($this->isFinalized('Cannot load directives after finalization')) return;
404  foreach ($config_array as $key => $value) {
405  $key = str_replace('_', '.', $key);
406  if (strpos($key, '.') !== false) {
407  $this->set($key, $value);
408  } else {
409  $namespace = $key;
410  $namespace_values = $value;
411  foreach ($namespace_values as $directive => $value) {
412  $this->set($namespace .'.'. $directive, $value);
413  }
414  }
415  }
416  }
417 
424  public static function getAllowedDirectivesForForm($allowed, $schema = null) {
425  if (!$schema) {
427  }
428  if ($allowed !== true) {
429  if (is_string($allowed)) $allowed = array($allowed);
430  $allowed_ns = array();
431  $allowed_directives = array();
432  $blacklisted_directives = array();
433  foreach ($allowed as $ns_or_directive) {
434  if (strpos($ns_or_directive, '.') !== false) {
435  // directive
436  if ($ns_or_directive[0] == '-') {
437  $blacklisted_directives[substr($ns_or_directive, 1)] = true;
438  } else {
439  $allowed_directives[$ns_or_directive] = true;
440  }
441  } else {
442  // namespace
443  $allowed_ns[$ns_or_directive] = true;
444  }
445  }
446  }
447  $ret = array();
448  foreach ($schema->info as $key => $def) {
449  list($ns, $directive) = explode('.', $key, 2);
450  if ($allowed !== true) {
451  if (isset($blacklisted_directives["$ns.$directive"])) continue;
452  if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) continue;
453  }
454  if (isset($def->isAlias)) continue;
455  if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') continue;
456  $ret[] = array($ns, $directive);
457  }
458  return $ret;
459  }
460 
470  public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) {
471  $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema);
473  return $config;
474  }
475 
480  public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true) {
481  $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def);
482  $this->loadArray($ret);
483  }
484 
489  public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) {
490  if ($index !== false) $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array();
491  $mq = $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc();
492 
493  $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema);
494  $ret = array();
495  foreach ($allowed as $key) {
496  list($ns, $directive) = $key;
497  $skey = "$ns.$directive";
498  if (!empty($array["Null_$skey"])) {
499  $ret[$ns][$directive] = null;
500  continue;
501  }
502  if (!isset($array[$skey])) continue;
503  $value = $mq ? stripslashes($array[$skey]) : $array[$skey];
504  $ret[$ns][$directive] = $value;
505  }
506  return $ret;
507  }
508 
513  public function loadIni($filename) {
514  if ($this->isFinalized('Cannot load directives after finalization')) return;
515  $array = parse_ini_file($filename, true);
516  $this->loadArray($array);
517  }
518 
523  public function isFinalized($error = false) {
524  if ($this->finalized && $error) {
525  $this->triggerError($error, E_USER_ERROR);
526  }
527  return $this->finalized;
528  }
529 
534  public function autoFinalize() {
535  if ($this->autoFinalize) {
536  $this->finalize();
537  } else {
538  $this->plist->squash(true);
539  }
540  }
541 
545  public function finalize() {
546  $this->finalized = true;
547  unset($this->parser);
548  }
549 
555  protected function triggerError($msg, $no) {
556  // determine previous stack frame
557  $backtrace = debug_backtrace();
558  if ($this->chatty && isset($backtrace[1])) {
559  $frame = $backtrace[1];
560  $extra = " on line {$frame['line']} in file {$frame['file']}";
561  } else {
562  $extra = '';
563  }
564  trigger_error($msg . $extra, $no);
565  }
566 
571  public function serialize() {
572  $this->getDefinition('HTML');
573  $this->getDefinition('CSS');
574  $this->getDefinition('URI');
575  return serialize($this);
576  }
577 
578 }
579 
580 // vim: et sw=4 sts=4