Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | 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
 
1441 ariadna 30
        $universal_attrdef = new HTMLPurifier_AttrDef_Enum(
31
            array(
32
                'initial',
33
                'inherit',
34
                'unset',
35
            )
36
        );
1 efrain 37
 
38
        // According to the CSS2.1 spec, the places where a
39
        // non-delimiting semicolon can appear are in strings
40
        // escape sequences.   So here is some dumb hack to
41
        // handle quotes.
42
        $len = strlen($css);
43
        $accum = "";
44
        $declarations = array();
45
        $quoted = false;
46
        for ($i = 0; $i < $len; $i++) {
47
            $c = strcspn($css, ";'\"", $i);
48
            $accum .= substr($css, $i, $c);
49
            $i += $c;
50
            if ($i == $len) break;
51
            $d = $css[$i];
52
            if ($quoted) {
53
                $accum .= $d;
54
                if ($d == $quoted) {
55
                    $quoted = false;
56
                }
57
            } else {
58
                if ($d == ";") {
59
                    $declarations[] = $accum;
60
                    $accum = "";
61
                } else {
62
                    $accum .= $d;
63
                    $quoted = $d;
64
                }
65
            }
66
        }
67
        if ($accum != "") $declarations[] = $accum;
68
 
69
        $propvalues = array();
70
        $new_declarations = '';
71
 
72
        /**
73
         * Name of the current CSS property being validated.
74
         */
75
        $property = false;
76
        $context->register('CurrentCSSProperty', $property);
77
 
78
        foreach ($declarations as $declaration) {
79
            if (!$declaration) {
80
                continue;
81
            }
82
            if (!strpos($declaration, ':')) {
83
                continue;
84
            }
85
            list($property, $value) = explode(':', $declaration, 2);
86
            $property = trim($property);
87
            $value = trim($value);
88
            $ok = false;
89
            do {
90
                if (isset($definition->info[$property])) {
91
                    $ok = true;
92
                    break;
93
                }
94
                if (ctype_lower($property)) {
95
                    break;
96
                }
97
                $property = strtolower($property);
98
                if (isset($definition->info[$property])) {
99
                    $ok = true;
100
                    break;
101
                }
102
            } while (0);
103
            if (!$ok) {
104
                continue;
105
            }
1441 ariadna 106
            $result = $universal_attrdef->validate($value, $config, $context);
107
            if ($result === false) {
1 efrain 108
                $result = $definition->info[$property]->validate(
109
                    $value,
110
                    $config,
111
                    $context
112
                );
113
            }
114
            if ($result === false) {
115
                continue;
116
            }
117
            if ($allow_duplicates) {
118
                $new_declarations .= "$property:$result;";
119
            } else {
120
                $propvalues[$property] = $result;
121
            }
122
        }
123
 
124
        $context->destroy('CurrentCSSProperty');
125
 
126
        // procedure does not write the new CSS simultaneously, so it's
127
        // slightly inefficient, but it's the only way of getting rid of
128
        // duplicates. Perhaps config to optimize it, but not now.
129
 
130
        foreach ($propvalues as $prop => $value) {
131
            $new_declarations .= "$prop:$value;";
132
        }
133
 
134
        return $new_declarations ? $new_declarations : false;
135
 
136
    }
137
 
138
}
139
 
140
// vim: et sw=4 sts=4