| 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 | public function validate($css, $config, $context) { |
|---|
| 18 | |
|---|
| 19 | $css = $this->parseCDATA($css); |
|---|
| 20 | |
|---|
| 21 | $definition = $config->getCSSDefinition(); |
|---|
| 22 | |
|---|
| 23 | // we're going to break the spec and explode by semicolons. |
|---|
| 24 | // This is because semicolon rarely appears in escaped form |
|---|
| 25 | // Doing this is generally flaky but fast |
|---|
| 26 | // IT MIGHT APPEAR IN URIs, see HTMLPurifier_AttrDef_CSSURI |
|---|
| 27 | // for details |
|---|
| 28 | |
|---|
| 29 | $declarations = explode(';', $css); |
|---|
| 30 | $propvalues = array(); |
|---|
| 31 | |
|---|
| 32 | foreach ($declarations as $declaration) { |
|---|
| 33 | if (!$declaration) continue; |
|---|
| 34 | if (!strpos($declaration, ':')) continue; |
|---|
| 35 | list($property, $value) = explode(':', $declaration, 2); |
|---|
| 36 | $property = trim($property); |
|---|
| 37 | $value = trim($value); |
|---|
| 38 | $ok = false; |
|---|
| 39 | do { |
|---|
| 40 | if (isset($definition->info[$property])) { |
|---|
| 41 | $ok = true; |
|---|
| 42 | break; |
|---|
| 43 | } |
|---|
| 44 | if (ctype_lower($property)) break; |
|---|
| 45 | $property = strtolower($property); |
|---|
| 46 | if (isset($definition->info[$property])) { |
|---|
| 47 | $ok = true; |
|---|
| 48 | break; |
|---|
| 49 | } |
|---|
| 50 | } while(0); |
|---|
| 51 | if (!$ok) continue; |
|---|
| 52 | // inefficient call, since the validator will do this again |
|---|
| 53 | if (strtolower(trim($value)) !== 'inherit') { |
|---|
| 54 | // inherit works for everything (but only on the base property) |
|---|
| 55 | $result = $definition->info[$property]->validate( |
|---|
| 56 | $value, $config, $context ); |
|---|
| 57 | } else { |
|---|
| 58 | $result = 'inherit'; |
|---|
| 59 | } |
|---|
| 60 | if ($result === false) continue; |
|---|
| 61 | $propvalues[$property] = $result; |
|---|
| 62 | } |
|---|
| 63 | |
|---|
| 64 | // procedure does not write the new CSS simultaneously, so it's |
|---|
| 65 | // slightly inefficient, but it's the only way of getting rid of |
|---|
| 66 | // duplicates. Perhaps config to optimize it, but not now. |
|---|
| 67 | |
|---|
| 68 | $new_declarations = ''; |
|---|
| 69 | foreach ($propvalues as $prop => $value) { |
|---|
| 70 | $new_declarations .= "$prop:$value;"; |
|---|
| 71 | } |
|---|
| 72 | |
|---|
| 73 | return $new_declarations ? $new_declarations : false; |
|---|
| 74 | |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | } |
|---|
| 78 | |
|---|