htmlpurifier-8.x-1.0-rc2/src/Plugin/Filter/HtmlPurifierFilter.php

src/Plugin/Filter/HtmlPurifierFilter.php
<?php

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\Core\StringTranslation\TranslatableMarkup;
use Drupal\filter\Attribute\Filter;
use Drupal\filter\FilterProcessResult;
use Drupal\filter\Plugin\FilterBase;
use Drupal\filter\Plugin\FilterInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * The implementation of HTML Purifier filter.
 */
#[Filter(
  id: 'htmlpurifier',
  title: new TranslatableMarkup('HTML Purifier'),
  type: FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE,
  description: new TranslatableMarkup('Removes malicious HTML code and ensures that the output is standards compliant.'),
)]
class HtmlPurifierFilter extends FilterBase implements ContainerFactoryPluginInterface {

  /**
   * Array of error messages from HTMLPurifier configuration assignments.
   *
   * @var array
   */
  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 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);
  }

  /**
   * Applies the configuration to a HTMLPurifier_Config object.
   */
  protected function applyPurifierConfig(string $configuration): \HTMLPurifier_Config {
    /** @var \HTMLPurifier_Config $purifier_config */
    $purifier_config = \HTMLPurifier_Config::createDefault();

    $settings = Yaml::decode($configuration);
    foreach ($settings as $namespace => $directives) {

      // 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.';
        }
      }
    }

    return $purifier_config;
  }

  /**
   * {@inheritdoc}
   */
  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();
      $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'];
    }

    $form['htmlpurifier_configuration'] = [
      '#type' => 'textarea',
      '#rows' => 50,
      '#title' => t('HTML Purifier Configuration'),
      '#description' => t('These are the config directives in YAML format, according to the <a href="@url">HTML Purifier documentation</a>', ['@url' => 'http://htmlpurifier.org/live/configdoc/plain.html']),
      '#default_value' => $default_value,
      '#element_validate' => [
        [$this, 'settingsFormConfigurationValidate'],
      ],
    ];

    return $form;
  }

  /**
   * Settings form validation callback for htmlpurifier_configuration element.
   */
  public function settingsFormConfigurationValidate(array $element, FormStateInterface $form_state): void {
    $values = $form_state->getValue('filters');
    if (isset($values['htmlpurifier']['settings']['htmlpurifier_configuration'])) {
      $this->configErrors = [];

      // HTMLPurifier library uses trigger_error() for not valid settings.
      set_error_handler([$this, 'configErrorHandler']);
      try {
        $this->applyPurifierConfig($values['htmlpurifier']['settings']['htmlpurifier_configuration']);
      }
      catch (\Exception $ex) {
        // This could be a malformed YAML or any other exception.
        $form_state->setError($element, $ex->getMessage());
      }
      restore_error_handler();

      if (!empty($this->configErrors)) {
        foreach ($this->configErrors as $error) {
          $form_state->setError($element, $error);
        }
        $this->configErrors = [];
      }
    }
  }

  /**
   * Custom error handler to manage invalid purifier configuration assignments.
   */
  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
      // error message. Remove that part from our validation error message.
      $needle = 'invoked on line';
      $pos = strpos($errstr, $needle);
      if ($pos !== FALSE) {
        $message = substr($errstr, 0, $pos - 1);
        $this->configErrors[] = $message;
      }
      else {
        $this->configErrors[] = 'HTMLPurifier configuration is not valid. Error: ' . $errstr;
      }
    }
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc