Skip to content
Snippets Groups Projects
Commit 38c3d19b authored by m4olivei's avatar m4olivei Committed by Lucas Hedding
Browse files

Issue #2989756 by juanolalla: HTMLPurifier Serializer caches into vendor directory by default

parent 3eaf7f24
Branches
Tags
1 merge request!1Resolve #2989756 "Htmlpurifier serializer caches"
Pipeline #333559 passed
cache.serializer_path: ''
......@@ -5,3 +5,10 @@ filter_settings.htmlpurifier:
htmlpurifier_configuration:
type: string
label: 'Configuration of HTMLPurifier'
htmlpurifier.settings:
type: config_object
label: 'HTML Purifier settings'
mapping:
cache.serializer_path:
type: string
label: 'Absolute path with no trailing slash to store serialized definitions.'
......@@ -2,6 +2,4 @@ name: 'HTML Purifier'
type: module
description: 'Filter that removes malicious HTML and ensures standards compliant output.'
package: Filter
core: 8.x
core_version_requirement: ^8 || ^9 || ^10
php: 7.1
core_version_requirement: ^10.2
......@@ -3,9 +3,13 @@
namespace Drupal\htmlpurifier\Plugin\Filter;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\filter\FilterProcessResult;
use Drupal\filter\Plugin\FilterBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* The implementation of HTML Purifier filter.
......@@ -17,7 +21,7 @@ use Drupal\filter\Plugin\FilterBase;
* type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE
* )
*/
class HtmlPurifierFilter extends FilterBase {
class HtmlPurifierFilter extends FilterBase implements ContainerFactoryPluginInterface {
/**
* Array of error messages from HTMLPurifier configuration assignments.
......@@ -26,16 +30,48 @@ class HtmlPurifierFilter extends FilterBase {
*/
protected $configErrors = [];
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
protected FileSystemInterface $fileSystem,
protected ConfigFactoryInterface $configFactory,
) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
}
/**
* {@inheritdoc}
*/
public function process($text, $langcode) {
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('file_system'),
$container->get('config.factory'),
);
}
/**
* {@inheritdoc}
*/
public function process($text, $langcode): FilterProcessResult {
if (!empty($this->settings['htmlpurifier_configuration'])) {
$purifier_config = $this->applyPurifierConfig($this->settings['htmlpurifier_configuration']);
}
else {
$purifier_config = \HTMLPurifier_Config::createDefault();
}
// Set Serializer path to the temporary directory, so it can be written.
$cache_serializer_path = $this->configFactory->get('htmlpurifier.settings')->get('cache.serializer_path');
if (empty($cache_serializer_path)) {
$cache_serializer_path = $this->fileSystem->getTempDirectory() . '/htmlpurifier';
}
$this->fileSystem->prepareDirectory($cache_serializer_path, FileSystemInterface::MODIFY_PERMISSIONS | FileSystemInterface::CREATE_DIRECTORY);
$purifier_config->set('Cache.SerializerPath', $cache_serializer_path);
$purifier = new \HTMLPurifier($purifier_config);
$purified_text = $purifier->purify($text);
return new FilterProcessResult($purified_text);
......@@ -50,13 +86,18 @@ class HtmlPurifierFilter extends FilterBase {
$settings = Yaml::decode($configuration);
foreach ($settings as $namespace => $directives) {
if (is_array($directives)) {
foreach ($directives as $key => $value) {
$purifier_config->set("$namespace.$key", $value);
// Keep Cache managing out of the text formats scope.
if ($namespace !== 'Cache') {
if (is_array($directives)) {
foreach ($directives as $key => $value) {
$purifier_config->set("$namespace.$key", $value);
}
}
else {
$this->configErrors[] = 'Invalid value for namespace $namespace, must be an array of directives.';
}
}
else {
$this->configErrors[] = 'Invalid value for namespace $namespace, must be an array of directives.';
}
}
......@@ -66,11 +107,16 @@ class HtmlPurifierFilter extends FilterBase {
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
public function settingsForm(array $form, FormStateInterface $form_state): array {
if (empty($this->settings['htmlpurifier_configuration'])) {
/** @var \HTMLPurifier_Config $purifier_config */
$purifier_config = \HTMLPurifier_Config::createDefault();
$default_value = Yaml::encode($purifier_config->getAll());
$config_array = $purifier_config->getAll();
// Keep Cache managing out of the text formats scope.
unset($config_array['Cache']);
$default_value = Yaml::encode($config_array);
}
else {
$default_value = $this->settings['htmlpurifier_configuration'];
......@@ -121,7 +167,7 @@ class HtmlPurifierFilter extends FilterBase {
/**
* Custom error handler to manage invalid purifier configuration assignments.
*/
public function configErrorHandler(int $errno, string $errstr) {
public function configErrorHandler(int $errno, string $errstr): void {
// Do not set a validation error if the error is about a deprecated use.
if ($errno < E_DEPRECATED) {
// \HTMLPurifier_Config::triggerError() adds ' invoked on line ...' to the
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment