| [ Index ] |
PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008] |
[Summary view] [Print] [Text view]
1 <?php 2 3 require_once 'HTMLPurifier/Error.php'; 4 require_once 'HTMLPurifier/ConfigDef.php'; 5 require_once 'HTMLPurifier/ConfigDef/Namespace.php'; 6 require_once 'HTMLPurifier/ConfigDef/Directive.php'; 7 require_once 'HTMLPurifier/ConfigDef/DirectiveAlias.php'; 8 9 if (!defined('HTMLPURIFIER_SCHEMA_STRICT')) define('HTMLPURIFIER_SCHEMA_STRICT', false); 10 11 /** 12 * Configuration definition, defines directives and their defaults. 13 * @note If you update this, please update Printer_ConfigForm 14 * @todo The ability to define things multiple times is confusing and should 15 * be factored out to its own function named registerDependency() or 16 * addNote(), where only the namespace.name and an extra descriptions 17 * documenting the nature of the dependency are needed. Since it's 18 * possible that the dependency is registered before the configuration 19 * is defined, deferring it to some sort of cache until it actually 20 * gets defined would be wise, keeping it opaque until it does get 21 * defined. We could add a finalize() method which would cause it to 22 * error out if we get a dangling dependency. It's difficult, however, 23 * to know whether or not it's a dependency, or a codependency, that is 24 * neither of them fully depends on it. Where does the configuration go 25 * then? This could be partially resolved by allowing blanket definitions 26 * and then splitting them up into finer-grained versions, however, there 27 * might be implementation difficulties in ini files regarding order of 28 * execution. 29 */ 30 class HTMLPurifier_ConfigSchema { 31 32 /** 33 * Defaults of the directives and namespaces. 34 * @note This shares the exact same structure as HTMLPurifier_Config::$conf 35 */ 36 var $defaults = array(); 37 38 /** 39 * Definition of the directives. 40 */ 41 var $info = array(); 42 43 /** 44 * Definition of namespaces. 45 */ 46 var $info_namespace = array(); 47 48 /** 49 * Lookup table of allowed types. 50 */ 51 var $types = array( 52 'string' => 'String', 53 'istring' => 'Case-insensitive string', 54 'text' => 'Text', 55 'itext' => 'Case-insensitive text', 56 'int' => 'Integer', 57 'float' => 'Float', 58 'bool' => 'Boolean', 59 'lookup' => 'Lookup array', 60 'list' => 'Array list', 61 'hash' => 'Associative array', 62 'mixed' => 'Mixed' 63 ); 64 65 /** 66 * Initializes the default namespaces. 67 */ 68 function initialize() { 69 $this->defineNamespace('Core', 'Core features that are always available.'); 70 $this->defineNamespace('Attr', 'Features regarding attribute validation.'); 71 $this->defineNamespace('URI', 'Features regarding Uniform Resource Identifiers.'); 72 $this->defineNamespace('HTML', 'Configuration regarding allowed HTML.'); 73 $this->defineNamespace('CSS', 'Configuration regarding allowed CSS.'); 74 $this->defineNamespace('AutoFormat', 'Configuration for activating auto-formatting functionality (also known as <code>Injector</code>s)'); 75 $this->defineNamespace('AutoFormatParam', 'Configuration for customizing auto-formatting functionality'); 76 $this->defineNamespace('Output', 'Configuration relating to the generation of (X)HTML.'); 77 $this->defineNamespace('Cache', 'Configuration for DefinitionCache and related subclasses.'); 78 $this->defineNamespace('Test', 'Developer testing configuration for our unit tests.'); 79 } 80 81 /** 82 * Retrieves an instance of the application-wide configuration definition. 83 * @static 84 */ 85 function &instance($prototype = null) { 86 static $instance; 87 if ($prototype !== null) { 88 $instance = $prototype; 89 } elseif ($instance === null || $prototype === true) { 90 $instance = new HTMLPurifier_ConfigSchema(); 91 $instance->initialize(); 92 } 93 return $instance; 94 } 95 96 /** 97 * Defines a directive for configuration 98 * @static 99 * @warning Will fail of directive's namespace is defined 100 * @param $namespace Namespace the directive is in 101 * @param $name Key of directive 102 * @param $default Default value of directive 103 * @param $type Allowed type of the directive. See 104 * HTMLPurifier_DirectiveDef::$type for allowed values 105 * @param $description Description of directive for documentation 106 */ 107 function define($namespace, $name, $default, $type, $description) { 108 $def =& HTMLPurifier_ConfigSchema::instance(); 109 110 // basic sanity checks 111 if (HTMLPURIFIER_SCHEMA_STRICT) { 112 if (!isset($def->info[$namespace])) { 113 trigger_error('Cannot define directive for undefined namespace', 114 E_USER_ERROR); 115 return; 116 } 117 if (!ctype_alnum($name)) { 118 trigger_error('Directive name must be alphanumeric', 119 E_USER_ERROR); 120 return; 121 } 122 if (empty($description)) { 123 trigger_error('Description must be non-empty', 124 E_USER_ERROR); 125 return; 126 } 127 } 128 129 if (isset($def->info[$namespace][$name])) { 130 // already defined 131 if ( 132 $def->info[$namespace][$name]->type !== $type || 133 $def->defaults[$namespace][$name] !== $default 134 ) { 135 trigger_error('Inconsistent default or type, cannot redefine'); 136 return; 137 } 138 } else { 139 // needs defining 140 141 // process modifiers (OPTIMIZE!) 142 $type_values = explode('/', $type, 2); 143 $type = $type_values[0]; 144 $modifier = isset($type_values[1]) ? $type_values[1] : false; 145 $allow_null = ($modifier === 'null'); 146 147 if (HTMLPURIFIER_SCHEMA_STRICT) { 148 if (!isset($def->types[$type])) { 149 trigger_error('Invalid type for configuration directive', 150 E_USER_ERROR); 151 return; 152 } 153 $default = $def->validate($default, $type, $allow_null); 154 if ($def->isError($default)) { 155 trigger_error('Default value does not match directive type', 156 E_USER_ERROR); 157 return; 158 } 159 } 160 161 $def->info[$namespace][$name] = 162 new HTMLPurifier_ConfigDef_Directive(); 163 $def->info[$namespace][$name]->type = $type; 164 $def->info[$namespace][$name]->allow_null = $allow_null; 165 $def->defaults[$namespace][$name] = $default; 166 } 167 if (!HTMLPURIFIER_SCHEMA_STRICT) return; 168 $backtrace = debug_backtrace(); 169 $file = $def->mungeFilename($backtrace[0]['file']); 170 $line = $backtrace[0]['line']; 171 $def->info[$namespace][$name]->addDescription($file,$line,$description); 172 } 173 174 /** 175 * Defines a namespace for directives to be put into. 176 * @static 177 * @param $namespace Namespace's name 178 * @param $description Description of the namespace 179 */ 180 function defineNamespace($namespace, $description) { 181 $def =& HTMLPurifier_ConfigSchema::instance(); 182 if (HTMLPURIFIER_SCHEMA_STRICT) { 183 if (isset($def->info[$namespace])) { 184 trigger_error('Cannot redefine namespace', E_USER_ERROR); 185 return; 186 } 187 if (!ctype_alnum($namespace)) { 188 trigger_error('Namespace name must be alphanumeric', 189 E_USER_ERROR); 190 return; 191 } 192 if (empty($description)) { 193 trigger_error('Description must be non-empty', 194 E_USER_ERROR); 195 return; 196 } 197 } 198 $def->info[$namespace] = array(); 199 $def->info_namespace[$namespace] = new HTMLPurifier_ConfigDef_Namespace(); 200 $def->info_namespace[$namespace]->description = $description; 201 $def->defaults[$namespace] = array(); 202 } 203 204 /** 205 * Defines a directive value alias. 206 * 207 * Directive value aliases are convenient for developers because it lets 208 * them set a directive to several values and get the same result. 209 * @static 210 * @param $namespace Directive's namespace 211 * @param $name Name of Directive 212 * @param $alias Name of aliased value 213 * @param $real Value aliased value will be converted into 214 */ 215 function defineValueAliases($namespace, $name, $aliases) { 216 $def =& HTMLPurifier_ConfigSchema::instance(); 217 if (HTMLPURIFIER_SCHEMA_STRICT && !isset($def->info[$namespace][$name])) { 218 trigger_error('Cannot set value alias for non-existant directive', 219 E_USER_ERROR); 220 return; 221 } 222 foreach ($aliases as $alias => $real) { 223 if (HTMLPURIFIER_SCHEMA_STRICT) { 224 if (!$def->info[$namespace][$name] !== true && 225 !isset($def->info[$namespace][$name]->allowed[$real]) 226 ) { 227 trigger_error('Cannot define alias to value that is not allowed', 228 E_USER_ERROR); 229 return; 230 } 231 if (isset($def->info[$namespace][$name]->allowed[$alias])) { 232 trigger_error('Cannot define alias over allowed value', 233 E_USER_ERROR); 234 return; 235 } 236 } 237 $def->info[$namespace][$name]->aliases[$alias] = $real; 238 } 239 } 240 241 /** 242 * Defines a set of allowed values for a directive. 243 * @static 244 * @param $namespace Namespace of directive 245 * @param $name Name of directive 246 * @param $allowed_values Arraylist of allowed values 247 */ 248 function defineAllowedValues($namespace, $name, $allowed_values) { 249 $def =& HTMLPurifier_ConfigSchema::instance(); 250 if (HTMLPURIFIER_SCHEMA_STRICT && !isset($def->info[$namespace][$name])) { 251 trigger_error('Cannot define allowed values for undefined directive', 252 E_USER_ERROR); 253 return; 254 } 255 $directive =& $def->info[$namespace][$name]; 256 $type = $directive->type; 257 if (HTMLPURIFIER_SCHEMA_STRICT && $type != 'string' && $type != 'istring') { 258 trigger_error('Cannot define allowed values for directive whose type is not string', 259 E_USER_ERROR); 260 return; 261 } 262 if ($directive->allowed === true) { 263 $directive->allowed = array(); 264 } 265 foreach ($allowed_values as $value) { 266 $directive->allowed[$value] = true; 267 } 268 if ( 269 HTMLPURIFIER_SCHEMA_STRICT && 270 $def->defaults[$namespace][$name] !== null && 271 !isset($directive->allowed[$def->defaults[$namespace][$name]]) 272 ) { 273 trigger_error('Default value must be in allowed range of variables', 274 E_USER_ERROR); 275 $directive->allowed = true; // undo undo! 276 return; 277 } 278 } 279 280 /** 281 * Defines a directive alias for backwards compatibility 282 * @static 283 * @param $namespace 284 * @param $name Directive that will be aliased 285 * @param $new_namespace 286 * @param $new_name Directive that the alias will be to 287 */ 288 function defineAlias($namespace, $name, $new_namespace, $new_name) { 289 $def =& HTMLPurifier_ConfigSchema::instance(); 290 if (HTMLPURIFIER_SCHEMA_STRICT) { 291 if (!isset($def->info[$namespace])) { 292 trigger_error('Cannot define directive alias in undefined namespace', 293 E_USER_ERROR); 294 return; 295 } 296 if (!ctype_alnum($name)) { 297 trigger_error('Directive name must be alphanumeric', 298 E_USER_ERROR); 299 return; 300 } 301 if (isset($def->info[$namespace][$name])) { 302 trigger_error('Cannot define alias over directive', 303 E_USER_ERROR); 304 return; 305 } 306 if (!isset($def->info[$new_namespace][$new_name])) { 307 trigger_error('Cannot define alias to undefined directive', 308 E_USER_ERROR); 309 return; 310 } 311 if ($def->info[$new_namespace][$new_name]->class == 'alias') { 312 trigger_error('Cannot define alias to alias', 313 E_USER_ERROR); 314 return; 315 } 316 } 317 $def->info[$namespace][$name] = 318 new HTMLPurifier_ConfigDef_DirectiveAlias( 319 $new_namespace, $new_name); 320 $def->info[$new_namespace][$new_name]->directiveAliases[] = "$namespace.$name"; 321 } 322 323 /** 324 * Validate a variable according to type. Return null if invalid. 325 */ 326 function validate($var, $type, $allow_null = false) { 327 if (!isset($this->types[$type])) { 328 trigger_error('Invalid type', E_USER_ERROR); 329 return; 330 } 331 if ($allow_null && $var === null) return null; 332 switch ($type) { 333 case 'mixed': 334 //if (is_string($var)) $var = unserialize($var); 335 return $var; 336 case 'istring': 337 case 'string': 338 case 'text': // no difference, just is longer/multiple line string 339 case 'itext': 340 if (!is_string($var)) break; 341 if ($type === 'istring' || $type === 'itext') $var = strtolower($var); 342 return $var; 343 case 'int': 344 if (is_string($var) && ctype_digit($var)) $var = (int) $var; 345 elseif (!is_int($var)) break; 346 return $var; 347 case 'float': 348 if (is_string($var) && is_numeric($var)) $var = (float) $var; 349 elseif (!is_float($var)) break; 350 return $var; 351 case 'bool': 352 if (is_int($var) && ($var === 0 || $var === 1)) { 353 $var = (bool) $var; 354 } elseif (is_string($var)) { 355 if ($var == 'on' || $var == 'true' || $var == '1') { 356 $var = true; 357 } elseif ($var == 'off' || $var == 'false' || $var == '0') { 358 $var = false; 359 } else { 360 break; 361 } 362 } elseif (!is_bool($var)) break; 363 return $var; 364 case 'list': 365 case 'hash': 366 case 'lookup': 367 if (is_string($var)) { 368 // special case: technically, this is an array with 369 // a single empty string item, but having an empty 370 // array is more intuitive 371 if ($var == '') return array(); 372 if (strpos($var, "\n") === false && strpos($var, "\r") === false) { 373 // simplistic string to array method that only works 374 // for simple lists of tag names or alphanumeric characters 375 $var = explode(',',$var); 376 } else { 377 $var = preg_split('/(,|[\n\r]+)/', $var); 378 } 379 // remove spaces 380 foreach ($var as $i => $j) $var[$i] = trim($j); 381 if ($type === 'hash') { 382 // key:value,key2:value2 383 $nvar = array(); 384 foreach ($var as $keypair) { 385 $c = explode(':', $keypair, 2); 386 if (!isset($c[1])) continue; 387 $nvar[$c[0]] = $c[1]; 388 } 389 $var = $nvar; 390 } 391 } 392 if (!is_array($var)) break; 393 $keys = array_keys($var); 394 if ($keys === array_keys($keys)) { 395 if ($type == 'list') return $var; 396 elseif ($type == 'lookup') { 397 $new = array(); 398 foreach ($var as $key) { 399 $new[$key] = true; 400 } 401 return $new; 402 } else break; 403 } 404 if ($type === 'lookup') { 405 foreach ($var as $key => $value) { 406 $var[$key] = true; 407 } 408 } 409 return $var; 410 } 411 $error = new HTMLPurifier_Error(); 412 return $error; 413 } 414 415 /** 416 * Takes an absolute path and munges it into a more manageable relative path 417 */ 418 function mungeFilename($filename) { 419 if (!HTMLPURIFIER_SCHEMA_STRICT) return $filename; 420 $offset = strrpos($filename, 'HTMLPurifier'); 421 $filename = substr($filename, $offset); 422 $filename = str_replace('\\', '/', $filename); 423 return $filename; 424 } 425 426 /** 427 * Checks if var is an HTMLPurifier_Error object 428 */ 429 function isError($var) { 430 if (!is_object($var)) return false; 431 if (!is_a($var, 'HTMLPurifier_Error')) return false; 432 return true; 433 } 434 } 435 436
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Jan 14 11:33:29 2009 | Cross-referenced by PHPXref 0.7 |