00001 <?php
00002
00017 class HTMLPurifier_Config
00018 {
00019
00023 public $version = '3.1.1';
00024
00029 public $autoFinalize = true;
00030
00031
00032
00037 protected $serials = array();
00038
00042 protected $serial;
00043
00047 protected $conf;
00048
00052 protected $parser;
00053
00059 public $def;
00060
00064 protected $definitions;
00065
00069 protected $finalized = false;
00070
00075 public function __construct($definition) {
00076 $this->conf = $definition->defaults;
00077 $this->def = $definition;
00078 $this->parser = new HTMLPurifier_VarParser_Flexible();
00079 }
00080
00090 public static function create($config, $schema = null) {
00091 if ($config instanceof HTMLPurifier_Config) {
00092
00093 return $config;
00094 }
00095 if (!$schema) {
00096 $ret = HTMLPurifier_Config::createDefault();
00097 } else {
00098 $ret = new HTMLPurifier_Config($schema);
00099 }
00100 if (is_string($config)) $ret->loadIni($config);
00101 elseif (is_array($config)) $ret->loadArray($config);
00102 return $ret;
00103 }
00104
00109 public static function createDefault() {
00110 $definition = HTMLPurifier_ConfigSchema::instance();
00111 $config = new HTMLPurifier_Config($definition);
00112 return $config;
00113 }
00114
00120 public function get($namespace, $key) {
00121 if (!$this->finalized && $this->autoFinalize) $this->finalize();
00122 if (!isset($this->def->info[$namespace][$key])) {
00123
00124 trigger_error('Cannot retrieve value of undefined directive ' . htmlspecialchars("$namespace.$key"),
00125 E_USER_WARNING);
00126 return;
00127 }
00128 if (isset($this->def->info[$namespace][$key]->isAlias)) {
00129 $d = $this->def->info[$namespace][$key];
00130 trigger_error('Cannot get value from aliased directive, use real name ' . $d->namespace . '.' . $d->name,
00131 E_USER_ERROR);
00132 return;
00133 }
00134 return $this->conf[$namespace][$key];
00135 }
00136
00141 public function getBatch($namespace) {
00142 if (!$this->finalized && $this->autoFinalize) $this->finalize();
00143 if (!isset($this->def->info[$namespace])) {
00144 trigger_error('Cannot retrieve undefined namespace ' . htmlspecialchars($namespace),
00145 E_USER_WARNING);
00146 return;
00147 }
00148 return $this->conf[$namespace];
00149 }
00150
00158 public function getBatchSerial($namespace) {
00159 if (empty($this->serials[$namespace])) {
00160 $batch = $this->getBatch($namespace);
00161 unset($batch['DefinitionRev']);
00162 $this->serials[$namespace] = md5(serialize($batch));
00163 }
00164 return $this->serials[$namespace];
00165 }
00166
00171 public function getSerial() {
00172 if (empty($this->serial)) {
00173 $this->serial = md5(serialize($this->getAll()));
00174 }
00175 return $this->serial;
00176 }
00177
00181 public function getAll() {
00182 if (!$this->finalized && $this->autoFinalize) $this->finalize();
00183 return $this->conf;
00184 }
00185
00192 public function set($namespace, $key, $value, $from_alias = false) {
00193 if ($this->isFinalized('Cannot set directive after finalization')) return;
00194 if (!isset($this->def->info[$namespace][$key])) {
00195 trigger_error('Cannot set undefined directive ' . htmlspecialchars("$namespace.$key") . ' to value',
00196 E_USER_WARNING);
00197 return;
00198 }
00199 $def = $this->def->info[$namespace][$key];
00200
00201 if (isset($def->isAlias)) {
00202 if ($from_alias) {
00203 trigger_error('Double-aliases not allowed, please fix '.
00204 'ConfigSchema bug with' . "$namespace.$key", E_USER_ERROR);
00205 return;
00206 }
00207 $this->set($new_ns = $def->namespace,
00208 $new_dir = $def->name,
00209 $value, true);
00210 trigger_error("$namespace.$key is an alias, preferred directive name is $new_ns.$new_dir", E_USER_NOTICE);
00211 return;
00212 }
00213
00214
00215
00216 $rtype = is_int($def) ? $def : $def->type;
00217 if ($rtype < 0) {
00218 $type = -$rtype;
00219 $allow_null = true;
00220 } else {
00221 $type = $rtype;
00222 $allow_null = isset($def->allow_null);
00223 }
00224
00225 try {
00226 $value = $this->parser->parse($value, $type, $allow_null);
00227 } catch (HTMLPurifier_VarParserException $e) {
00228 trigger_error('Value for ' . "$namespace.$key" . ' is of invalid type, should be ' . HTMLPurifier_VarParser::getTypeName($type), E_USER_WARNING);
00229 return;
00230 }
00231 if (is_string($value) && is_object($def)) {
00232
00233 if (isset($def->aliases[$value])) {
00234 $value = $def->aliases[$value];
00235 }
00236
00237 if (isset($def->allowed) && !isset($def->allowed[$value])) {
00238 trigger_error('Value not supported, valid values are: ' .
00239 $this->_listify($def->allowed), E_USER_WARNING);
00240 return;
00241 }
00242 }
00243 $this->conf[$namespace][$key] = $value;
00244
00245
00246
00247
00248 if ($namespace == 'HTML' || $namespace == 'CSS') {
00249 $this->definitions[$namespace] = null;
00250 }
00251
00252 $this->serials[$namespace] = false;
00253 }
00254
00258 private function _listify($lookup) {
00259 $list = array();
00260 foreach ($lookup as $name => $b) $list[] = $name;
00261 return implode(', ', $list);
00262 }
00263
00269 public function getHTMLDefinition($raw = false) {
00270 return $this->getDefinition('HTML', $raw);
00271 }
00272
00278 public function getCSSDefinition($raw = false) {
00279 return $this->getDefinition('CSS', $raw);
00280 }
00281
00287 public function getDefinition($type, $raw = false) {
00288 if (!$this->finalized && $this->autoFinalize) $this->finalize();
00289 $factory = HTMLPurifier_DefinitionCacheFactory::instance();
00290 $cache = $factory->create($type, $this);
00291 if (!$raw) {
00292
00293 if (!empty($this->definitions[$type])) {
00294 if (!$this->definitions[$type]->setup) {
00295 $this->definitions[$type]->setup($this);
00296 $cache->set($this->definitions[$type], $this);
00297 }
00298 return $this->definitions[$type];
00299 }
00300
00301 $this->definitions[$type] = $cache->get($this);
00302 if ($this->definitions[$type]) {
00303
00304 return $this->definitions[$type];
00305 }
00306 } elseif (
00307 !empty($this->definitions[$type]) &&
00308 !$this->definitions[$type]->setup
00309 ) {
00310
00311 return $this->definitions[$type];
00312 }
00313
00314 if ($type == 'HTML') {
00315 $this->definitions[$type] = new HTMLPurifier_HTMLDefinition();
00316 } elseif ($type == 'CSS') {
00317 $this->definitions[$type] = new HTMLPurifier_CSSDefinition();
00318 } elseif ($type == 'URI') {
00319 $this->definitions[$type] = new HTMLPurifier_URIDefinition();
00320 } else {
00321 throw new HTMLPurifier_Exception("Definition of $type type not supported");
00322 }
00323
00324 if ($raw) {
00325 if (is_null($this->get($type, 'DefinitionID'))) {
00326
00327 throw new HTMLPurifier_Exception("Cannot retrieve raw version without specifying %$type.DefinitionID");
00328 }
00329 return $this->definitions[$type];
00330 }
00331
00332 $this->definitions[$type]->setup($this);
00333
00334 $cache->set($this->definitions[$type], $this);
00335 return $this->definitions[$type];
00336 }
00337
00343 public function loadArray($config_array) {
00344 if ($this->isFinalized('Cannot load directives after finalization')) return;
00345 foreach ($config_array as $key => $value) {
00346 $key = str_replace('_', '.', $key);
00347 if (strpos($key, '.') !== false) {
00348
00349 list($namespace, $directive) = explode('.', $key);
00350 $this->set($namespace, $directive, $value);
00351 } else {
00352 $namespace = $key;
00353 $namespace_values = $value;
00354 foreach ($namespace_values as $directive => $value) {
00355 $this->set($namespace, $directive, $value);
00356 }
00357 }
00358 }
00359 }
00360
00367 public static function getAllowedDirectivesForForm($allowed, $schema = null) {
00368 if (!$schema) {
00369 $schema = HTMLPurifier_ConfigSchema::instance();
00370 }
00371 if ($allowed !== true) {
00372 if (is_string($allowed)) $allowed = array($allowed);
00373 $allowed_ns = array();
00374 $allowed_directives = array();
00375 $blacklisted_directives = array();
00376 foreach ($allowed as $ns_or_directive) {
00377 if (strpos($ns_or_directive, '.') !== false) {
00378
00379 if ($ns_or_directive[0] == '-') {
00380 $blacklisted_directives[substr($ns_or_directive, 1)] = true;
00381 } else {
00382 $allowed_directives[$ns_or_directive] = true;
00383 }
00384 } else {
00385
00386 $allowed_ns[$ns_or_directive] = true;
00387 }
00388 }
00389 }
00390 $ret = array();
00391 foreach ($schema->info as $ns => $keypairs) {
00392 foreach ($keypairs as $directive => $def) {
00393 if ($allowed !== true) {
00394 if (isset($blacklisted_directives["$ns.$directive"])) continue;
00395 if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) continue;
00396 }
00397 if (isset($def->isAlias)) continue;
00398 if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') continue;
00399 $ret[] = array($ns, $directive);
00400 }
00401 }
00402 return $ret;
00403 }
00404
00414 public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) {
00415 $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema);
00416 $config = HTMLPurifier_Config::create($ret, $schema);
00417 return $config;
00418 }
00419
00424 public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true) {
00425 $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def);
00426 $this->loadArray($ret);
00427 }
00428
00433 public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) {
00434 if ($index !== false) $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array();
00435 $mq = $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc();
00436
00437 $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema);
00438 $ret = array();
00439 foreach ($allowed as $key) {
00440 list($ns, $directive) = $key;
00441 $skey = "$ns.$directive";
00442 if (!empty($array["Null_$skey"])) {
00443 $ret[$ns][$directive] = null;
00444 continue;
00445 }
00446 if (!isset($array[$skey])) continue;
00447 $value = $mq ? stripslashes($array[$skey]) : $array[$skey];
00448 $ret[$ns][$directive] = $value;
00449 }
00450 return $ret;
00451 }
00452
00457 public function loadIni($filename) {
00458 if ($this->isFinalized('Cannot load directives after finalization')) return;
00459 $array = parse_ini_file($filename, true);
00460 $this->loadArray($array);
00461 }
00462
00467 public function isFinalized($error = false) {
00468 if ($this->finalized && $error) {
00469 trigger_error($error, E_USER_ERROR);
00470 }
00471 return $this->finalized;
00472 }
00473
00478 public function autoFinalize() {
00479 if (!$this->finalized && $this->autoFinalize) $this->finalize();
00480 }
00481
00485 public function finalize() {
00486 $this->finalized = true;
00487 }
00488
00489 }
00490
00491
00492