File indexing completed on 2025-01-26 05:29:06
0001 <?php 0002 0003 class HTMLPurifier_ConfigSchema_InterchangeBuilder 0004 { 0005 0006 /** 0007 * Used for processing DEFAULT, nothing else. 0008 * @type HTMLPurifier_VarParser 0009 */ 0010 protected $varParser; 0011 0012 /** 0013 * @param HTMLPurifier_VarParser $varParser 0014 */ 0015 public function __construct($varParser = null) 0016 { 0017 $this->varParser = $varParser ? $varParser : new HTMLPurifier_VarParser_Native(); 0018 } 0019 0020 /** 0021 * @param string $dir 0022 * @return HTMLPurifier_ConfigSchema_Interchange 0023 */ 0024 public static function buildFromDirectory($dir = null) 0025 { 0026 $builder = new HTMLPurifier_ConfigSchema_InterchangeBuilder(); 0027 $interchange = new HTMLPurifier_ConfigSchema_Interchange(); 0028 return $builder->buildDir($interchange, $dir); 0029 } 0030 0031 /** 0032 * @param HTMLPurifier_ConfigSchema_Interchange $interchange 0033 * @param string $dir 0034 * @return HTMLPurifier_ConfigSchema_Interchange 0035 */ 0036 public function buildDir($interchange, $dir = null) 0037 { 0038 if (!$dir) { 0039 $dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema'; 0040 } 0041 if (file_exists($dir . '/info.ini')) { 0042 $info = parse_ini_file($dir . '/info.ini'); 0043 $interchange->name = $info['name']; 0044 } 0045 0046 $files = array(); 0047 $dh = opendir($dir); 0048 while (false !== ($file = readdir($dh))) { 0049 if (!$file || $file[0] == '.' || strrchr($file, '.') !== '.txt') { 0050 continue; 0051 } 0052 $files[] = $file; 0053 } 0054 closedir($dh); 0055 0056 sort($files); 0057 foreach ($files as $file) { 0058 $this->buildFile($interchange, $dir . '/' . $file); 0059 } 0060 return $interchange; 0061 } 0062 0063 /** 0064 * @param HTMLPurifier_ConfigSchema_Interchange $interchange 0065 * @param string $file 0066 */ 0067 public function buildFile($interchange, $file) 0068 { 0069 $parser = new HTMLPurifier_StringHashParser(); 0070 $this->build( 0071 $interchange, 0072 new HTMLPurifier_StringHash($parser->parseFile($file)) 0073 ); 0074 } 0075 0076 /** 0077 * Builds an interchange object based on a hash. 0078 * @param HTMLPurifier_ConfigSchema_Interchange $interchange HTMLPurifier_ConfigSchema_Interchange object to build 0079 * @param HTMLPurifier_StringHash $hash source data 0080 * @throws HTMLPurifier_ConfigSchema_Exception 0081 */ 0082 public function build($interchange, $hash) 0083 { 0084 if (!$hash instanceof HTMLPurifier_StringHash) { 0085 $hash = new HTMLPurifier_StringHash($hash); 0086 } 0087 if (!isset($hash['ID'])) { 0088 throw new HTMLPurifier_ConfigSchema_Exception('Hash does not have any ID'); 0089 } 0090 if (strpos($hash['ID'], '.') === false) { 0091 if (count($hash) == 2 && isset($hash['DESCRIPTION'])) { 0092 $hash->offsetGet('DESCRIPTION'); // prevent complaining 0093 } else { 0094 throw new HTMLPurifier_ConfigSchema_Exception('All directives must have a namespace'); 0095 } 0096 } else { 0097 $this->buildDirective($interchange, $hash); 0098 } 0099 $this->_findUnused($hash); 0100 } 0101 0102 /** 0103 * @param HTMLPurifier_ConfigSchema_Interchange $interchange 0104 * @param HTMLPurifier_StringHash $hash 0105 * @throws HTMLPurifier_ConfigSchema_Exception 0106 */ 0107 public function buildDirective($interchange, $hash) 0108 { 0109 $directive = new HTMLPurifier_ConfigSchema_Interchange_Directive(); 0110 0111 // These are required elements: 0112 $directive->id = $this->id($hash->offsetGet('ID')); 0113 $id = $directive->id->toString(); // convenience 0114 0115 if (isset($hash['TYPE'])) { 0116 $type = explode('/', $hash->offsetGet('TYPE')); 0117 if (isset($type[1])) { 0118 $directive->typeAllowsNull = true; 0119 } 0120 $directive->type = $type[0]; 0121 } else { 0122 throw new HTMLPurifier_ConfigSchema_Exception("TYPE in directive hash '$id' not defined"); 0123 } 0124 0125 if (isset($hash['DEFAULT'])) { 0126 try { 0127 $directive->default = $this->varParser->parse( 0128 $hash->offsetGet('DEFAULT'), 0129 $directive->type, 0130 $directive->typeAllowsNull 0131 ); 0132 } catch (HTMLPurifier_VarParserException $e) { 0133 throw new HTMLPurifier_ConfigSchema_Exception($e->getMessage() . " in DEFAULT in directive hash '$id'"); 0134 } 0135 } 0136 0137 if (isset($hash['DESCRIPTION'])) { 0138 $directive->description = $hash->offsetGet('DESCRIPTION'); 0139 } 0140 0141 if (isset($hash['ALLOWED'])) { 0142 $directive->allowed = $this->lookup($this->evalArray($hash->offsetGet('ALLOWED'))); 0143 } 0144 0145 if (isset($hash['VALUE-ALIASES'])) { 0146 $directive->valueAliases = $this->evalArray($hash->offsetGet('VALUE-ALIASES')); 0147 } 0148 0149 if (isset($hash['ALIASES'])) { 0150 $raw_aliases = trim($hash->offsetGet('ALIASES')); 0151 $aliases = preg_split('/\s*,\s*/', $raw_aliases); 0152 foreach ($aliases as $alias) { 0153 $directive->aliases[] = $this->id($alias); 0154 } 0155 } 0156 0157 if (isset($hash['VERSION'])) { 0158 $directive->version = $hash->offsetGet('VERSION'); 0159 } 0160 0161 if (isset($hash['DEPRECATED-USE'])) { 0162 $directive->deprecatedUse = $this->id($hash->offsetGet('DEPRECATED-USE')); 0163 } 0164 0165 if (isset($hash['DEPRECATED-VERSION'])) { 0166 $directive->deprecatedVersion = $hash->offsetGet('DEPRECATED-VERSION'); 0167 } 0168 0169 if (isset($hash['EXTERNAL'])) { 0170 $directive->external = preg_split('/\s*,\s*/', trim($hash->offsetGet('EXTERNAL'))); 0171 } 0172 0173 $interchange->addDirective($directive); 0174 } 0175 0176 /** 0177 * Evaluates an array PHP code string without array() wrapper 0178 * @param string $contents 0179 */ 0180 protected function evalArray($contents) 0181 { 0182 return eval('return array(' . $contents . ');'); 0183 } 0184 0185 /** 0186 * Converts an array list into a lookup array. 0187 * @param array $array 0188 * @return array 0189 */ 0190 protected function lookup($array) 0191 { 0192 $ret = array(); 0193 foreach ($array as $val) { 0194 $ret[$val] = true; 0195 } 0196 return $ret; 0197 } 0198 0199 /** 0200 * Convenience function that creates an HTMLPurifier_ConfigSchema_Interchange_Id 0201 * object based on a string Id. 0202 * @param string $id 0203 * @return HTMLPurifier_ConfigSchema_Interchange_Id 0204 */ 0205 protected function id($id) 0206 { 0207 return HTMLPurifier_ConfigSchema_Interchange_Id::make($id); 0208 } 0209 0210 /** 0211 * Triggers errors for any unused keys passed in the hash; such keys 0212 * may indicate typos, missing values, etc. 0213 * @param HTMLPurifier_StringHash $hash Hash to check. 0214 */ 0215 protected function _findUnused($hash) 0216 { 0217 $accessed = $hash->getAccessed(); 0218 foreach ($hash as $k => $v) { 0219 if (!isset($accessed[$k])) { 0220 trigger_error("String hash key '$k' not used by builder", E_USER_NOTICE); 0221 } 0222 } 0223 } 0224 } 0225 0226 // vim: et sw=4 sts=4