This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * Loading Slots. |
||
5 | */ |
||
6 | declare(strict_types = 1); |
||
7 | |||
8 | namespace HDNET\Autoloader\Loader; |
||
9 | |||
10 | use Doctrine\Common\Annotations\AnnotationReader; |
||
11 | use HDNET\Autoloader\Annotation\EnableRichText; |
||
12 | use HDNET\Autoloader\Annotation\NoHeader; |
||
13 | use HDNET\Autoloader\Annotation\WizardTab; |
||
14 | use HDNET\Autoloader\Loader; |
||
15 | use HDNET\Autoloader\LoaderInterface; |
||
16 | use HDNET\Autoloader\Service\NameMapperService; |
||
17 | use HDNET\Autoloader\SmartObjectRegister; |
||
18 | use HDNET\Autoloader\Utility\ClassNamingUtility; |
||
19 | use HDNET\Autoloader\Utility\FileUtility; |
||
20 | use HDNET\Autoloader\Utility\IconUtility; |
||
21 | use HDNET\Autoloader\Utility\ModelUtility; |
||
22 | use HDNET\Autoloader\Utility\ReflectionUtility; |
||
23 | use HDNET\Autoloader\Utility\TranslateUtility; |
||
24 | use TYPO3\CMS\Core\Imaging\IconProvider\BitmapIconProvider; |
||
25 | use TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider; |
||
26 | use TYPO3\CMS\Core\Imaging\IconRegistry; |
||
27 | use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; |
||
28 | use TYPO3\CMS\Core\Utility\GeneralUtility; |
||
29 | use TYPO3\CMS\Extbase\Utility\ExtensionUtility; |
||
30 | |||
31 | /** |
||
32 | * Loading Slots. |
||
33 | */ |
||
34 | class ContentObjects implements LoaderInterface |
||
35 | { |
||
36 | /** |
||
37 | * Prepare the content object loader. |
||
38 | */ |
||
39 | public function prepareLoader(Loader $loader, int $type): array |
||
40 | { |
||
41 | $loaderInformation = []; |
||
42 | |||
43 | /** @var AnnotationReader $annotationReader */ |
||
44 | $annotationReader = GeneralUtility::makeInstance(AnnotationReader::class); |
||
45 | |||
46 | $modelPath = ExtensionManagementUtility::extPath($loader->getExtensionKey()) . 'Classes/Domain/Model/Content/'; |
||
47 | $models = FileUtility::getBaseFilesInDir($modelPath, 'php'); |
||
48 | if (!empty($models)) { |
||
49 | TranslateUtility::assureLabel( |
||
50 | 'tt_content.' . |
||
51 | $loader->getExtensionKey() . '.header', |
||
52 | $loader->getExtensionKey(), |
||
53 | $loader->getExtensionKey() . ' (Header)' |
||
54 | ); |
||
55 | } |
||
56 | foreach ($models as $model) { |
||
57 | $key = GeneralUtility::camelCaseToLowerCaseUnderscored($model); |
||
58 | $className = ClassNamingUtility::getFqnByPath( |
||
59 | $loader->getVendorName(), |
||
60 | $loader->getExtensionKey(), |
||
61 | 'Domain/Model/Content/' . $model |
||
62 | ); |
||
63 | if (!$loader->isInstantiableClass($className)) { |
||
64 | continue; |
||
65 | } |
||
66 | $fieldConfiguration = []; |
||
67 | $richTextFields = []; |
||
68 | $noHeader = $this->isTaggedWithNoHeader($className); |
||
69 | |||
70 | $reflectionClass = new \ReflectionClass($className); |
||
71 | |||
72 | // create labels in the ext_tables run, to have a valid DatabaseConnection |
||
73 | if (LoaderInterface::EXT_TABLES === $type) { |
||
74 | TranslateUtility::assureLabel('wizard.' . $key, $loader->getExtensionKey(), $key . ' (Title)', null, 'tt_content'); |
||
75 | TranslateUtility::assureLabel( |
||
76 | 'wizard.' . $key . '.description', |
||
77 | $loader->getExtensionKey(), |
||
78 | $key . ' (Description)', |
||
79 | null, |
||
80 | 'tt_content' |
||
81 | ); |
||
82 | $fieldConfiguration = $this->getClassPropertiesInLowerCaseUnderscored($className); |
||
83 | $defaultFields = $this->getDefaultTcaFields($noHeader, null); |
||
84 | $fieldConfiguration = array_diff($fieldConfiguration, $defaultFields); |
||
85 | |||
86 | // RTE manipulation |
||
87 | foreach ($reflectionClass->getProperties() as $property) { |
||
88 | $richTextField = $annotationReader->getPropertyAnnotation($property, EnableRichText::class); |
||
89 | if (null === $richTextField) { |
||
90 | continue; |
||
91 | } |
||
92 | |||
93 | $search = array_search( |
||
94 | GeneralUtility::camelCaseToLowerCaseUnderscored($property->getName()), |
||
95 | $fieldConfiguration, |
||
96 | true |
||
97 | ); |
||
98 | if (false !== $search) { |
||
99 | $richTextFields[] = $fieldConfiguration[$search]; |
||
100 | } |
||
101 | } |
||
102 | } |
||
103 | |||
104 | $entry = [ |
||
105 | 'fieldConfiguration' => implode(',', $fieldConfiguration), |
||
106 | 'richTextFields' => $richTextFields, |
||
107 | 'modelClass' => $className, |
||
108 | 'model' => $model, |
||
109 | 'icon' => IconUtility::getByModelName($className, false), |
||
110 | 'iconExt' => IconUtility::getByModelName($className, true), |
||
111 | 'noHeader' => $noHeader, |
||
112 | 'tabInformation' => (string)$annotationReader->getClassAnnotation($reflectionClass, WizardTab::class), |
||
113 | ]; |
||
114 | |||
115 | SmartObjectRegister::register($entry['modelClass']); |
||
116 | $loaderInformation[$key] = $entry; |
||
117 | } |
||
118 | |||
119 | $this->checkAndCreateDummyTemplates($loaderInformation, $loader); |
||
120 | |||
121 | return $loaderInformation; |
||
122 | } |
||
123 | |||
124 | /** |
||
125 | * Run the loading process for the ext_tables.php file. |
||
126 | */ |
||
127 | public function loadExtensionTables(Loader $loader, array $loaderInformation): void |
||
128 | { |
||
129 | if (empty($loaderInformation)) { |
||
130 | return; |
||
131 | } |
||
132 | $createWizardHeader = []; |
||
133 | $predefinedWizards = [ |
||
134 | 'common', |
||
135 | 'special', |
||
136 | 'forms', |
||
137 | 'plugins', |
||
138 | ]; |
||
139 | |||
140 | // Add the divider |
||
141 | $GLOBALS['TCA']['tt_content']['columns']['CType']['config']['items'][] = [ |
||
142 | TranslateUtility::getLllString( |
||
143 | 'tt_content.' . $loader->getExtensionKey() . '.header', |
||
144 | $loader->getExtensionKey(), |
||
145 | null, |
||
146 | 'tt_content' |
||
147 | ), |
||
148 | '--div--', |
||
149 | ]; |
||
150 | |||
151 | foreach ($loaderInformation as $e => $config) { |
||
152 | SmartObjectRegister::register($config['modelClass']); |
||
153 | $typeKey = $loader->getExtensionKey() . '_' . $e; |
||
154 | |||
155 | ExtensionManagementUtility::addPlugin([ |
||
156 | TranslateUtility::getLllOrHelpMessage( |
||
157 | 'content.element.' . $e, |
||
158 | $loader->getExtensionKey(), |
||
159 | 'tt_content' |
||
160 | ), |
||
161 | $typeKey, |
||
162 | $config['iconExt'], |
||
163 | ], 'CType', $loader->getExtensionKey()); |
||
164 | |||
165 | if (!isset($GLOBALS['TCA']['tt_content']['types'][$typeKey]['showitem']) || empty($GLOBALS['TCA']['tt_content']['types'][$typeKey]['showitem'])) { |
||
166 | $baseTcaConfiguration = $this->wrapDefaultTcaConfiguration( |
||
167 | $config['fieldConfiguration'], |
||
168 | (bool)$config['noHeader'] |
||
169 | ); |
||
170 | |||
171 | if (ExtensionManagementUtility::isLoaded('gridelements')) { |
||
172 | $baseTcaConfiguration .= ',tx_gridelements_container,tx_gridelements_columns'; |
||
173 | } |
||
174 | |||
175 | $GLOBALS['TCA']['tt_content']['types'][$typeKey]['showitem'] = $baseTcaConfiguration; |
||
176 | } |
||
177 | |||
178 | // RTE |
||
179 | if (isset($config['richTextFields']) && \is_array($config['richTextFields']) && $config['richTextFields']) { |
||
180 | foreach ($config['richTextFields'] as $field) { |
||
181 | $conf = [ |
||
182 | 'config' => [ |
||
183 | 'type' => 'text', |
||
184 | 'enableRichtext' => '1', |
||
185 | 'richtextConfiguration' => 'default', |
||
186 | ], |
||
187 | ]; |
||
188 | $GLOBALS['TCA']['tt_content']['types'][$typeKey]['columnsOverrides'][$field] = $conf; |
||
189 | } |
||
190 | } |
||
191 | |||
192 | IconUtility::addTcaTypeIcon('tt_content', $typeKey, $config['icon']); |
||
193 | |||
194 | $tabName = $config['tabInformation'] ?: $loader->getExtensionKey(); |
||
195 | if (!\in_array($tabName, $predefinedWizards, true) && !\in_array($tabName, $createWizardHeader, true)) { |
||
196 | $createWizardHeader[] = $tabName; |
||
197 | } |
||
198 | |||
199 | /** @var IconRegistry $iconRegistry */ |
||
200 | $provider = BitmapIconProvider::class; |
||
201 | if ('svg' === mb_substr(mb_strtolower($config['iconExt']), -3)) { |
||
202 | $provider = SvgIconProvider::class; |
||
203 | } |
||
204 | $iconRegistry = GeneralUtility::makeInstance(IconRegistry::class); |
||
205 | $iconRegistry->registerIcon($tabName . '-' . $typeKey, $provider, ['source' => $config['iconExt']]); |
||
206 | |||
207 | ExtensionManagementUtility::addPageTSConfig(' |
||
208 | mod.wizards.newContentElement.wizardItems.' . $tabName . '.elements.' . $typeKey . ' { |
||
209 | icon = ' . $config['icon'] . ' |
||
210 | iconIdentifier = ' . $tabName . '-' . $typeKey . ' |
||
211 | title = ' . TranslateUtility::getLllOrHelpMessage('wizard.' . $e, $loader->getExtensionKey()) . ' |
||
212 | description = ' . TranslateUtility::getLllOrHelpMessage( |
||
213 | 'wizard.' . $e . '.description', |
||
214 | $loader->getExtensionKey() |
||
215 | ) . ' |
||
216 | tt_content_defValues { |
||
217 | CType = ' . $typeKey . ' |
||
218 | } |
||
219 | } |
||
220 | mod.wizards.newContentElement.wizardItems.' . $tabName . '.show := addToList(' . $typeKey . ')'); |
||
221 | $cObjectConfiguration = [ |
||
222 | 'extensionKey' => $loader->getExtensionKey(), |
||
223 | 'backendTemplatePath' => 'EXT:' . $loader->getExtensionKey() . '/Resources/Private/Templates/Content/' . $config['model'] . 'Backend.html', |
||
224 | 'modelClass' => $config['modelClass'], |
||
225 | ]; |
||
226 | |||
227 | $GLOBALS['TYPO3_CONF_VARS']['AUTOLOADER']['ContentObject'][$loader->getExtensionKey() . '_' . GeneralUtility::camelCaseToLowerCaseUnderscored($config['model'])] = $cObjectConfiguration; |
||
228 | } |
||
229 | |||
230 | if ($createWizardHeader) { |
||
0 ignored issues
–
show
|
|||
231 | foreach ($createWizardHeader as $element) { |
||
232 | ExtensionManagementUtility::addPageTSConfig(' |
||
233 | mod.wizards.newContentElement.wizardItems.' . $element . ' { |
||
234 | show = * |
||
235 | header = ' . TranslateUtility::getLllOrHelpMessage('wizard.' . $element . '.header', $loader->getExtensionKey()) . ' |
||
236 | }'); |
||
237 | } |
||
238 | } |
||
239 | } |
||
240 | |||
241 | /** |
||
242 | * Run the loading process for the ext_localconf.php file. |
||
243 | */ |
||
244 | public function loadExtensionConfiguration(Loader $loader, array $loaderInformation): void |
||
245 | { |
||
246 | if (empty($loaderInformation)) { |
||
247 | return; |
||
248 | } |
||
249 | static $loadPlugin = true; |
||
250 | $csc = ExtensionManagementUtility::isLoaded('css_styled_content'); |
||
251 | $typoScript = ''; |
||
252 | |||
253 | if ($loadPlugin) { |
||
254 | $loadPlugin = false; |
||
255 | ExtensionUtility::configurePlugin('HDNET.autoloader', 'Content', ['Content' => 'index'], ['Content' => '']); |
||
256 | if (!$csc) { |
||
257 | $typoScript .= 'tt_content = CASE |
||
258 | tt_content.key.field = CType'; |
||
259 | } |
||
260 | } |
||
261 | foreach ($loaderInformation as $e => $config) { |
||
262 | $typoScript .= ' |
||
263 | tt_content.' . $loader->getExtensionKey() . '_' . $e . ' = COA |
||
264 | tt_content.' . $loader->getExtensionKey() . '_' . $e . ' { |
||
265 | ' . ($config['noHeader'] ? '' : '10 =< lib.stdheader') . ' |
||
266 | 20 = USER |
||
267 | 20 { |
||
268 | userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run |
||
269 | extensionName = Autoloader |
||
270 | pluginName = Content |
||
271 | vendorName = HDNET |
||
272 | settings { |
||
273 | contentElement = ' . $config['model'] . ' |
||
274 | extensionKey = ' . $loader->getExtensionKey() . ' |
||
275 | vendorName = ' . $loader->getVendorName() . ' |
||
276 | } |
||
277 | } |
||
278 | } |
||
279 | config.tx_extbase.persistence.classes.' . $config['modelClass'] . '.mapping.tableName = tt_content |
||
280 | '; |
||
281 | } |
||
282 | |||
283 | if ($csc) { |
||
284 | ExtensionManagementUtility::addTypoScript($loader->getExtensionKey(), 'setup', $typoScript, 43); |
||
285 | } else { |
||
286 | ExtensionManagementUtility::addTypoScriptSetup($typoScript); |
||
287 | } |
||
288 | } |
||
289 | |||
290 | /** |
||
291 | * Check if the class is tagged with noHeader. |
||
292 | * |
||
293 | * @param $class |
||
294 | */ |
||
295 | protected function isTaggedWithNoHeader($class): bool |
||
296 | { |
||
297 | /** @var AnnotationReader $annotationReader */ |
||
298 | $annotationReader = GeneralUtility::makeInstance(AnnotationReader::class); |
||
299 | |||
300 | $classNameRef = new \ReflectionClass($class); |
||
301 | |||
302 | return null !== $annotationReader->getClassAnnotation($classNameRef, NoHeader::class); |
||
303 | } |
||
304 | |||
305 | /** |
||
306 | * Check if the templates are exist and create a dummy, if there |
||
307 | * is no valid template. |
||
308 | */ |
||
309 | protected function checkAndCreateDummyTemplates(array $loaderInformation, Loader $loader): void |
||
310 | { |
||
311 | if (empty($loaderInformation)) { |
||
312 | return; |
||
313 | } |
||
314 | |||
315 | $siteRelPathPrivate = 'EXT:' . $loader->getExtensionKey() . '/Resources/Private/'; |
||
316 | $frontendLayout = GeneralUtility::getFileAbsFileName($siteRelPathPrivate . 'Layouts/Content.html'); |
||
317 | if (!is_file($frontendLayout)) { |
||
318 | $this->writeContentTemplateToTarget('FrontendLayout', $frontendLayout); |
||
319 | } |
||
320 | $backendLayout = GeneralUtility::getFileAbsFileName($siteRelPathPrivate . 'Layouts/ContentBackend.html'); |
||
321 | if (!is_file($backendLayout)) { |
||
322 | $this->writeContentTemplateToTarget('BackendLayout', $backendLayout); |
||
323 | } |
||
324 | |||
325 | foreach ($loaderInformation as $configuration) { |
||
326 | $templatePath = $siteRelPathPrivate . 'Templates/Content/' . $configuration['model'] . '.html'; |
||
327 | $absoluteTemplatePath = GeneralUtility::getFileAbsFileName($templatePath); |
||
328 | if (!is_file($absoluteTemplatePath)) { |
||
329 | $beTemplatePath = $siteRelPathPrivate . 'Templates/Content/' . $configuration['model'] . 'Backend.html'; |
||
330 | $absoluteBeTemplatePath = GeneralUtility::getFileAbsFileName($beTemplatePath); |
||
331 | |||
332 | $this->writeContentTemplateToTarget('Frontend', $absoluteTemplatePath); |
||
333 | $this->writeContentTemplateToTarget('Backend', $absoluteBeTemplatePath); |
||
334 | } |
||
335 | } |
||
336 | } |
||
337 | |||
338 | /** |
||
339 | * Write the given content object template to the target path. |
||
340 | * |
||
341 | * @param string $name |
||
342 | * @param string $absoluteTargetPath |
||
343 | */ |
||
344 | protected function writeContentTemplateToTarget($name, $absoluteTargetPath): void |
||
345 | { |
||
346 | $template = GeneralUtility::getUrl(ExtensionManagementUtility::extPath( |
||
347 | 'autoloader', |
||
348 | 'Resources/Private/Templates/ContentObjects/' . $name . '.html' |
||
349 | )); |
||
350 | FileUtility::writeFileAndCreateFolder($absoluteTargetPath, $template); |
||
351 | } |
||
352 | |||
353 | /** |
||
354 | * Same as getClassProperties, but the fields are in LowerCaseUnderscored. |
||
355 | * |
||
356 | * @param $className |
||
357 | * |
||
358 | * @return array |
||
359 | */ |
||
360 | protected function getClassPropertiesInLowerCaseUnderscored($className) |
||
361 | { |
||
362 | $nameMapperService = GeneralUtility::makeInstance(NameMapperService::class); |
||
363 | $tableName = ModelUtility::getTableName($className); |
||
364 | |||
365 | return array_map(function ($value) use ($nameMapperService, $tableName) { |
||
366 | return $nameMapperService->getDatabaseFieldName($tableName, $value); |
||
367 | }, ReflectionUtility::getDeclaringProperties($className)); |
||
368 | } |
||
369 | |||
370 | /** |
||
371 | * Wrap the given field configuration in the CE default TCA fields. |
||
372 | * |
||
373 | * @param string $configuration |
||
374 | * @param bool $noHeader |
||
375 | * |
||
376 | * @return string |
||
377 | */ |
||
378 | protected function wrapDefaultTcaConfiguration($configuration, $noHeader = false) |
||
379 | { |
||
380 | $languagePrefix = 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf'; |
||
381 | $languagePrefixCore = 'LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf'; |
||
382 | $configuration = trim($configuration) ? trim($configuration) . ',' : ''; |
||
383 | |||
384 | return '--palette--;' . $languagePrefix . ':palette.general;general, |
||
385 | ' . ($noHeader ? '' : '--palette--;' . $languagePrefix . ':palette.header;header,') . ' |
||
386 | --div--;LLL:EXT:autoloader/Resources/Private/Language/locallang.xlf:contentData, |
||
387 | ' . $configuration . ' |
||
388 | --div--;' . $languagePrefix . ':tabs.appearance, |
||
389 | --palette--;;frames, |
||
390 | --palette--;;appearanceLinks, |
||
391 | --div--;' . $languagePrefixCore . ':language, |
||
392 | --palette--;;language, |
||
393 | --div--;' . $languagePrefixCore . ':access, |
||
394 | --palette--;;hidden, |
||
395 | --palette--;' . $languagePrefix . ':palette.access;access, |
||
396 | --div--;' . $languagePrefixCore . ':extended'; |
||
397 | } |
||
398 | |||
399 | /** |
||
400 | * Get the fields that are in the default configuration. |
||
401 | * |
||
402 | * @param bool $noHeader |
||
403 | * @param string|null $configuration |
||
404 | * |
||
405 | * @return array |
||
406 | */ |
||
407 | protected function getDefaultTcaFields($noHeader, $configuration = null) |
||
408 | { |
||
409 | if (null === $configuration) { |
||
410 | $configuration = $this->wrapDefaultTcaConfiguration('', $noHeader); |
||
411 | } |
||
412 | $defaultFields = []; |
||
413 | // Note: TCA could be missing in install tool checks, so cast the TCA to array |
||
414 | $existingFields = array_keys((array)$GLOBALS['TCA']['tt_content']['columns']); |
||
415 | $parts = GeneralUtility::trimExplode(',', $configuration, true); |
||
416 | foreach ($parts as $fieldConfiguration) { |
||
417 | $fieldConfiguration = GeneralUtility::trimExplode(';', $fieldConfiguration, true); |
||
418 | if (\in_array($fieldConfiguration[0], $existingFields, true)) { |
||
419 | $defaultFields[] = $fieldConfiguration[0]; |
||
420 | } elseif ('--palette--' === $fieldConfiguration[0]) { |
||
421 | $paletteConfiguration = $GLOBALS['TCA']['tt_content']['palettes'][$fieldConfiguration[2]]['showitem']; |
||
422 | if (\is_string($paletteConfiguration)) { |
||
423 | $defaultFields = array_merge( |
||
424 | $defaultFields, |
||
425 | $this->getDefaultTcaFields($noHeader, $paletteConfiguration) |
||
426 | ); |
||
427 | } |
||
428 | } |
||
429 | } |
||
430 | |||
431 | return $defaultFields; |
||
432 | } |
||
433 | } |
||
434 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.