]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - vendor/wikimedia/css-sanitizer/src/Sanitizer/PropertySanitizer.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / vendor / wikimedia / css-sanitizer / src / Sanitizer / PropertySanitizer.php
1 <?php
2 /**
3  * @file
4  * @license https://opensource.org/licenses/Apache-2.0 Apache-2.0
5  */
6
7 namespace Wikimedia\CSS\Sanitizer;
8
9 use InvalidArgumentException;
10 use Wikimedia\CSS\Grammar\Matcher;
11 use Wikimedia\CSS\Grammar\NothingMatcher;
12 use Wikimedia\CSS\Objects\CSSObject;
13 use Wikimedia\CSS\Objects\ComponentValueList;
14 use Wikimedia\CSS\Objects\Declaration;
15 use Wikimedia\CSS\Util;
16
17 /**
18  * Sanitizes a Declaration
19  */
20 class PropertySanitizer extends Sanitizer {
21
22         /** @var Matcher[] Array mapping declaration names (lowercase) to Matchers for the values */
23         private $knownProperties = [];
24
25         /** @var Matcher|null Matcher for CSS-wide keywords */
26         private $cssWideKeywords = null;
27
28         /**
29          * @param Matcher[] $properties Array mapping declaration names (lowercase)
30          *  to Matchers for the values
31          * @param Matcher $cssWideKeywordsMatcher Matcher for keywords that should
32          *  be recognized for all known properties.
33          */
34         public function __construct( array $properties = [], Matcher $cssWideKeywordsMatcher = null ) {
35                 $this->setKnownProperties( $properties );
36                 $this->setCssWideKeywordsMatcher( $cssWideKeywordsMatcher ?: new NothingMatcher );
37         }
38
39         /**
40          * Access the list of known properties
41          * @return Matcher[]
42          */
43         public function getKnownProperties() {
44                 return $this->knownProperties;
45         }
46
47         /**
48          * Set the list of known properties
49          * @param Matcher[] $properties Array mapping declaration names (lowercase)
50          *  to Matchers for the values
51          */
52         public function setKnownProperties( array $properties ) {
53                 foreach ( $properties as $prop => $matcher ) {
54                         if ( strtolower( $prop ) !== $prop ) {
55                                 throw new InvalidArgumentException( "Property name '$prop' must be lowercased" );
56                         }
57                         if ( !$matcher instanceof Matcher ) {
58                                 throw new InvalidArgumentException( "Value for '$prop' is not a Matcher" );
59                         }
60                 }
61                 $this->knownProperties = $properties;
62         }
63
64         /**
65          * Merge a list of matchers into the list of known properties
66          * @param Matcher[] $properties Array mapping declaration names (lowercase)
67          *  to Matchers for the values
68          * @throws InvalidArgumentException if some property is already defined
69          */
70         public function addKnownProperties( $props ) {
71                 $dups = [];
72                 foreach ( $props as $k => $v ) {
73                         if ( isset( $this->knownProperties[$k] ) && $props[$k] !== $this->knownProperties[$k] ) {
74                                 $dups[] = $k;
75                         }
76                 }
77                 if ( $dups ) {
78                         throw new InvalidArgumentException(
79                                 'Duplicate definitions for properties: ' . join( ' ', $dups )
80                         );
81                 }
82                 $this->setKnownProperties( $this->knownProperties + $props );
83         }
84
85         /**
86          * Fetch the matcher for keywords that should be recognized for all properties.
87          * @return Matcher
88          */
89         public function getCssWideKeywordsMatcher() {
90                 return $this->cssWideKeywords;
91         }
92
93         /**
94          * Set the matcher for keywords that should be recognized for all properties.
95          * @param Matcher $matcher
96          */
97         public function setCssWideKeywordsMatcher( Matcher $matcher ) {
98                 $this->cssWideKeywords = $matcher;
99         }
100
101         protected function doSanitize( CSSObject $object ) {
102                 if ( !$object instanceof Declaration ) {
103                         $this->sanitizationError( 'expected-declaration', $object );
104                         return null;
105                 }
106
107                 $knownProperties = $this->getKnownProperties();
108                 $name = strtolower( $object->getName() );
109                 if ( !isset( $knownProperties[$name] ) ) {
110                         $this->sanitizationError( 'unrecognized-property', $object );
111                         return null;
112                 }
113
114                 $list = $object->getValue();
115                 if ( !$knownProperties[$name]->match( $list, [ 'mark-significance' => true ] ) &&
116                         !$this->getCssWideKeywordsMatcher()->match( $list, [ 'mark-significance' => true ] )
117                 ) {
118                         $cv = Util::findFirstNonWhitespace( $list );
119                         if ( $cv ) {
120                                 $this->sanitizationError( 'bad-value-for-property', $cv, [ $name ] );
121                         } else {
122                                 $this->sanitizationError( 'missing-value-for-property', $object, [ $name ] );
123                         }
124                         return null;
125                 }
126
127                 return $object;
128         }
129 }