wikimedia / css-sanitizer
Classes to parse and sanitize CSS
Installs: 4 390 330
Dependents: 1
Suggesters: 0
Security: 0
Stars: 15
Watchers: 12
Forks: 7
pkg:composer/wikimedia/css-sanitizer
Requires
- php: >=8.1
 - ext-iconv: *
 - ext-mbstring: *
 - wikimedia/scoped-callback: 3.0.0 || 4.0.0 || 5.0.0
 - wikimedia/utfnormal: ^3.0.1 || ^4.0.0
 
Requires (Dev)
- mediawiki/mediawiki-codesniffer: 48.0.0
 - mediawiki/mediawiki-phan-config: 0.17.0
 - mediawiki/minus-x: 1.1.3
 - php-parallel-lint/php-console-highlighter: 1.0.0
 - php-parallel-lint/php-parallel-lint: 1.4.0
 - phpunit/phpunit: 10.5.58
 - wikimedia/testing-access-wrapper: ~2.0.0 || ~3.0.0
 - wikimedia/update-history: ^1.0.1
 
README
Wikimedia CSS Parser & Sanitizer
This library implements a CSS tokenizer, parser and grammar matcher in PHP.
Usage
use Wikimedia\CSS\Parser\Parser; use Wikimedia\CSS\Sanitizer\StylesheetSanitizer; /** Parse a stylesheet from a string **/ $parser = Parser::newFromString( $cssText ); $stylesheet = $parser->parseStylesheet(); /** Report any parser errors **/ foreach ( $parser->getParseErrors() as list( $code, $line, $pos ) ) { // $code is a string that should be suitable as a key for an i18n library. // See errors.md for details. $error = lookupI18nMessage( "css-parse-error-$code" ); echo "Parse error: $error at line $line character $pos\n"; } /** Apply sanitization to the stylesheet **/ // If you need to customize the defaults, copy the code of this method and // modify it. $sanitizer = StylesheetSanitizer::newDefault(); $newStylesheet = $sanitizer->sanitize( $stylesheet ); /** Report any sanitizer errors **/ foreach ( $sanitizer->getSanitizationErrors() as list( $code, $line, $pos ) ) { // $code is a string that should be suitable as a key for an i18n library. // See errors.md for details. $error = lookupI18nMessage( "css-sanitization-error-$code" ); echo "Sanitization error: $error at line $line character $pos\n"; } /** Convert the sanitized stylesheet back to text **/ $newText = (string)$newStylesheet; // Or if you'd rather have it minified too $minifiedText = Wikimedia\CSS\Util::stringify( $newStylesheet, [ 'minify' => true ] );
Conformance
The library follows the following grammar specifications:
- CSS Syntax Level 3, 2019-07-16
 - CSS Values and Units Module Level 4, 2024-03-12
 - CSS Selectors Level 3, 2018-11-06
 
The sanitizer recognizes the following CSS modules:
- Align Level 3, 2025-03-11
 - Animations Level 1, 2023-03-02
 - Backgrounds Level 3, 2024-03-11
 - Break Level 3, 2018-12-04
 - Cascade Level 4, 2022-01-13
 - Color Level 4, 2025-04-24
 - Compositing Level 1, 2024-03-21
 - Counter Styles Level 3, 2021-07-27
 - CSS Level 2, 2011-06-07
 - Display Level 3, 2023-03-30
 - Easing Level 1, 2023-02-13
 - Filter Effects Level 1, 2018-12-18
 - Flexbox Level 1, 2018-11-19
 - Fonts Level 3, 2018-09-20
 - Grid Level 1, 2025-03-26
 - Images Level 3, 2023-12-18
 - Lists and Counters Level 3, 2020-11-17
 - Logical Properties and Values Level 1, 2018-08-27
 - Masking Level 1, 2021-08-05
 - Multicol Level 1, 2019-10-15
 - Overflow Level 3, 2023-03-29
 - Overflow Level 4, 2023-03-21
 - Page Level 3, 2023-09-14
 - Position Level 3, 2025-03-11
 - Pseudo-Elements Level 4, 2022-12-30
 - Ruby Level 1, 2022-12-31
 - Scroll Snap Module Level 1
 - Shapes Level 1, 2022-11-15
 - Sizing Level 3, 2021-12-17
 - Sizing Level 4, 2025-02-24
 - Text Level 3, 2024-09-30
 - Text Decorations Level 3, 2022-05-05
 - Transforms Level 1, 2019-02-14
 - Transforms Level 2, 2021-11-09
 - Transitions Level 1, 2018-10-11
 - UI 3 Level 3, 2018-06-21
 - UI 4 Level 4, 2021-03-16
 - Writing Modes Level 4, 2019-07-30
 
And also,
- The 
touch-actionproperty from Pointer Events Level 2, 2019-04-04 :dir()pseudo-class from Selectors Level 4, 2022-11-11- Accessibility related media features from Media Queries Level 5 including prefers-reduced-motion, prefers-reduced-transparency, prefers-contrast and forced-colors.
 light-dark()color function from Color Module Level 5, 2024-02-29
Running tests
composer install --prefer-dist
composer test
Adding properties
CSS specifications typically contain a summary of value grammars in the property index section. These value grammars map directly to PHP code.
| Syntax | css-sanitizer code | 
|---|---|
foo | 
new KeywordMatcher( 'foo' ) | 
foo | bar | 
new KeywordMatcher( [ 'foo', 'bar' ] ) | 
<string> | 
$matcherFactory->string() | 
<url> | 
$matcherFactory->url() | 
<integer> | 
$matcherFactory->integer() | 
<number> | 
$matcherFactory->number() | 
<ratio> | 
$matcherFactory->ratio() | 
<percentage> | 
$matcherFactory->percentage() | 
<length> | 
$matcherFactory->length() | 
<frequency> | 
$matcherFactory->frequency() | 
<angle> | 
$matcherFactory->angle() | 
<time> | 
$matcherFactory->time() | 
<resolution> | 
$matcherFactory->resolution() | 
| Syntax | css-sanitizer code | 
|---|---|
a b | 
new Juxtaposition( [ a, b ] ) | 
a && b | 
UnorderedGroup::allOf( [ a, b ] ) | 
a  || b | 
UnorderedGroup::someOf( [ a, b ] ) | 
a | b | 
new Alternative( [ a, b ] ) | 
| Syntax | css-sanitizer code | 
|---|---|
a* | 
Quantifier::star( a ) | 
a+ | 
Quantifier::plus( a ) | 
a? | 
Quantifier::optional( a ) | 
a{3,4} | 
Quantifier::count( a, 3, 4 ) | 
a# | 
Quantifier::hash( a ) | 
a! | 
new NonEmpty( a ) | 
Releasing a new version
This package uses wikimedia/update-history and its conventions.
See https://www.mediawiki.org/wiki/UpdateHistory for details.
History
We required a CSS sanitizer with several properties:
- Strict parsing according to modern standards.
 - Includes line and character position for all errors.
 - Configurable to limit unsafe constructs such as external URL references.
 - Errors are easily localizable.
 
We could not find a library that fit these requirements, so we created one.
Additional release history is in HISTORY.md.