[ Index ]

PHP Cross Reference of phpBB-3.3.7-deutsch

title

Body

[close]

/vendor/s9e/text-formatter/src/Plugins/Censor/ -> Configurator.php (source)

   1  <?php
   2  
   3  /**
   4  * @package   s9e\TextFormatter
   5  * @copyright Copyright (c) 2010-2021 The s9e authors
   6  * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
   7  */
   8  namespace s9e\TextFormatter\Plugins\Censor;
   9  
  10  use ArrayAccess;
  11  use Countable;
  12  use Iterator;
  13  use s9e\TextFormatter\Configurator\Collections\NormalizedCollection;
  14  use s9e\TextFormatter\Configurator\Helpers\ConfigHelper;
  15  use s9e\TextFormatter\Configurator\Helpers\RegexpBuilder;
  16  use s9e\TextFormatter\Configurator\Items\Regexp;
  17  use s9e\TextFormatter\Configurator\JavaScript\Code;
  18  use s9e\TextFormatter\Configurator\JavaScript\RegexpConvertor;
  19  use s9e\TextFormatter\Configurator\Traits\CollectionProxy;
  20  use s9e\TextFormatter\Plugins\ConfiguratorBase;
  21  
  22  /**
  23  * @method mixed   add(string $key, mixed $value) Add an item to this collection
  24  * @method array   asConfig()
  25  * @method void    clear()                        Empty this collection
  26  * @method bool    contains(mixed $value)         Test whether a given value is present in this collection
  27  * @method integer count()
  28  * @method mixed   current()
  29  * @method void    delete(string $key)            Delete an item from this collection
  30  * @method bool    exists(string $key)            Test whether an item of given key exists
  31  * @method mixed   get(string $key)               Return a value from this collection
  32  * @method mixed   indexOf(mixed $value)          Find the index of a given value
  33  * @method integer|string key()
  34  * @method mixed   next()
  35  * @method string  normalizeKey(string $key)      Normalize an item's key
  36  * @method mixed   normalizeValue(mixed $value)   Normalize a value for storage
  37  * @method bool    offsetExists(string|integer $offset)
  38  * @method mixed   offsetGet(string|integer $offset)
  39  * @method void    offsetSet(string|integer $offset, mixed $value)
  40  * @method void    offsetUnset(string|integer $offset)
  41  * @method string  onDuplicate(string|null $action) Query and set the action to take when add() is called with a key that already exists
  42  * @method void    rewind()
  43  * @method mixed   set(string $key, mixed $value) Set and overwrite a value in this collection
  44  * @method bool    valid()
  45  */
  46  class Configurator extends ConfiguratorBase implements ArrayAccess, Countable, Iterator
  47  {
  48      use CollectionProxy;
  49  
  50      /**
  51      * @var array List of whitelisted words as [word => true]
  52      */
  53      protected $allowed = [];
  54  
  55      /**
  56      * @var string Name of attribute used for the replacement
  57      */
  58      protected $attrName = 'with';
  59  
  60      /**
  61      * @var NormalizedCollection List of [word => replacement]
  62      */
  63      protected $collection;
  64  
  65      /**
  66      * @var string Default string used to replace censored words
  67      */
  68      protected $defaultReplacement = '****';
  69  
  70      /**
  71      * @var array Options passed to the RegexpBuilder
  72      */
  73      protected $regexpOptions = [
  74          'caseInsensitive' => true,
  75          'specialChars'    => [
  76              '*' => '[\\pL\\pN]*',
  77              '?' => '.',
  78              ' ' => '\\s*'
  79          ]
  80      ];
  81  
  82      /**
  83      * @var string Name of the tag used to mark censored words
  84      */
  85      protected $tagName = 'CENSOR';
  86  
  87      /**
  88      * Plugin's setup
  89      *
  90      * Will initialize its collection and create the plugin's tag if it does not exist
  91      */
  92  	protected function setUp()
  93      {
  94          $this->collection = new NormalizedCollection;
  95          $this->collection->onDuplicate('replace');
  96  
  97          if (isset($this->configurator->tags[$this->tagName]))
  98          {
  99              return;
 100          }
 101  
 102          // Create a tag
 103          $tag = $this->configurator->tags->add($this->tagName);
 104  
 105          // Create the attribute and make it optional
 106          $tag->attributes->add($this->attrName)->required = false;
 107  
 108          // Ensure that censored content can't ever be used by other tags
 109          $tag->rules->ignoreTags();
 110  
 111          // Create a template that renders censored words either as their custom replacement or as
 112          // the default replacement
 113          $tag->template =
 114              '<xsl:choose>
 115                  <xsl:when test="@' . $this->attrName . '">
 116                      <xsl:value-of select="@' . htmlspecialchars($this->attrName) . '"/>
 117                  </xsl:when>
 118                  <xsl:otherwise>' . htmlspecialchars($this->defaultReplacement, ENT_COMPAT) . '</xsl:otherwise>
 119              </xsl:choose>';
 120      }
 121  
 122      /**
 123      * Add a word to the list of uncensored words
 124      *
 125      * @param  string $word Word to exclude from the censored list
 126      * @return void
 127      */
 128  	public function allow($word)
 129      {
 130          $this->allowed[$word] = true;
 131      }
 132  
 133      /**
 134      * Return an instance of s9e\TextFormatter\Plugins\Censor\Helper
 135      *
 136      * @return Helper
 137      */
 138  	public function getHelper()
 139      {
 140          $config = $this->asConfig();
 141          if (isset($config))
 142          {
 143              $config = ConfigHelper::filterConfig($config, 'PHP');
 144          }
 145          else
 146          {
 147              // Use a dummy config with a regexp that doesn't match anything
 148              $config = [
 149                  'attrName' => $this->attrName,
 150                  'regexp'   => '/(?!)/',
 151                  'tagName'  => $this->tagName
 152              ];
 153          }
 154  
 155          return new Helper($config);
 156      }
 157  
 158      /**
 159      * {@inheritdoc}
 160      */
 161  	public function asConfig()
 162      {
 163          $words = $this->getWords();
 164  
 165          if (empty($words))
 166          {
 167              return;
 168          }
 169  
 170          // Create the config
 171          $config = [
 172              'attrName'   => $this->attrName,
 173              'regexp'     => $this->getWordsRegexp(array_keys($words)),
 174              'regexpHtml' => $this->getWordsRegexp(array_map('htmlspecialchars', array_keys($words))),
 175              'tagName'    => $this->tagName
 176          ];
 177  
 178          // Add custom replacements
 179          $replacementWords = [];
 180          foreach ($words as $word => $replacement)
 181          {
 182              if (isset($replacement) && $replacement !== $this->defaultReplacement)
 183              {
 184                  $replacementWords[$replacement][] = $word;
 185              }
 186          }
 187  
 188          foreach ($replacementWords as $replacement => $words)
 189          {
 190              $wordsRegexp = '/^' . RegexpBuilder::fromList($words, $this->regexpOptions) . '$/Diu';
 191  
 192              $regexp = new Regexp($wordsRegexp);
 193              $regexp->setJS(RegexpConvertor::toJS(str_replace('[\\pL\\pN]', '[^\\s!-\\/:-?]', $wordsRegexp)));
 194  
 195              $config['replacements'][] = [$regexp, $replacement];
 196          }
 197  
 198          // Add the whitelist
 199          if (!empty($this->allowed))
 200          {
 201              $config['allowed'] = $this->getWordsRegexp(array_keys($this->allowed));
 202          }
 203  
 204          return $config;
 205      }
 206  
 207      /**
 208      * {@inheritdoc}
 209      */
 210  	public function getJSHints()
 211      {
 212          $hints = [
 213              'CENSOR_HAS_ALLOWED'      => !empty($this->allowed),
 214              'CENSOR_HAS_REPLACEMENTS' => false
 215          ];
 216          foreach ($this->getWords() as $replacement)
 217          {
 218              if (isset($replacement) && $replacement !== $this->defaultReplacement)
 219              {
 220                  $hints['CENSOR_HAS_REPLACEMENTS'] = true;
 221                  break;
 222              }
 223          }
 224  
 225          return $hints;
 226      }
 227  
 228      /**
 229      * Return a list of censored words
 230      *
 231      * @return string[]
 232      */
 233  	protected function getWords()
 234      {
 235          return array_diff_key(iterator_to_array($this->collection), $this->allowed);
 236      }
 237  
 238      /**
 239      * Generate a regexp that matches the given list of words
 240      *
 241      * @param  array   $words List of words
 242      * @return Regexp         Regexp instance with a Unicode-free JS variant
 243      */
 244  	protected function getWordsRegexp(array $words)
 245      {
 246          $expr  = RegexpBuilder::fromList($words, $this->regexpOptions);
 247          $regexp = new Regexp('/(?<![\\pL\\pN])' . $expr . '(?![\\pL\\pN])/Siu');
 248  
 249          // JavaScript regexps don't support Unicode properties, so instead of Unicode letters
 250          // we'll accept any non-whitespace, non-common punctuation
 251          $expr = str_replace('[\\pL\\pN]', '[^\\s!-\\/:-?]', $expr);
 252          $expr = str_replace('(?>',        '(?:',            $expr);
 253          $regexp->setJS('/(?:^|\\W)' . $expr . '(?!\\w)/gi');
 254  
 255          return $regexp;
 256      }
 257  }


Generated: Thu Mar 24 21:31:15 2022 Cross-referenced by PHPXref 0.7.1