Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
/**
4
 * Validates the HTML attribute style, otherwise known as CSS.
5
 * @note We don't implement the whole CSS specification, so it might be
6
 *       difficult to reuse this component in the context of validating
7
 *       actual stylesheet declarations.
8
 * @note If we were really serious about validating the CSS, we would
9
 *       tokenize the styles and then parse the tokens. Obviously, we
10
 *       are not doing that. Doing that could seriously harm performance,
11
 *       but would make these components a lot more viable for a CSS
12
 *       filtering solution.
13
 */
14
class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
15
{
16
 
17
    /**
18
     * @param string $css
19
     * @param HTMLPurifier_Config $config
20
     * @param HTMLPurifier_Context $context
21
     * @return bool|string
22
     */
23
    public function validate($css, $config, $context)
24
    {
25
        $css = $this->parseCDATA($css);
26
 
27
        $definition = $config->getCSSDefinition();
28
        $allow_duplicates = $config->get("CSS.AllowDuplicates");
29
 
30
 
31
        // According to the CSS2.1 spec, the places where a
32
        // non-delimiting semicolon can appear are in strings
33
        // escape sequences.   So here is some dumb hack to
34
        // handle quotes.
35
        $len = strlen($css);
36
        $accum = "";
37
        $declarations = array();
38
        $quoted = false;
39
        for ($i = 0; $i < $len; $i++) {
40
            $c = strcspn($css, ";'\"", $i);
41
            $accum .= substr($css, $i, $c);
42
            $i += $c;
43
            if ($i == $len) break;
44
            $d = $css[$i];
45
            if ($quoted) {
46
                $accum .= $d;
47
                if ($d == $quoted) {
48
                    $quoted = false;
49
                }
50
            } else {
51
                if ($d == ";") {
52
                    $declarations[] = $accum;
53
                    $accum = "";
54
                } else {
55
                    $accum .= $d;
56
                    $quoted = $d;
57
                }
58
            }
59
        }
60
        if ($accum != "") $declarations[] = $accum;
61
 
62
        $propvalues = array();
63
        $new_declarations = '';
64
 
65
        /**
66
         * Name of the current CSS property being validated.
67
         */
68
        $property = false;
69
        $context->register('CurrentCSSProperty', $property);
70
 
71
        foreach ($declarations as $declaration) {
72
            if (!$declaration) {
73
                continue;
74
            }
75
            if (!strpos($declaration, ':')) {
76
                continue;
77
            }
78
            list($property, $value) = explode(':', $declaration, 2);
79
            $property = trim($property);
80
            $value = trim($value);
81
            $ok = false;
82
            do {
83
                if (isset($definition->info[$property])) {
84
                    $ok = true;
85
                    break;
86
                }
87
                if (ctype_lower($property)) {
88
                    break;
89
                }
90
                $property = strtolower($property);
91
                if (isset($definition->info[$property])) {
92
                    $ok = true;
93
                    break;
94
                }
95
            } while (0);
96
            if (!$ok) {
97
                continue;
98
            }
99
            // inefficient call, since the validator will do this again
100
            if (strtolower(trim($value)) !== 'inherit') {
101
                // inherit works for everything (but only on the base property)
102
                $result = $definition->info[$property]->validate(
103
                    $value,
104
                    $config,
105
                    $context
106
                );
107
            } else {
108
                $result = 'inherit';
109
            }
110
            if ($result === false) {
111
                continue;
112
            }
113
            if ($allow_duplicates) {
114
                $new_declarations .= "$property:$result;";
115
            } else {
116
                $propvalues[$property] = $result;
117
            }
118
        }
119
 
120
        $context->destroy('CurrentCSSProperty');
121
 
122
        // procedure does not write the new CSS simultaneously, so it's
123
        // slightly inefficient, but it's the only way of getting rid of
124
        // duplicates. Perhaps config to optimize it, but not now.
125
 
126
        foreach ($propvalues as $prop => $value) {
127
            $new_declarations .= "$prop:$value;";
128
        }
129
 
130
        return $new_declarations ? $new_declarations : false;
131
 
132
    }
133
 
134
}
135
 
136
// vim: et sw=4 sts=4