pokemon-showdown-client/lib/css-sanitizer/Wikimedia/CSS/Sanitizer/Sanitizer.php

141 lines
3.7 KiB
PHP

<?php
/**
* @file
* @license https://opensource.org/licenses/Apache-2.0 Apache-2.0
*/
namespace Wikimedia\CSS\Sanitizer;
use Wikimedia\CSS\Objects\CSSObject;
use Wikimedia\CSS\Objects\CSSObjectList;
use Wikimedia\CSS\Objects\RuleList;
/**
* Base class for CSS sanitizers
*/
abstract class Sanitizer {
/** @var array Sanitization errors. Each error is [ string $tag, int $line, int $pos ] */
protected $sanitizationErrors = [];
/**
* Return all sanitization errors seen so far
* @return array Array of [ string $tag, int $line, int $pos, ... ]
*/
public function getSanitizationErrors() {
return $this->sanitizationErrors;
}
/**
* Clear sanitization errors
*/
public function clearSanitizationErrors() {
$this->sanitizationErrors = [];
}
/**
* Record a sanitization error
* @param string $tag Error tag
* @param CSSObject $object Report the error starting at this object
* @param array $data Extra data about the error.
*/
protected function sanitizationError( $tag, CSSObject $object, array $data = [] ) {
list( $line, $pos ) = $object->getPosition();
$this->sanitizationErrors[] = array_merge( [ $tag, $line, $pos ], $data );
}
/**
* Run another sanitizer over a CSSObject
* @param Sanitizer $sanitizer
* @param CSSObject $object
* @return CSSObject|null
*/
protected function sanitizeObj( Sanitizer $sanitizer, CSSObject $object ) {
$newObj = $sanitizer->doSanitize( $object );
$errors = $sanitizer->getSanitizationErrors();
if ( $errors && $sanitizer !== $this ) {
$this->sanitizationErrors = array_merge( $this->sanitizationErrors, $errors );
$sanitizer->clearSanitizationErrors();
}
return $newObj;
}
/**
* Run a sanitizer over all CSSObjects in a CSSObjectList
* @param Sanitizer $sanitizer
* @param CSSObjectList $list
* @return CSSObjectList
*/
protected function sanitizeList( Sanitizer $sanitizer, CSSObjectList $list ) {
$class = get_class( $list );
$ret = new $class;
foreach ( $list as $obj ) {
$newObj = $sanitizer->doSanitize( $obj );
if ( $newObj ) {
$ret->add( $newObj );
}
}
$errors = $sanitizer->getSanitizationErrors();
if ( $errors && $sanitizer !== $this ) {
$this->sanitizationErrors = array_merge( $this->sanitizationErrors, $errors );
$sanitizer->clearSanitizationErrors();
}
return $ret;
}
/**
* Run a set of RuleSanitizers over all rules in a RuleList
* @param RuleSanitizer[] $ruleSanitizers
* @param RuleList $list
* @return RuleList
*/
protected function sanitizeRules( array $ruleSanitizers, RuleList $list ) {
$ret = new RuleList();
$curIndex = -INF;
foreach ( $list as $rule ) {
foreach ( $ruleSanitizers as $sanitizer ) {
if ( $sanitizer->handlesRule( $rule ) ) {
$indexes = $sanitizer->getIndex();
if ( is_array( $indexes ) ) {
list( $testIndex, $setIndex ) = $indexes;
} else {
$testIndex = $setIndex = $indexes;
}
if ( $testIndex < $curIndex ) {
$this->sanitizationError( 'misordered-rule', $rule );
} else {
$curIndex = $setIndex;
$rule = $this->sanitizeObj( $sanitizer, $rule );
if ( $rule ) {
$ret->add( $rule );
}
}
continue 2;
}
}
$this->sanitizationError( 'unrecognized-rule', $rule );
}
return $ret;
}
/**
* Sanitize a CSS object
* @param CSSObject $object
* @return CSSObject|null Sanitized version of the object, or null if
* sanitization failed
*/
abstract protected function doSanitize( CSSObject $object );
/**
* Sanitize a CSS object
* @param CSSObject $object
* @return CSSObject|null Sanitized version of the object, or null if
* sanitization failed
*/
public function sanitize( CSSObject $object ) {
return $this->doSanitize( $object );
}
}