Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

Configurator.php

Zuletzt modifiziert: 02.04.2025, 15:04 - Dateigröße: 6.93 KiB


001  <?php
002   
003  /**
004  * @package   s9e\TextFormatter
005  * @copyright Copyright (c) 2010-2022 The s9e authors
006  * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
007  */
008  namespace s9e\TextFormatter\Plugins\Censor;
009   
010  use ArrayAccess;
011  use Countable;
012  use Iterator;
013  use s9e\TextFormatter\Configurator\Collections\NormalizedCollection;
014  use s9e\TextFormatter\Configurator\Helpers\ConfigHelper;
015  use s9e\TextFormatter\Configurator\Helpers\RegexpBuilder;
016  use s9e\TextFormatter\Configurator\Items\Regexp;
017  use s9e\TextFormatter\Configurator\JavaScript\Code;
018  use s9e\TextFormatter\Configurator\JavaScript\RegexpConvertor;
019  use s9e\TextFormatter\Configurator\Traits\CollectionProxy;
020  use s9e\TextFormatter\Plugins\ConfiguratorBase;
021   
022  /**
023  * @method mixed   add(string $key, mixed $value) Add an item to this collection
024  * @method array   asConfig()
025  * @method void    clear()                        Empty this collection
026  * @method bool    contains(mixed $value)         Test whether a given value is present in this collection
027  * @method integer count()
028  * @method mixed   current()
029  * @method void    delete(string $key)            Delete an item from this collection
030  * @method bool    exists(string $key)            Test whether an item of given key exists
031  * @method mixed   get(string $key)               Return a value from this collection
032  * @method mixed   indexOf(mixed $value)          Find the index of a given value
033  * @method integer|string key()
034  * @method mixed   next()
035  * @method string  normalizeKey(string $key)      Normalize an item's key
036  * @method mixed   normalizeValue(mixed $value)   Normalize a value for storage
037  * @method bool    offsetExists(string|integer $offset)
038  * @method mixed   offsetGet(string|integer $offset)
039  * @method void    offsetSet(string|integer $offset, mixed $value)
040  * @method void    offsetUnset(string|integer $offset)
041  * @method string  onDuplicate(string|null $action) Query and set the action to take when add() is called with a key that already exists
042  * @method void    rewind()
043  * @method mixed   set(string $key, mixed $value) Set and overwrite a value in this collection
044  * @method bool    valid()
045  */
046  class Configurator extends ConfiguratorBase implements ArrayAccess, Countable, Iterator
047  {
048      use CollectionProxy;
049   
050      /**
051      * @var array List of whitelisted words as [word => true]
052      */
053      protected $allowed = [];
054   
055      /**
056      * @var string Name of attribute used for the replacement
057      */
058      protected $attrName = 'with';
059   
060      /**
061      * @var NormalizedCollection List of [word => replacement]
062      */
063      protected $collection;
064   
065      /**
066      * @var string Default string used to replace censored words
067      */
068      protected $defaultReplacement = '****';
069   
070      /**
071      * @var array Options passed to the RegexpBuilder
072      */
073      protected $regexpOptions = [
074          'caseInsensitive' => true,
075          'specialChars'    => [
076              '*' => '[\\pL\\pN]*',
077              '?' => '.',
078              ' ' => '\\s*'
079          ]
080      ];
081   
082      /**
083      * @var string Name of the tag used to mark censored words
084      */
085      protected $tagName = 'CENSOR';
086   
087      /**
088      * Plugin's setup
089      *
090      * Will initialize its collection and create the plugin's tag if it does not exist
091      */
092      protected function setUp()
093      {
094          $this->collection = new NormalizedCollection;
095          $this->collection->onDuplicate('replace');
096   
097          if (isset($this->configurator->tags[$this->tagName]))
098          {
099              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  }