praiadeseselle/site/modules/FileValidatorSvgSanitizer/FileValidatorSvgSanitizer.module.php

198 lines
5.4 KiB
PHP
Raw Permalink Normal View History

2022-04-05 12:43:22 +02:00
<?php namespace ProcessWire;
/**
* Validates and/or sanitizes SVG files in ProcessWire
*
* Uses the svg-sanitizer library:
* https://github.com/darylldoyle/svg-sanitizer
*
* The FileValidatorModule interface and this module file are MIT licensed,
* while the svg-sanitizer library in the /svgSanitize/ dir is GPL 2.0.
* As a result, if your installation does not support GPL code, you should
* inquire with the developer of the sanitizer lib before using this module
* in your project: https://github.com/darylldoyle
*
* Originally developed by Adrian and Ryan in 2015 and updated in 2020
* to change the SVG sanitizer library this module uses. Additional updates
* were also made in 2021.
*
* @property int|bool $removeRemoteReferences
* @property int|bool $minify
* @property string $customTags
* @property string $customAttrs
*
*/
class FileValidatorSvgSanitizer extends FileValidatorModule {
public static function getModuleInfo() {
return array(
'title' => 'SVG File Sanitizer/Validator',
'summary' => 'Validates and/or sanitizes uploaded SVG files.',
'version' => 5,
'author' => 'Adrian and Ryan',
'autoload' => false,
'singular' => false,
'validates' => array('svg'),
'requires' => 'ProcessWire>=3.0.148',
);
}
/**
* @var \enshrined\svgSanitize\Sanitizer
*
*/
protected $svgSanitizer = null;
/**
* Construct
*
*/
public function __construct() {
$this->set('removeRemoteReferences', 1);
$this->set('minify', 0);
$this->set('customTags', '');
$this->set('customAttrs', '');
}
/**
* Module init
*
*/
public function init() {
$this->getSvgSanitizer();
}
/**
* Get the SVG Sanitizer instance
*
* @return \enshrined\svgSanitize\Sanitizer
*
*/
public function getSvgSanitizer() {
if($this->svgSanitizer !== null) return $this->svgSanitizer;
$ns = 'enshrined\svgSanitize';
$classLoader = $this->wire()->classLoader;
if(!$classLoader->hasNamespace($ns)) $classLoader->addNamespace($ns, __DIR__ . '/svgSanitize/');
$className = $ns . '\Sanitizer';
$this->svgSanitizer = new $className();
$this->svgSanitizer->removeRemoteReferences((bool) $this->removeRemoteReferences);
$this->svgSanitizer->minify((bool) $this->minify);
list($tags, $attrs) = array($this->customTags, $this->customAttrs);
if($tags || $attrs) {
require_once(__DIR__ . '/FileValidatorSvgSanitizer.data.php');
if($tags) {
FileValidatorSvgSanitizerTags::add($tags);
$this->svgSanitizer->setAllowedTags(new FileValidatorSvgSanitizerTags());
}
if($attrs) {
FileValidatorSvgSanitizerAttributes::add($attrs);
$this->svgSanitizer->setAllowedAttrs(new FileValidatorSvgSanitizerAttributes());
}
}
return $this->svgSanitizer;
}
/**
* Is the given SVG file valid?
*
* This is for implementation of PW's FileValidator interface.
*
* This method should return:
* - boolean TRUE if file is valid
* - boolean FALSE if file is not valid
* - integer 1 if file is valid as a result of sanitization performed by this method
*
* If method wants to explain why the file is not valid, it should call $this->error('reason why not valid').
*
* @param string $filename Full path and filename to the file
* @return bool|int
*
*/
protected function isValidFile($filename) {
$svgSanitizer = $this->getSvgSanitizer();
$svgDirty = file_get_contents($filename);
$svgClean = $svgSanitizer->sanitize($svgDirty);
$svgIssues = $svgSanitizer->getXmlIssues();
if(!empty($svgIssues)) {
// log found issues
$issues = array();
foreach($svgIssues as $issue) {
$issue = "$issue[message] (line $issue[line])";
$issues[$issue] = $issue;
}
if($svgClean === false) {
foreach($issues as $issue) $this->error($issue);
} else if(count($issues)) {
$this->log("SvgSanitizer: " . basename($filename) . ": " . implode(', ', $issues));
}
}
if($svgClean === false) {
// sanitize failed
return false;
} else if($svgDirty === $svgClean) {
// no changes after sanitization, file is ok. this is sort of unlikely
// as SvgSanitizer seems to apply minor changes either way
return true;
}
// write new sanitized svg file
$files = $this->wire()->files;
$files->unlink($filename);
if($files->filePutContents($filename, $svgClean) === false) return false;
return 1;
}
/**
* Return the data from the default whitelist
*
* This method doesnt do anything for this module, it is just here if you want to
* know what are the whitelisted tags and attributes.
*
* @return array
*
*/
public function getDefaultWhitelist() {
return array(
'tags' => \enshrined\svgSanitize\data\AllowedTags::getTags(),
'attributes' => \enshrined\svgSanitize\data\AllowedAttributes::getAttributes(),
);
}
/**
* Return data from the customized whitelist
*
* @return array
*
*/
public function getWhitelist() {
$this->getSvgSanitizer();
return array(
'tags' => FileValidatorSvgSanitizerTags::getTags(),
'attributes' => FileValidatorSvgSanitizerAttributes::getAttributes(),
);
}
/**
* Install
*
* @throws WireException
*
*/
public function ___install() {
$exts = get_loaded_extensions();
if(!in_array('dom', $exts)) {
throw new WireException('This module requires the PHP “dom” extension (ext-dom)');
}
if(!in_array('libxml', $exts)) {
throw new WireException('This module requires the PHP “libxml” extension (ext-libxml)');
}
}
}