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. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
Configurator.php
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\MediaEmbed;
009
010 use InvalidArgumentException;
011 use RuntimeException;
012 use s9e\TextFormatter\Configurator\Helpers\FilterHelper;
013 use s9e\TextFormatter\Configurator\Items\Regexp;
014 use s9e\TextFormatter\Configurator\Items\Tag;
015 use s9e\TextFormatter\Configurator\JavaScript\Dictionary;
016 use s9e\TextFormatter\Plugins\ConfiguratorBase;
017 use s9e\TextFormatter\Plugins\MediaEmbed\Configurator\Collections\CachedDefinitionCollection;
018 use s9e\TextFormatter\Plugins\MediaEmbed\Configurator\TemplateBuilder;
019
020 class Configurator extends ConfiguratorBase
021 {
022 /**
023 * @var array List of filters that are explicitly allowed in attribute definitions
024 */
025 public $allowedFilters = ['htmlspecialchars_decode', 'stripslashes', 'urldecode'];
026
027 /**
028 * @var bool Whether to create the MEDIA BBCode
029 */
030 protected $createMediaBBCode = true;
031
032 /**
033 * @var Configurator\Collections\SiteDefinitionCollection Default sites
034 */
035 public $defaultSites;
036
037 /**
038 * {@inheritdoc}
039 */
040 protected $quickMatch = '://';
041
042 /**
043 * {@inheritdoc}
044 */
045 protected $regexp = '/\\bhttps?:\\/\\/[^["\'\\s]+/Si';
046
047 /**
048 * @var array Configured sites
049 */
050 protected $sites = [];
051
052 /**
053 * @var string Name of the tag used to handle embeddable URLs
054 */
055 protected $tagName = 'MEDIA';
056
057 /**
058 * @var TemplateBuilder
059 */
060 protected $templateBuilder;
061
062 /**
063 * {@inheritdoc}
064 */
065 protected function setUp()
066 {
067 $this->defaultSites = new CachedDefinitionCollection;
068 $this->templateBuilder = new TemplateBuilder;
069
070 $this->configurator->registeredVars['MediaEmbed.hosts'] = new Dictionary;
071 $this->configurator->registeredVars['MediaEmbed.sites'] = new Dictionary;
072
073 // Create a MEDIA tag
074 $this->createMediaTag();
075
076 // Create a [MEDIA] BBCode if applicable
077 if ($this->createMediaBBCode)
078 {
079 $this->configurator->BBCodes->set($this->tagName, ['contentAttributes' => ['url']]);
080 }
081 }
082
083 /**
084 * {@inheritdoc}
085 */
086 public function asConfig()
087 {
088 if (empty($this->sites))
089 {
090 return;
091 }
092
093 return [
094 'quickMatch' => $this->quickMatch,
095 'regexp' => $this->regexp,
096 'tagName' => $this->tagName
097 ];
098 }
099
100 /**
101 * Add a media site
102 *
103 * @param string $siteId Site's ID
104 * @param array $siteConfig Site's config
105 * @return Tag Tag created for this site
106 */
107 public function add($siteId, array $siteConfig = null)
108 {
109 // Normalize or retrieve the site definition
110 $siteId = $this->normalizeId($siteId);
111 if (isset($siteConfig))
112 {
113 $siteConfig = $this->defaultSites->normalizeValue($siteConfig);
114 }
115 else
116 {
117 $siteConfig = $this->defaultSites->get($siteId);
118 }
119 $siteConfig['extract'] = $this->convertRegexps($siteConfig['extract']);
120 $siteConfig['scrape'] = $this->convertScrapes($siteConfig['scrape']);
121
122 // Check the safety of attribute filters
123 $this->checkAttributeFilters($siteConfig['attributes']);
124
125 // Create the tag for this site
126 $tag = $this->addTag($siteId, $siteConfig);
127
128 // Update the configurator's data
129 $this->sites[$siteId] = $siteConfig;
130 foreach ($siteConfig['host'] as $host)
131 {
132 $this->configurator->registeredVars['MediaEmbed.hosts'][$host] = $siteId;
133 }
134 $this->configurator->registeredVars['MediaEmbed.sites'][$siteId] = [$siteConfig['extract'], $siteConfig['scrape']];
135
136 return $tag;
137 }
138
139 /**
140 * Return the list of configured sites
141 *
142 * @return array Site's ID as keys, site's config as values
143 */
144 public function getSites()
145 {
146 return $this->sites;
147 }
148
149 /**
150 * Create and return a tag that handles given media site
151 *
152 * @param string $siteId
153 * @param array $siteConfig
154 * @return Tag
155 */
156 protected function addTag($siteId, array $siteConfig)
157 {
158 $tag = new Tag([
159 'attributes' => $this->getAttributesConfig($siteConfig),
160 'rules' => [
161 'allowChild' => 'URL',
162 'autoClose' => true,
163 'denyChild' => [$siteId, $this->tagName]
164 ],
165 'template' => $this->templateBuilder->build($siteId, $siteConfig)
166 ]);
167
168 $this->configurator->templateNormalizer->normalizeTag($tag);
169 $this->configurator->templateChecker->checkTag($tag);
170 $this->configurator->tags->add($siteId, $tag);
171
172 return $tag;
173 }
174
175 /**
176 * Check the safety of given attributes
177 *
178 * @param array $attributes
179 * @return void
180 */
181 protected function checkAttributeFilters(array $attributes)
182 {
183 foreach ($attributes as $attrConfig)
184 {
185 if (empty($attrConfig['filterChain']))
186 {
187 continue;
188 }
189 foreach ($attrConfig['filterChain'] as $filter)
190 {
191 if (!FilterHelper::isAllowed($filter, $this->allowedFilters))
192 {
193 throw new RuntimeException("Filter '$filter' is not allowed in media sites");
194 }
195 }
196 }
197 }
198
199 /**
200 * Convert given regexp to a [regexp, map] pair
201 *
202 * @param string $regexp Original regexp
203 * @return array [regexp, [list of captures' names]]
204 */
205 protected function convertRegexp($regexp)
206 {
207 $regexp = new Regexp($regexp);
208
209 return [$regexp, $regexp->getCaptureNames()];
210 }
211
212 /**
213 * Convert a list of regexps
214 *
215 * @param string[] $regexps Original list
216 * @return array[] Converted list
217 */
218 protected function convertRegexps(array $regexps)
219 {
220 return array_map([$this, 'convertRegexp'], $regexps);
221 }
222
223 /**
224 * Convert all regexps in a scraping config
225 *
226 * @param array $config Original config
227 * @return array Converted config
228 */
229 protected function convertScrapeConfig(array $config)
230 {
231 $config['extract'] = $this->convertRegexps($config['extract']);
232 $config['match'] = $this->convertRegexps($config['match']);
233
234 return $config;
235 }
236
237 /**
238 * Convert all regexps in a list of scraping configs
239 *
240 * @param array[] $scrapes Original config
241 * @return array[] Converted config
242 */
243 protected function convertScrapes(array $scrapes)
244 {
245 return array_map([$this, 'convertScrapeConfig'], $scrapes);
246 }
247
248 /**
249 * Create the default MEDIA tag
250 *
251 * @return void
252 */
253 protected function createMediaTag()
254 {
255 $tag = $this->configurator->tags->add($this->tagName);
256
257 // This tag should not need to be closed and should not contain itself
258 $tag->rules->autoClose();
259 $tag->rules->denyChild($this->tagName);
260
261 // Empty this tag's filter chain and add our tag filter
262 $tag->filterChain->clear();
263 $tag->filterChain
264 ->append(__NAMESPACE__ . '\\Parser::filterTag')
265 ->resetParameters()
266 ->addParameterByName('tag')
267 ->addParameterByName('parser')
268 ->addParameterByName('MediaEmbed.hosts')
269 ->addParameterByName('MediaEmbed.sites')
270 ->addParameterByName('cacheDir')
271 ->setJS(file_get_contents(__DIR__ . '/Parser/tagFilter.js'));
272 }
273
274 /**
275 * Return the list of named captures from a list of [regexp, map] pairs
276 *
277 * @param array[] $regexps List of [regexp, map] pairs
278 * @return string[]
279 */
280 protected function getAttributeNamesFromRegexps(array $regexps)
281 {
282 $attrNames = [];
283 foreach ($regexps as list($regexp, $map))
284 {
285 $attrNames += array_flip(array_filter($map));
286 }
287
288 return $attrNames;
289 }
290
291 /**
292 * Get the attributes config for given site config
293 *
294 * @param array $siteConfig Site's config
295 * @return array Map of [attrName => attrConfig]
296 */
297 protected function getAttributesConfig(array $siteConfig)
298 {
299 $attrNames = $this->getAttributeNamesFromRegexps($siteConfig['extract']);
300 foreach ($siteConfig['scrape'] as $scrapeConfig)
301 {
302 $attrNames += $this->getAttributeNamesFromRegexps($scrapeConfig['extract']);
303 }
304
305 $attributes = $siteConfig['attributes'] + array_fill_keys(array_keys($attrNames), []);
306 foreach ($attributes as &$attrConfig)
307 {
308 $attrConfig += ['required' => false];
309 }
310 unset($attrConfig);
311
312 return $attributes;
313 }
314
315 /**
316 * Validate and normalize a site ID
317 *
318 * @param string $siteId
319 * @return string
320 */
321 protected function normalizeId($siteId)
322 {
323 $siteId = strtolower($siteId);
324
325 if (!preg_match('(^[a-z0-9]+$)', $siteId))
326 {
327 throw new InvalidArgumentException('Invalid site ID');
328 }
329
330 return $siteId;
331 }
332 }