Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
/**
4
 * Performs validations on HTMLPurifier_ConfigSchema_Interchange
5
 *
6
 * @note If you see '// handled by InterchangeBuilder', that means a
7
 *       design decision in that class would prevent this validation from
8
 *       ever being necessary. We have them anyway, however, for
9
 *       redundancy.
10
 */
11
class HTMLPurifier_ConfigSchema_Validator
12
{
13
 
14
    /**
15
     * @type HTMLPurifier_ConfigSchema_Interchange
16
     */
17
    protected $interchange;
18
 
19
    /**
20
     * @type array
21
     */
22
    protected $aliases;
23
 
24
    /**
25
     * Context-stack to provide easy to read error messages.
26
     * @type array
27
     */
28
    protected $context = array();
29
 
30
    /**
31
     * to test default's type.
32
     * @type HTMLPurifier_VarParser
33
     */
34
    protected $parser;
35
 
36
    public function __construct()
37
    {
38
        $this->parser = new HTMLPurifier_VarParser();
39
    }
40
 
41
    /**
42
     * Validates a fully-formed interchange object.
43
     * @param HTMLPurifier_ConfigSchema_Interchange $interchange
44
     * @return bool
45
     */
46
    public function validate($interchange)
47
    {
48
        $this->interchange = $interchange;
49
        $this->aliases = array();
50
        // PHP is a bit lax with integer <=> string conversions in
51
        // arrays, so we don't use the identical !== comparison
52
        foreach ($interchange->directives as $i => $directive) {
53
            $id = $directive->id->toString();
54
            if ($i != $id) {
55
                $this->error(false, "Integrity violation: key '$i' does not match internal id '$id'");
56
            }
57
            $this->validateDirective($directive);
58
        }
59
        return true;
60
    }
61
 
62
    /**
63
     * Validates a HTMLPurifier_ConfigSchema_Interchange_Id object.
64
     * @param HTMLPurifier_ConfigSchema_Interchange_Id $id
65
     */
66
    public function validateId($id)
67
    {
68
        $id_string = $id->toString();
69
        $this->context[] = "id '$id_string'";
70
        if (!$id instanceof HTMLPurifier_ConfigSchema_Interchange_Id) {
71
            // handled by InterchangeBuilder
72
            $this->error(false, 'is not an instance of HTMLPurifier_ConfigSchema_Interchange_Id');
73
        }
74
        // keys are now unconstrained (we might want to narrow down to A-Za-z0-9.)
75
        // we probably should check that it has at least one namespace
76
        $this->with($id, 'key')
77
            ->assertNotEmpty()
78
            ->assertIsString(); // implicit assertIsString handled by InterchangeBuilder
79
        array_pop($this->context);
80
    }
81
 
82
    /**
83
     * Validates a HTMLPurifier_ConfigSchema_Interchange_Directive object.
84
     * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d
85
     */
86
    public function validateDirective($d)
87
    {
88
        $id = $d->id->toString();
89
        $this->context[] = "directive '$id'";
90
        $this->validateId($d->id);
91
 
92
        $this->with($d, 'description')
93
            ->assertNotEmpty();
94
 
95
        // BEGIN - handled by InterchangeBuilder
96
        $this->with($d, 'type')
97
            ->assertNotEmpty();
98
        $this->with($d, 'typeAllowsNull')
99
            ->assertIsBool();
100
        try {
101
            // This also tests validity of $d->type
102
            $this->parser->parse($d->default, $d->type, $d->typeAllowsNull);
103
        } catch (HTMLPurifier_VarParserException $e) {
104
            $this->error('default', 'had error: ' . $e->getMessage());
105
        }
106
        // END - handled by InterchangeBuilder
107
 
108
        if (!is_null($d->allowed) || !empty($d->valueAliases)) {
109
            // allowed and valueAliases require that we be dealing with
110
            // strings, so check for that early.
111
            $d_int = HTMLPurifier_VarParser::$types[$d->type];
112
            if (!isset(HTMLPurifier_VarParser::$stringTypes[$d_int])) {
113
                $this->error('type', 'must be a string type when used with allowed or value aliases');
114
            }
115
        }
116
 
117
        $this->validateDirectiveAllowed($d);
118
        $this->validateDirectiveValueAliases($d);
119
        $this->validateDirectiveAliases($d);
120
 
121
        array_pop($this->context);
122
    }
123
 
124
    /**
125
     * Extra validation if $allowed member variable of
126
     * HTMLPurifier_ConfigSchema_Interchange_Directive is defined.
127
     * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d
128
     */
129
    public function validateDirectiveAllowed($d)
130
    {
131
        if (is_null($d->allowed)) {
132
            return;
133
        }
134
        $this->with($d, 'allowed')
135
            ->assertNotEmpty()
136
            ->assertIsLookup(); // handled by InterchangeBuilder
137
        if (is_string($d->default) && !isset($d->allowed[$d->default])) {
138
            $this->error('default', 'must be an allowed value');
139
        }
140
        $this->context[] = 'allowed';
141
        foreach ($d->allowed as $val => $x) {
142
            if (!is_string($val)) {
143
                $this->error("value $val", 'must be a string');
144
            }
145
        }
146
        array_pop($this->context);
147
    }
148
 
149
    /**
150
     * Extra validation if $valueAliases member variable of
151
     * HTMLPurifier_ConfigSchema_Interchange_Directive is defined.
152
     * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d
153
     */
154
    public function validateDirectiveValueAliases($d)
155
    {
156
        if (is_null($d->valueAliases)) {
157
            return;
158
        }
159
        $this->with($d, 'valueAliases')
160
            ->assertIsArray(); // handled by InterchangeBuilder
161
        $this->context[] = 'valueAliases';
162
        foreach ($d->valueAliases as $alias => $real) {
163
            if (!is_string($alias)) {
164
                $this->error("alias $alias", 'must be a string');
165
            }
166
            if (!is_string($real)) {
167
                $this->error("alias target $real from alias '$alias'", 'must be a string');
168
            }
169
            if ($alias === $real) {
170
                $this->error("alias '$alias'", "must not be an alias to itself");
171
            }
172
        }
173
        if (!is_null($d->allowed)) {
174
            foreach ($d->valueAliases as $alias => $real) {
175
                if (isset($d->allowed[$alias])) {
176
                    $this->error("alias '$alias'", 'must not be an allowed value');
177
                } elseif (!isset($d->allowed[$real])) {
178
                    $this->error("alias '$alias'", 'must be an alias to an allowed value');
179
                }
180
            }
181
        }
182
        array_pop($this->context);
183
    }
184
 
185
    /**
186
     * Extra validation if $aliases member variable of
187
     * HTMLPurifier_ConfigSchema_Interchange_Directive is defined.
188
     * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d
189
     */
190
    public function validateDirectiveAliases($d)
191
    {
192
        $this->with($d, 'aliases')
193
            ->assertIsArray(); // handled by InterchangeBuilder
194
        $this->context[] = 'aliases';
195
        foreach ($d->aliases as $alias) {
196
            $this->validateId($alias);
197
            $s = $alias->toString();
198
            if (isset($this->interchange->directives[$s])) {
199
                $this->error("alias '$s'", 'collides with another directive');
200
            }
201
            if (isset($this->aliases[$s])) {
202
                $other_directive = $this->aliases[$s];
203
                $this->error("alias '$s'", "collides with alias for directive '$other_directive'");
204
            }
205
            $this->aliases[$s] = $d->id->toString();
206
        }
207
        array_pop($this->context);
208
    }
209
 
210
    // protected helper functions
211
 
212
    /**
213
     * Convenience function for generating HTMLPurifier_ConfigSchema_ValidatorAtom
214
     * for validating simple member variables of objects.
215
     * @param $obj
216
     * @param $member
217
     * @return HTMLPurifier_ConfigSchema_ValidatorAtom
218
     */
219
    protected function with($obj, $member)
220
    {
221
        return new HTMLPurifier_ConfigSchema_ValidatorAtom($this->getFormattedContext(), $obj, $member);
222
    }
223
 
224
    /**
225
     * Emits an error, providing helpful context.
226
     * @throws HTMLPurifier_ConfigSchema_Exception
227
     */
228
    protected function error($target, $msg)
229
    {
230
        if ($target !== false) {
231
            $prefix = ucfirst($target) . ' in ' . $this->getFormattedContext();
232
        } else {
233
            $prefix = ucfirst($this->getFormattedContext());
234
        }
235
        throw new HTMLPurifier_ConfigSchema_Exception(trim($prefix . ' ' . $msg));
236
    }
237
 
238
    /**
239
     * Returns a formatted context string.
240
     * @return string
241
     */
242
    protected function getFormattedContext()
243
    {
244
        return implode(' in ', array_reverse($this->context));
245
    }
246
}
247
 
248
// vim: et sw=4 sts=4