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