1<?php 2 3class HTMLPurifier_ConfigSchema_InterchangeBuilder 4{ 5 6 /** 7 * Used for processing DEFAULT, nothing else. 8 */ 9 protected $varParser; 10 11 public function __construct($varParser = null) { 12 $this->varParser = $varParser ? $varParser : new HTMLPurifier_VarParser_Native(); 13 } 14 15 public static function buildFromDirectory($dir = null) { 16 $builder = new HTMLPurifier_ConfigSchema_InterchangeBuilder(); 17 $interchange = new HTMLPurifier_ConfigSchema_Interchange(); 18 return $builder->buildDir($interchange, $dir); 19 } 20 21 public function buildDir($interchange, $dir = null) { 22 if (!$dir) $dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema'; 23 if (file_exists($dir . '/info.ini')) { 24 $info = parse_ini_file($dir . '/info.ini'); 25 $interchange->name = $info['name']; 26 } 27 28 $files = array(); 29 $dh = opendir($dir); 30 while (false !== ($file = readdir($dh))) { 31 if (!$file || $file[0] == '.' || strrchr($file, '.') !== '.txt') { 32 continue; 33 } 34 $files[] = $file; 35 } 36 closedir($dh); 37 38 sort($files); 39 foreach ($files as $file) { 40 $this->buildFile($interchange, $dir . '/' . $file); 41 } 42 43 return $interchange; 44 } 45 46 public function buildFile($interchange, $file) { 47 $parser = new HTMLPurifier_StringHashParser(); 48 $this->build( 49 $interchange, 50 new HTMLPurifier_StringHash( $parser->parseFile($file) ) 51 ); 52 } 53 54 /** 55 * Builds an interchange object based on a hash. 56 * @param $interchange HTMLPurifier_ConfigSchema_Interchange object to build 57 * @param $hash HTMLPurifier_ConfigSchema_StringHash source data 58 */ 59 public function build($interchange, $hash) { 60 if (!$hash instanceof HTMLPurifier_StringHash) { 61 $hash = new HTMLPurifier_StringHash($hash); 62 } 63 if (!isset($hash['ID'])) { 64 throw new HTMLPurifier_ConfigSchema_Exception('Hash does not have any ID'); 65 } 66 if (strpos($hash['ID'], '.') === false) { 67 if (count($hash) == 2 && isset($hash['DESCRIPTION'])) { 68 $hash->offsetGet('DESCRIPTION'); // prevent complaining 69 } else { 70 throw new HTMLPurifier_ConfigSchema_Exception('All directives must have a namespace'); 71 } 72 } else { 73 $this->buildDirective($interchange, $hash); 74 } 75 $this->_findUnused($hash); 76 } 77 78 public function buildDirective($interchange, $hash) { 79 $directive = new HTMLPurifier_ConfigSchema_Interchange_Directive(); 80 81 // These are required elements: 82 $directive->id = $this->id($hash->offsetGet('ID')); 83 $id = $directive->id->toString(); // convenience 84 85 if (isset($hash['TYPE'])) { 86 $type = explode('/', $hash->offsetGet('TYPE')); 87 if (isset($type[1])) $directive->typeAllowsNull = true; 88 $directive->type = $type[0]; 89 } else { 90 throw new HTMLPurifier_ConfigSchema_Exception("TYPE in directive hash '$id' not defined"); 91 } 92 93 if (isset($hash['DEFAULT'])) { 94 try { 95 $directive->default = $this->varParser->parse($hash->offsetGet('DEFAULT'), $directive->type, $directive->typeAllowsNull); 96 } catch (HTMLPurifier_VarParserException $e) { 97 throw new HTMLPurifier_ConfigSchema_Exception($e->getMessage() . " in DEFAULT in directive hash '$id'"); 98 } 99 } 100 101 if (isset($hash['DESCRIPTION'])) { 102 $directive->description = $hash->offsetGet('DESCRIPTION'); 103 } 104 105 if (isset($hash['ALLOWED'])) { 106 $directive->allowed = $this->lookup($this->evalArray($hash->offsetGet('ALLOWED'))); 107 } 108 109 if (isset($hash['VALUE-ALIASES'])) { 110 $directive->valueAliases = $this->evalArray($hash->offsetGet('VALUE-ALIASES')); 111 } 112 113 if (isset($hash['ALIASES'])) { 114 $raw_aliases = trim($hash->offsetGet('ALIASES')); 115 $aliases = preg_split('/\s*,\s*/', $raw_aliases); 116 foreach ($aliases as $alias) { 117 $directive->aliases[] = $this->id($alias); 118 } 119 } 120 121 if (isset($hash['VERSION'])) { 122 $directive->version = $hash->offsetGet('VERSION'); 123 } 124 125 if (isset($hash['DEPRECATED-USE'])) { 126 $directive->deprecatedUse = $this->id($hash->offsetGet('DEPRECATED-USE')); 127 } 128 129 if (isset($hash['DEPRECATED-VERSION'])) { 130 $directive->deprecatedVersion = $hash->offsetGet('DEPRECATED-VERSION'); 131 } 132 133 if (isset($hash['EXTERNAL'])) { 134 $directive->external = preg_split('/\s*,\s*/', trim($hash->offsetGet('EXTERNAL'))); 135 } 136 137 $interchange->addDirective($directive); 138 } 139 140 /** 141 * Evaluates an array PHP code string without array() wrapper 142 */ 143 protected function evalArray($contents) { 144 return eval('return array('. $contents .');'); 145 } 146 147 /** 148 * Converts an array list into a lookup array. 149 */ 150 protected function lookup($array) { 151 $ret = array(); 152 foreach ($array as $val) $ret[$val] = true; 153 return $ret; 154 } 155 156 /** 157 * Convenience function that creates an HTMLPurifier_ConfigSchema_Interchange_Id 158 * object based on a string Id. 159 */ 160 protected function id($id) { 161 return HTMLPurifier_ConfigSchema_Interchange_Id::make($id); 162 } 163 164 /** 165 * Triggers errors for any unused keys passed in the hash; such keys 166 * may indicate typos, missing values, etc. 167 * @param $hash Instance of ConfigSchema_StringHash to check. 168 */ 169 protected function _findUnused($hash) { 170 $accessed = $hash->getAccessed(); 171 foreach ($hash as $k => $v) { 172 if (!isset($accessed[$k])) { 173 trigger_error("String hash key '$k' not used by builder", E_USER_NOTICE); 174 } 175 } 176 } 177 178} 179 180// vim: et sw=4 sts=4 181