‪TYPO3CMS  10.4
ContentObjectRenderer.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
18 use Doctrine\DBAL\DBALException;
19 use Doctrine\DBAL\Driver\Statement;
20 use Psr\Container\ContainerInterface;
21 use Psr\Log\LoggerAwareInterface;
22 use Psr\Log\LoggerAwareTrait;
23 use Symfony\Component\Mime\Address;
85 use TYPO3\HtmlSanitizer\Builder\BuilderInterface;
86 
96 class ‪ContentObjectRenderer implements LoggerAwareInterface
97 {
98  use LoggerAwareTrait;
99 
103  protected ‪$container;
104 
108  public ‪$align = [
109  'center',
110  'right',
111  'left'
112  ];
113 
120  public ‪$stdWrapOrder = [
121  'stdWrapPreProcess' => 'hook',
122  // this is a placeholder for the first Hook
123  'cacheRead' => 'hook',
124  // this is a placeholder for checking if the content is available in cache
125  'setContentToCurrent' => 'boolean',
126  'setContentToCurrent.' => 'array',
127  'addPageCacheTags' => 'string',
128  'addPageCacheTags.' => 'array',
129  'setCurrent' => 'string',
130  'setCurrent.' => 'array',
131  'lang.' => 'array',
132  'data' => 'getText',
133  'data.' => 'array',
134  'field' => 'fieldName',
135  'field.' => 'array',
136  'current' => 'boolean',
137  'current.' => 'array',
138  'cObject' => 'cObject',
139  'cObject.' => 'array',
140  'numRows.' => 'array',
141  'preUserFunc' => 'functionName',
142  'stdWrapOverride' => 'hook',
143  // this is a placeholder for the second Hook
144  'override' => 'string',
145  'override.' => 'array',
146  'preIfEmptyListNum' => 'listNum',
147  'preIfEmptyListNum.' => 'array',
148  'ifNull' => 'string',
149  'ifNull.' => 'array',
150  'ifEmpty' => 'string',
151  'ifEmpty.' => 'array',
152  'ifBlank' => 'string',
153  'ifBlank.' => 'array',
154  'listNum' => 'listNum',
155  'listNum.' => 'array',
156  'trim' => 'boolean',
157  'trim.' => 'array',
158  'strPad.' => 'array',
159  'stdWrap' => 'stdWrap',
160  'stdWrap.' => 'array',
161  'stdWrapProcess' => 'hook',
162  // this is a placeholder for the third Hook
163  'required' => 'boolean',
164  'required.' => 'array',
165  'if.' => 'array',
166  'fieldRequired' => 'fieldName',
167  'fieldRequired.' => 'array',
168  'csConv' => 'string',
169  'csConv.' => 'array',
170  'parseFunc' => 'objectpath',
171  'parseFunc.' => 'array',
172  'HTMLparser' => 'boolean',
173  'HTMLparser.' => 'array',
174  'split.' => 'array',
175  'replacement.' => 'array',
176  'prioriCalc' => 'boolean',
177  'prioriCalc.' => 'array',
178  'char' => 'integer',
179  'char.' => 'array',
180  'intval' => 'boolean',
181  'intval.' => 'array',
182  'hash' => 'string',
183  'hash.' => 'array',
184  'round' => 'boolean',
185  'round.' => 'array',
186  'numberFormat.' => 'array',
187  'expandList' => 'boolean',
188  'expandList.' => 'array',
189  'date' => 'dateconf',
190  'date.' => 'array',
191  'strtotime' => 'strtotimeconf',
192  'strtotime.' => 'array',
193  'strftime' => 'strftimeconf',
194  'strftime.' => 'array',
195  'age' => 'boolean',
196  'age.' => 'array',
197  'case' => 'case',
198  'case.' => 'array',
199  'bytes' => 'boolean',
200  'bytes.' => 'array',
201  'substring' => 'parameters',
202  'substring.' => 'array',
203  'cropHTML' => 'crop',
204  'cropHTML.' => 'array',
205  'stripHtml' => 'boolean',
206  'stripHtml.' => 'array',
207  'crop' => 'crop',
208  'crop.' => 'array',
209  'rawUrlEncode' => 'boolean',
210  'rawUrlEncode.' => 'array',
211  'htmlSpecialChars' => 'boolean',
212  'htmlSpecialChars.' => 'array',
213  'encodeForJavaScriptValue' => 'boolean',
214  'encodeForJavaScriptValue.' => 'array',
215  'doubleBrTag' => 'string',
216  'doubleBrTag.' => 'array',
217  'br' => 'boolean',
218  'br.' => 'array',
219  'brTag' => 'string',
220  'brTag.' => 'array',
221  'encapsLines.' => 'array',
222  'keywords' => 'boolean',
223  'keywords.' => 'array',
224  'innerWrap' => 'wrap',
225  'innerWrap.' => 'array',
226  'innerWrap2' => 'wrap',
227  'innerWrap2.' => 'array',
228  'preCObject' => 'cObject',
229  'preCObject.' => 'array',
230  'postCObject' => 'cObject',
231  'postCObject.' => 'array',
232  'wrapAlign' => 'align',
233  'wrapAlign.' => 'array',
234  'typolink.' => 'array',
235  'wrap' => 'wrap',
236  'wrap.' => 'array',
237  'noTrimWrap' => 'wrap',
238  'noTrimWrap.' => 'array',
239  'wrap2' => 'wrap',
240  'wrap2.' => 'array',
241  'dataWrap' => 'dataWrap',
242  'dataWrap.' => 'array',
243  'prepend' => 'cObject',
244  'prepend.' => 'array',
245  'append' => 'cObject',
246  'append.' => 'array',
247  'wrap3' => 'wrap',
248  'wrap3.' => 'array',
249  'orderedStdWrap' => 'stdWrap',
250  'orderedStdWrap.' => 'array',
251  'outerWrap' => 'wrap',
252  'outerWrap.' => 'array',
253  'insertData' => 'boolean',
254  'insertData.' => 'array',
255  'postUserFunc' => 'functionName',
256  'postUserFuncInt' => 'functionName',
257  'prefixComment' => 'string',
258  'prefixComment.' => 'array',
259  'editIcons' => 'string',
260  'editIcons.' => 'array',
261  'editPanel' => 'boolean',
262  'editPanel.' => 'array',
263  'htmlSanitize' => 'boolean',
264  'htmlSanitize.' => 'array',
265  'cacheStore' => 'hook',
266  // this is a placeholder for storing the content in cache
267  'stdWrapPostProcess' => 'hook',
268  // this is a placeholder for the last Hook
269  'debug' => 'boolean',
270  'debug.' => 'array',
271  'debugFunc' => 'boolean',
272  'debugFunc.' => 'array',
273  'debugData' => 'boolean',
274  'debugData.' => 'array'
275  ];
276 
282  protected ‪$contentObjectClassMap = [];
283 
293  public ‪$data = [];
294 
298  protected ‪$table = '';
299 
305  public ‪$oldData = [];
306 
312  public ‪$alternativeData = '';
313 
319  public ‪$parameters = [];
320 
324  public ‪$currentValKey = 'currentValue_kidjls9dksoje';
325 
332  public ‪$currentRecord = '';
333 
340 
346  public ‪$currentRecordNumber = 0;
347 
353  public ‪$parentRecordNumber = 0;
354 
360  public ‪$parentRecord = [];
361 
366 
372  public ‪$lastTypoLinkUrl = '';
373 
379  public ‪$lastTypoLinkTarget = '';
380 
384  public ‪$lastTypoLinkLD = [];
385 
391  public ‪$recordRegister = [];
392 
400 
405  public ‪$cObjHookObjectsArr = [];
406 
412  protected ‪$stdWrapHookObjects = [];
413 
420 
424  protected ‪$currentFile;
425 
431 
438  protected ‪$userObjectType = false;
439 
443  protected ‪$stopRendering = [];
444 
448  protected ‪$stdWrapRecursionLevel = 0;
449 
454 
460  const ‪OBJECTTYPE_USER_INT = 1;
466  const ‪OBJECTTYPE_USER = 2;
467 
472  public function ‪__construct(‪TypoScriptFrontendController ‪$typoScriptFrontendController = null, ContainerInterface ‪$container = null)
473  {
474  $this->typoScriptFrontendController = ‪$typoScriptFrontendController;
475  $this->contentObjectClassMap = ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['ContentObjects'];
476  $this->container = ‪$container;
477  }
478 
486  public function ‪__sleep()
487  {
488  $vars = get_object_vars($this);
489  unset($vars['typoScriptFrontendController'], $vars['logger'], $vars['container']);
490  if ($this->currentFile instanceof ‪FileReference) {
491  $this->currentFile = 'FileReference:' . $this->currentFile->getUid();
492  } elseif ($this->currentFile instanceof File) {
493  $this->currentFile = 'File:' . $this->currentFile->getIdentifier();
494  } else {
495  unset($vars['currentFile']);
496  }
497  return array_keys($vars);
498  }
499 
505  public function ‪__wakeup()
506  {
507  if (isset(‪$GLOBALS['TSFE'])) {
508  $this->typoScriptFrontendController = ‪$GLOBALS['TSFE'];
509  }
510  if ($this->currentFile !== null && is_string($this->currentFile)) {
511  [$objectType, $identifier] = explode(':', $this->currentFile, 2);
512  try {
513  if ($objectType === 'File') {
514  $this->currentFile = GeneralUtility::makeInstance(ResourceFactory::class)->retrieveFileOrFolderObject($identifier);
515  } elseif ($objectType === 'FileReference') {
516  $this->currentFile = GeneralUtility::makeInstance(ResourceFactory::class)->getFileReferenceObject($identifier);
517  }
518  } catch (‪ResourceDoesNotExistException $e) {
519  $this->currentFile = null;
520  }
521  }
522  $this->logger = GeneralUtility::makeInstance(LogManager::class)->getLogger(__CLASS__);
523  $this->container = GeneralUtility::getContainer();
524  }
525 
536  {
537  $this->contentObjectClassMap = ‪$contentObjectClassMap;
538  }
539 
550  public function ‪registerContentObjectClass($className, $contentObjectName)
551  {
552  $this->contentObjectClassMap[$contentObjectName] = $className;
553  }
554 
563  public function ‪start(‪$data, ‪$table = '')
564  {
565  $this->data = ‪$data;
566  $this->table = ‪$table;
567  $this->currentRecord = ‪$table !== ''
568  ? ‪$table . ':' . ($this->data['uid'] ?? '')
569  : '';
570  $this->parameters = [];
571  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['cObjTypeAndClass'] ?? [] as $classArr) {
572  trigger_error('The hook $TYPO3_CONF_VARS[SC_OPTIONS][tslib/class.tslib_content.php][cObjTypeAndClass] for adding custom cObjects will be removed in TYPO3 v11.0. Use a custom cObject which you can register directly instead.', E_USER_DEPRECATED);
573  $this->cObjHookObjectsRegistry[$classArr[0]] = $classArr[1];
574  }
575  $this->stdWrapHookObjects = [];
576  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['stdWrap'] ?? [] as $className) {
577  $hookObject = GeneralUtility::makeInstance($className);
578  if (!$hookObject instanceof ‪ContentObjectStdWrapHookInterface) {
579  throw new \UnexpectedValueException($className . ' must implement interface ' . ContentObjectStdWrapHookInterface::class, 1195043965);
580  }
581  $this->stdWrapHookObjects[] = $hookObject;
582  }
583  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['postInit'] ?? [] as $className) {
584  $postInitializationProcessor = GeneralUtility::makeInstance($className);
585  if (!$postInitializationProcessor instanceof ContentObjectPostInitHookInterface) {
586  throw new \UnexpectedValueException($className . ' must implement interface ' . ContentObjectPostInitHookInterface::class, 1274563549);
587  }
588  $postInitializationProcessor->postProcessContentObjectInitialization($this);
589  }
590  }
591 
597  public function ‪getCurrentTable()
598  {
599  return ‪$this->table;
600  }
601 
608  protected function ‪getGetImgResourceHookObjects()
609  {
610  if (!isset($this->getImgResourceHookObjects)) {
611  $this->getImgResourceHookObjects = [];
612  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImgResource'] ?? [] as $className) {
613  $hookObject = GeneralUtility::makeInstance($className);
614  if (!$hookObject instanceof ‪ContentObjectGetImageResourceHookInterface) {
615  throw new \UnexpectedValueException('$hookObject must implement interface ' . ContentObjectGetImageResourceHookInterface::class, 1218636383);
616  }
617  $this->getImgResourceHookObjects[] = $hookObject;
618  }
619  }
621  }
622 
631  public function ‪setParent(‪$data, ‪$currentRecord)
632  {
633  $this->parentRecord = [
634  'data' => ‪$data,
635  'currentRecord' => ‪$currentRecord
636  ];
637  }
638 
639  /***********************************************
640  *
641  * CONTENT_OBJ:
642  *
643  ***********************************************/
652  public function ‪getCurrentVal()
653  {
654  return $this->data[‪$this->currentValKey];
655  }
656 
663  public function ‪setCurrentVal($value)
664  {
665  $this->data[‪$this->currentValKey] = $value;
666  }
667 
677  public function ‪cObjGet($setup, $addKey = '')
678  {
679  if (!is_array($setup)) {
680  return '';
681  }
682  $sKeyArray = ‪ArrayUtility::filterAndSortByNumericKeys($setup);
683  $content = '';
684  foreach ($sKeyArray as $theKey) {
685  $theValue = $setup[$theKey];
686  if ((int)$theKey && strpos($theKey, '.') === false) {
687  $conf = $setup[$theKey . '.'] ?? [];
688  $content .= $this->‪cObjGetSingle($theValue, $conf, $addKey . $theKey);
689  }
690  }
691  return $content;
692  }
693 
703  public function ‪cObjGetSingle($name, $conf, $TSkey = '__')
704  {
705  $content = '';
706  // Checking that the function is not called eternally. This is done by interrupting at a depth of 100
707  $this->‪getTypoScriptFrontendController()->cObjectDepthCounter--;
708  if ($this->‪getTypoScriptFrontendController()->cObjectDepthCounter > 0) {
709  $timeTracker = $this->‪getTimeTracker();
710  $name = trim($name);
711  if ($timeTracker->LR) {
712  $timeTracker->push($TSkey, $name);
713  }
714  // Checking if the COBJ is a reference to another object. (eg. name of 'some.object =< styles.something')
715  if (isset($name[0]) && $name[0] === '<') {
716  $key = trim(substr($name, 1));
717  $cF = GeneralUtility::makeInstance(TypoScriptParser::class);
718  // $name and $conf is loaded with the referenced values.
719  $confOverride = is_array($conf) ? $conf : [];
720  [$name, $conf] = $cF->getVal($key, $this->‪getTypoScriptFrontendController()->tmpl->setup);
721  $conf = array_replace_recursive(is_array($conf) ? $conf : [], $confOverride);
722  // Getting the cObject
723  $timeTracker->incStackPointer();
724  $content .= $this->‪cObjGetSingle($name, $conf, $key);
725  $timeTracker->decStackPointer();
726  } else {
727  $hooked = false;
728  // Application defined cObjects
729  // @deprecated since TYPO3 v10.4 - will be removed in TYPO3 v11.0
730  if (!empty($this->cObjHookObjectsRegistry[$name])) {
731  if (empty($this->cObjHookObjectsArr[$name])) {
732  $this->cObjHookObjectsArr[$name] = GeneralUtility::makeInstance($this->cObjHookObjectsRegistry[$name]);
733  }
734  $hookObj = $this->cObjHookObjectsArr[$name];
735  if (method_exists($hookObj, 'cObjGetSingleExt')) {
736  $content .= $hookObj->cObjGetSingleExt($name, $conf, $TSkey, $this);
737  $hooked = true;
738  }
739  }
740  if (!$hooked) {
741  $contentObject = $this->‪getContentObject($name);
742  if ($contentObject) {
743  $content .= $this->‪render($contentObject, $conf);
744  } else {
745  // Call hook functions for extra processing
746  if ($name) {
747  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['cObjTypeAndClassDefault'])) {
748  trigger_error('The hook $TYPO3_CONF_VARS[SC_OPTIONS][tslib/class.tslib_content.php][cObjTypeAndClassDefault] for adding custom processing will be removed. Use a custom cObject which you can register directly instead.', E_USER_DEPRECATED);
749  }
750  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['cObjTypeAndClassDefault'] ?? [] as $className) {
751  $hookObject = GeneralUtility::makeInstance($className);
752  if (!$hookObject instanceof ContentObjectGetSingleHookInterface) {
753  throw new \UnexpectedValueException('$hookObject must implement interface ' . ContentObjectGetSingleHookInterface::class, 1195043731);
754  }
756  $content .= $hookObject->getSingleContentObject($name, (array)$conf, $TSkey, $this);
757  }
758  } else {
759  // Log error in AdminPanel
760  $warning = sprintf('Content Object "%s" does not exist', $name);
761  $timeTracker->setTSlogMessage($warning, 2);
762  }
763  }
764  }
765  }
766  if ($timeTracker->LR) {
767  $timeTracker->pull($content);
768  }
769  }
770  // Increasing on exit...
771  $this->‪getTypoScriptFrontendController()->cObjectDepthCounter++;
772  return $content;
773  }
774 
784  public function ‪getContentObject($name)
785  {
786  if (!isset($this->contentObjectClassMap[$name])) {
787  return null;
788  }
789  $fullyQualifiedClassName = $this->contentObjectClassMap[$name];
790  $contentObject = GeneralUtility::makeInstance($fullyQualifiedClassName, $this);
791  if (!($contentObject instanceof AbstractContentObject)) {
792  throw new ContentRenderingException(sprintf('Registered content object class name "%s" must be an instance of AbstractContentObject, but is not!', $fullyQualifiedClassName), 1422564295);
793  }
794  return $contentObject;
795  }
796 
797  /********************************************
798  *
799  * Functions rendering content objects (cObjects)
800  *
801  ********************************************/
813  public function ‪render(AbstractContentObject $contentObject, $configuration = [])
814  {
815  $content = '';
816 
817  // Evaluate possible cache and return
818  $cacheConfiguration = $configuration['cache.'] ?? null;
819  if ($cacheConfiguration !== null) {
820  unset($configuration['cache.']);
821  $cache = $this->‪getFromCache($cacheConfiguration);
822  if ($cache !== false) {
823  return $cache;
824  }
825  }
826 
827  // Render content
828  try {
829  $content .= $contentObject->render($configuration);
830  } catch (ContentRenderingException $exception) {
831  // Content rendering Exceptions indicate a critical problem which should not be
832  // caught e.g. when something went wrong with Exception handling itself
833  throw $exception;
834  } catch (\Exception $exception) {
835  $exceptionHandler = $this->‪createExceptionHandler($configuration);
836  if ($exceptionHandler === null) {
837  throw $exception;
838  }
839  $content = $exceptionHandler->handle($exception, $contentObject, $configuration);
840  }
841 
842  // Store cache
843  if ($cacheConfiguration !== null && !$this->‪getTypoScriptFrontendController()->no_cache) {
844  $key = $this->‪calculateCacheKey($cacheConfiguration);
845  if (!empty($key)) {
847  $cacheFrontend = GeneralUtility::makeInstance(CacheManager::class)->getCache('hash');
848  $tags = $this->‪calculateCacheTags($cacheConfiguration);
849  $lifetime = $this->‪calculateCacheLifetime($cacheConfiguration);
850  $cacheFrontend->set($key, $content, $tags, $lifetime);
851  }
852  }
853 
854  return $content;
855  }
856 
865  protected function ‪createExceptionHandler($configuration = [])
866  {
867  $exceptionHandler = null;
868  $exceptionHandlerClassName = $this->‪determineExceptionHandlerClassName($configuration);
869  if (!empty($exceptionHandlerClassName)) {
870  $exceptionHandler = GeneralUtility::makeInstance($exceptionHandlerClassName, $this->‪mergeExceptionHandlerConfiguration($configuration));
871  if (!$exceptionHandler instanceof ‪ExceptionHandlerInterface) {
872  throw new ‪ContentRenderingException('An exception handler was configured but the class does not exist or does not implement the ExceptionHandlerInterface', 1403653369);
873  }
874  }
875 
876  return $exceptionHandler;
877  }
878 
885  protected function ‪determineExceptionHandlerClassName($configuration)
886  {
887  $exceptionHandlerClassName = null;
888  $tsfe = $this->‪getTypoScriptFrontendController();
889  if (!isset($tsfe->config['config']['contentObjectExceptionHandler'])) {
890  if (‪Environment::getContext()->isProduction()) {
891  $exceptionHandlerClassName = '1';
892  }
893  } else {
894  $exceptionHandlerClassName = $tsfe->config['config']['contentObjectExceptionHandler'];
895  }
896 
897  if (isset($configuration['exceptionHandler'])) {
898  $exceptionHandlerClassName = $configuration['exceptionHandler'];
899  }
900 
901  if ($exceptionHandlerClassName === '1') {
902  $exceptionHandlerClassName = ProductionExceptionHandler::class;
903  }
904 
905  return $exceptionHandlerClassName;
906  }
907 
915  protected function ‪mergeExceptionHandlerConfiguration($configuration)
916  {
917  $exceptionHandlerConfiguration = [];
918  $tsfe = $this->‪getTypoScriptFrontendController();
919  if (!empty($tsfe->config['config']['contentObjectExceptionHandler.'])) {
920  $exceptionHandlerConfiguration = $tsfe->config['config']['contentObjectExceptionHandler.'];
921  }
922  if (!empty($configuration['exceptionHandler.'])) {
923  $exceptionHandlerConfiguration = array_replace_recursive($exceptionHandlerConfiguration, $configuration['exceptionHandler.']);
924  }
925 
926  return $exceptionHandlerConfiguration;
927  }
928 
937  public function ‪getUserObjectType()
938  {
940  }
941 
948  {
949  $this->userObjectType = ‪$userObjectType;
950  }
951 
955  public function ‪convertToUserIntObject()
956  {
957  if ($this->userObjectType !== self::OBJECTTYPE_USER) {
958  $this->‪getTimeTracker()->‪setTSlogMessage(self::class . '::convertToUserIntObject() is called in the wrong context or for the wrong object type', 2);
959  } else {
960  $this->doConvertToUserIntObject = true;
961  }
962  }
963 
964  /************************************
965  *
966  * Various helper functions for content objects:
967  *
968  ************************************/
976  public function ‪readFlexformIntoConf($flexData, &$conf, $recursive = false)
977  {
978  if ($recursive === false && is_string($flexData)) {
979  $flexData = ‪GeneralUtility::xml2array($flexData, 'T3');
980  }
981  if (is_array($flexData) && isset($flexData['data']['sDEF']['lDEF'])) {
982  $flexData = $flexData['data']['sDEF']['lDEF'];
983  }
984  if (!is_array($flexData)) {
985  return;
986  }
987  foreach ($flexData as $key => $value) {
988  if (!is_array($value)) {
989  continue;
990  }
991  if (isset($value['el'])) {
992  if (is_array($value['el']) && !empty($value['el'])) {
993  foreach ($value['el'] as $ekey => $element) {
994  if (isset($element['vDEF'])) {
995  $conf[$ekey] = $element['vDEF'];
996  } else {
997  if (is_array($element)) {
998  $this->‪readFlexformIntoConf($element, $conf[$key][key($element)][$ekey], true);
999  } else {
1000  $this->‪readFlexformIntoConf($element, $conf[$key][$ekey], true);
1001  }
1002  }
1003  }
1004  } else {
1005  $this->‪readFlexformIntoConf($value['el'], $conf[$key], true);
1006  }
1007  }
1008  if (isset($value['vDEF'])) {
1009  $conf[$key] = $value['vDEF'];
1010  }
1011  }
1012  }
1013 
1022  public function ‪getSlidePids($pidList, $pidConf)
1023  {
1024  // todo: phpstan states that $pidConf always exists and is not nullable. At the moment, this is a false positive
1025  // as null can be passed into this method via $pidConf. As soon as more strict types are used, this isset
1026  // check must be replaced with a more appropriate check like empty or count.
1027  $pidList = isset($pidConf) ? trim($this->‪stdWrap($pidList, $pidConf)) : trim($pidList);
1028  if ($pidList === '') {
1029  $pidList = 'this';
1030  }
1031  $tsfe = $this->‪getTypoScriptFrontendController();
1032  $listArr = null;
1033  if (trim($pidList)) {
1034  $listArr = ‪GeneralUtility::intExplode(',', str_replace('this', (string)$tsfe->contentPid, $pidList));
1035  $listArr = $this->‪checkPidArray($listArr);
1036  }
1037  $pidList = [];
1038  if (is_array($listArr) && !empty($listArr)) {
1039  foreach ($listArr as $uid) {
1040  $page = $tsfe->sys_page->getPage($uid);
1041  if (!$page['is_siteroot']) {
1042  $pidList[] = $page['pid'];
1043  }
1044  }
1045  }
1046  return implode(',', $pidList);
1047  }
1048 
1060  public function ‪cImage($file, $conf)
1061  {
1062  trigger_error('cObj->cImage() will be removed in TYPO3 v11.0. This functionality is integrated into ImageContentObject now.', E_USER_DEPRECATED);
1063  $tsfe = $this->‪getTypoScriptFrontendController();
1064  $info = $this->‪getImgResource($file, $conf['file.']);
1065  $tsfe->lastImageInfo = $info;
1066  if (!is_array($info)) {
1067  return '';
1068  }
1069  if (is_file(‪Environment::getPublicPath() . '/' . $info['3'])) {
1070  $source = $tsfe->absRefPrefix . str_replace('%2F', '/', rawurlencode($info['3']));
1071  } else {
1072  $source = $info[3];
1073  }
1074  // Remove file objects for AssetCollector, as it only allows to store scalar values
1075  unset($info['originalFile'], $info['processedFile']);
1076  GeneralUtility::makeInstance(AssetCollector::class)->addMedia(
1077  $source,
1078  $info
1079  );
1080 
1081  $layoutKey = $this->‪stdWrap($conf['layoutKey'], $conf['layoutKey.']);
1082  $imageTagTemplate = $this->‪getImageTagTemplate($layoutKey, $conf);
1083  $sourceCollection = $this->‪getImageSourceCollection($layoutKey, $conf, $file);
1084 
1085  // This array is used to collect the image-refs on the page...
1086  $tsfe->imagesOnPage[] = $source;
1087  $altParam = $this->‪getAltParam($conf);
1088  $params = $this->‪stdWrapValue('params', $conf);
1089  if ($params !== '' && $params[0] !== ' ') {
1090  $params = ' ' . $params;
1091  }
1092 
1093  $imageTagValues = [
1094  'width' => (int)$info[0],
1095  'height' => (int)$info[1],
1096  'src' => htmlspecialchars($source),
1097  'params' => $params,
1098  'altParams' => $altParam,
1099  'border' => $this->‪getBorderAttr(' border="' . (int)$conf['border'] . '"'),
1100  'sourceCollection' => $sourceCollection,
1101  'selfClosingTagSlash' => !empty($tsfe->xhtmlDoctype) ? ' /' : '',
1102  ];
1103 
1104  $markerTemplateEngine = GeneralUtility::makeInstance(MarkerBasedTemplateService::class);
1105  $theValue = $markerTemplateEngine->substituteMarkerArray($imageTagTemplate, $imageTagValues, '###|###', true, true);
1106 
1107  $linkWrap = isset($conf['linkWrap.']) ? $this->‪stdWrap($conf['linkWrap'], $conf['linkWrap.']) : $conf['linkWrap'];
1108  if ($linkWrap) {
1109  $theValue = $this->‪linkWrap($theValue, $linkWrap);
1110  } elseif ($conf['imageLinkWrap']) {
1111  $originalFile = !empty($info['originalFile']) ? $info['originalFile'] : $info['origFile'];
1112  $theValue = $this->‪imageLinkWrap($theValue, $originalFile, $conf['imageLinkWrap.']);
1113  }
1114  $wrap = isset($conf['wrap.']) ? $this->‪stdWrap($conf['wrap'], $conf['wrap.']) : $conf['wrap'];
1115  if ((string)$wrap !== '') {
1116  $theValue = $this->‪wrap($theValue, $conf['wrap']);
1117  }
1118  return $theValue;
1119  }
1120 
1129  public function ‪getBorderAttr($borderAttr)
1130  {
1131  trigger_error('cObj->getBorderAttr() will be removed in TYPO3 v11.0. This functionality is integrated into ImageContentObject.', E_USER_DEPRECATED);
1132  $tsfe = $this->‪getTypoScriptFrontendController();
1133  $docType = $tsfe->xhtmlDoctype;
1134  if (
1135  $docType !== 'xhtml_strict' && $docType !== 'xhtml_11'
1136  && $tsfe->config['config']['doctype'] !== 'html5'
1137  && !$tsfe->config['config']['disableImgBorderAttr']
1138  ) {
1139  return $borderAttr;
1140  }
1141  return '';
1142  }
1143 
1153  public function ‪getImageTagTemplate($layoutKey, $conf)
1154  {
1155  trigger_error('cObj->getImageTagTemplate() will be removed in TYPO3 v11.0. This functionality is integrated into ImageContentObject.', E_USER_DEPRECATED);
1156  if ($layoutKey && isset($conf['layout.']) && isset($conf['layout.'][$layoutKey . '.'])) {
1157  $imageTagLayout = $this->‪stdWrap(
1158  $conf['layout.'][$layoutKey . '.']['element'] ?? '',
1159  $conf['layout.'][$layoutKey . '.']['element.'] ?? []
1160  );
1161  } else {
1162  $imageTagLayout = '<img src="###SRC###" width="###WIDTH###" height="###HEIGHT###" ###PARAMS### ###ALTPARAMS### ###BORDER######SELFCLOSINGTAGSLASH###>';
1163  }
1164  return $imageTagLayout;
1165  }
1166 
1177  public function ‪getImageSourceCollection($layoutKey, $conf, $file)
1178  {
1179  trigger_error('cObj->getImageSourceCollection() will be removed in TYPO3 v11.0. This functionality is integrated into ImageContentObject.', E_USER_DEPRECATED);
1180  $sourceCollection = '';
1181  if ($layoutKey
1182  && isset($conf['sourceCollection.']) && $conf['sourceCollection.']
1183  && (
1184  isset($conf['layout.'][$layoutKey . '.']['source']) && $conf['layout.'][$layoutKey . '.']['source']
1185  || isset($conf['layout.'][$layoutKey . '.']['source.']) && $conf['layout.'][$layoutKey . '.']['source.']
1186  )
1187  ) {
1188 
1189  // find active sourceCollection
1190  $activeSourceCollections = [];
1191  foreach ($conf['sourceCollection.'] as $sourceCollectionKey => $sourceCollectionConfiguration) {
1192  if (substr($sourceCollectionKey, -1) === '.') {
1193  if (empty($sourceCollectionConfiguration['if.']) || $this->‪checkIf($sourceCollectionConfiguration['if.'])) {
1194  $activeSourceCollections[] = $sourceCollectionConfiguration;
1195  }
1196  }
1197  }
1198 
1199  // apply option split to configurations
1200  $tsfe = $this->‪getTypoScriptFrontendController();
1201  $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
1202  $srcLayoutOptionSplitted = $typoScriptService->explodeConfigurationForOptionSplit((array)$conf['layout.'][$layoutKey . '.'], count($activeSourceCollections));
1203 
1204  // render sources
1205  foreach ($activeSourceCollections as $key => $sourceConfiguration) {
1206  $sourceLayout = $this->‪stdWrap(
1207  $srcLayoutOptionSplitted[$key]['source'] ?? '',
1208  $srcLayoutOptionSplitted[$key]['source.'] ?? []
1209  );
1210 
1211  $sourceRenderConfiguration = [
1212  'file' => $file,
1213  'file.' => $conf['file.'] ?? null
1214  ];
1215 
1216  if (isset($sourceConfiguration['quality']) || isset($sourceConfiguration['quality.'])) {
1217  $imageQuality = $sourceConfiguration['quality'] ?? '';
1218  if (isset($sourceConfiguration['quality.'])) {
1219  $imageQuality = $this->‪stdWrap($sourceConfiguration['quality'], $sourceConfiguration['quality.']);
1220  }
1221  if ($imageQuality) {
1222  $sourceRenderConfiguration['file.']['params'] = '-quality ' . (int)$imageQuality;
1223  }
1224  }
1225 
1226  if (isset($sourceConfiguration['pixelDensity'])) {
1227  $pixelDensity = (int)$this->‪stdWrap(
1228  $sourceConfiguration['pixelDensity'] ?? '',
1229  $sourceConfiguration['pixelDensity.'] ?? []
1230  );
1231  } else {
1232  $pixelDensity = 1;
1233  }
1234  $dimensionKeys = ['width', 'height', 'maxW', 'minW', 'maxH', 'minH', 'maxWidth', 'maxHeight', 'XY'];
1235  foreach ($dimensionKeys as $dimensionKey) {
1236  $dimension = $this->‪stdWrap(
1237  $sourceConfiguration[$dimensionKey] ?? '',
1238  $sourceConfiguration[$dimensionKey . '.'] ?? []
1239  );
1240  if (!$dimension) {
1241  $dimension = $this->‪stdWrap(
1242  $conf['file.'][$dimensionKey] ?? '',
1243  $conf['file.'][$dimensionKey . '.'] ?? []
1244  );
1245  }
1246  if ($dimension) {
1247  if (strpos($dimension, 'c') !== false && ($dimensionKey === 'width' || $dimensionKey === 'height')) {
1248  $dimensionParts = explode('c', $dimension, 2);
1249  $dimension = ((int)$dimensionParts[0] * $pixelDensity) . 'c';
1250  if ($dimensionParts[1]) {
1251  $dimension .= $dimensionParts[1];
1252  }
1253  } elseif ($dimensionKey === 'XY') {
1254  $dimensionParts = ‪GeneralUtility::intExplode(',', $dimension, false, 2);
1255  $dimension = $dimensionParts[0] * $pixelDensity;
1256  if ($dimensionParts[1]) {
1257  $dimension .= ',' . $dimensionParts[1] * $pixelDensity;
1258  }
1259  } else {
1260  $dimension = (int)$dimension * $pixelDensity;
1261  }
1262  $sourceRenderConfiguration['file.'][$dimensionKey] = $dimension;
1263  // Remove the stdWrap properties for dimension as they have been processed already above.
1264  unset($sourceRenderConfiguration['file.'][$dimensionKey . '.']);
1265  }
1266  }
1267  $sourceInfo = $this->‪getImgResource($sourceRenderConfiguration['file'], $sourceRenderConfiguration['file.']);
1268  if ($sourceInfo) {
1269  $sourceConfiguration['width'] = $sourceInfo[0];
1270  $sourceConfiguration['height'] = $sourceInfo[1];
1271  $urlPrefix = '';
1272  if (parse_url($sourceInfo[3], PHP_URL_HOST) === null) {
1273  $urlPrefix = $tsfe->absRefPrefix;
1274  }
1275  $sourceConfiguration['src'] = htmlspecialchars($urlPrefix . $sourceInfo[3]);
1276  $sourceConfiguration['selfClosingTagSlash'] = !empty($tsfe->xhtmlDoctype) ? ' /' : '';
1277 
1278  $markerTemplateEngine = GeneralUtility::makeInstance(MarkerBasedTemplateService::class);
1279  $oneSourceCollection = $markerTemplateEngine->substituteMarkerArray($sourceLayout, $sourceConfiguration, '###|###', true, true);
1280 
1281  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImageSourceCollection'] ?? [] as $className) {
1282  $hookObject = GeneralUtility::makeInstance($className);
1283  if (!$hookObject instanceof ‪ContentObjectOneSourceCollectionHookInterface) {
1284  throw new \UnexpectedValueException(
1285  '$hookObject must implement interface ' . ContentObjectOneSourceCollectionHookInterface::class,
1286  1380007853
1287  );
1288  }
1289  $oneSourceCollection = $hookObject->getOneSourceCollection((array)$sourceRenderConfiguration, (array)$sourceConfiguration, $oneSourceCollection, $this);
1290  }
1291 
1292  $sourceCollection .= $oneSourceCollection;
1293  }
1294  }
1295  }
1296  return $sourceCollection;
1297  }
1298 
1309  public function ‪imageLinkWrap($string, $imageFile, $conf)
1310  {
1311  $string = (string)$string;
1312  $enable = isset($conf['enable.']) ? $this->‪stdWrap($conf['enable'], $conf['enable.']) : $conf['enable'];
1313  if (!$enable) {
1314  return $string;
1315  }
1316  $content = (string)$this->‪typoLink($string, $conf['typolink.']);
1317  if (isset($conf['file.']) && is_scalar($imageFile)) {
1318  $imageFile = $this->‪stdWrap((string)$imageFile, $conf['file.']);
1319  }
1320 
1321  if ($imageFile instanceof File) {
1322  $file = $imageFile;
1323  } elseif ($imageFile instanceof FileReference) {
1324  $file = $imageFile->getOriginalFile();
1325  } else {
1327  $file = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObject((int)$imageFile);
1328  } else {
1329  $file = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObjectFromCombinedIdentifier($imageFile);
1330  }
1331  }
1332 
1333  // Create imageFileLink if not created with typolink
1334  if ($content === $string && $file !== null) {
1335  $parameterNames = ['width', 'height', 'effects', 'bodyTag', 'title', 'wrap', 'crop'];
1336  ‪$parameters = [];
1337  $sample = isset($conf['sample.']) ? $this->‪stdWrap($conf['sample'], $conf['sample.']) : $conf['sample'];
1338  if ($sample) {
1339  ‪$parameters['sample'] = 1;
1340  }
1341  foreach ($parameterNames as $parameterName) {
1342  if (isset($conf[$parameterName . '.'])) {
1343  $conf[$parameterName] = $this->‪stdWrap($conf[$parameterName], $conf[$parameterName . '.']);
1344  }
1345  if (isset($conf[$parameterName]) && $conf[$parameterName]) {
1346  ‪$parameters[$parameterName] = $conf[$parameterName];
1347  }
1348  }
1349  $parametersEncoded = base64_encode((string)json_encode(‪$parameters));
1350  $hmac = GeneralUtility::hmac(implode('|', [$file->getUid(), $parametersEncoded]));
1351  $params = '&md5=' . $hmac;
1352  foreach (str_split($parametersEncoded, 64) as $index => $chunk) {
1353  $params .= '&parameters' . rawurlencode('[') . $index . rawurlencode(']') . '=' . rawurlencode($chunk);
1354  }
1355  $url = $this->‪getTypoScriptFrontendController()->absRefPrefix . 'index.php?eID=tx_cms_showpic&file=' . $file->getUid() . $params;
1356  $directImageLink = isset($conf['directImageLink.']) ? $this->‪stdWrap($conf['directImageLink'], $conf['directImageLink.']) : $conf['directImageLink'];
1357  if ($directImageLink) {
1358  $imgResourceConf = [
1359  'file' => $imageFile,
1360  'file.' => $conf
1361  ];
1362  $url = $this->‪cObjGetSingle('IMG_RESOURCE', $imgResourceConf);
1363  if (!$url) {
1364  // If no imagemagick / gm is available
1365  $url = $imageFile;
1366  }
1367  }
1368  // Create TARGET-attribute only if the right doctype is used
1369  $target = '';
1370  $xhtmlDocType = $this->‪getTypoScriptFrontendController()->xhtmlDoctype;
1371  if ($xhtmlDocType !== 'xhtml_strict' && $xhtmlDocType !== 'xhtml_11') {
1372  $target = isset($conf['target.'])
1373  ? (string)$this->‪stdWrap($conf['target'], $conf['target.'])
1374  : (string)$conf['target'];
1375  if ($target === '') {
1376  $target = 'thePicture';
1377  }
1378  }
1379  $a1 = '';
1380  $a2 = '';
1381  $conf['JSwindow'] = isset($conf['JSwindow.']) ? $this->‪stdWrap($conf['JSwindow'], $conf['JSwindow.']) : $conf['JSwindow'];
1382  if ($conf['JSwindow']) {
1383  if ($conf['JSwindow.']['altUrl'] || $conf['JSwindow.']['altUrl.']) {
1384  $altUrl = isset($conf['JSwindow.']['altUrl.']) ? $this->‪stdWrap($conf['JSwindow.']['altUrl'], $conf['JSwindow.']['altUrl.']) : $conf['JSwindow.']['altUrl'];
1385  if ($altUrl) {
1386  $url = $altUrl . ($conf['JSwindow.']['altUrl_noDefaultParams'] ? '' : '?file=' . rawurlencode($imageFile) . $params);
1387  }
1388  }
1389 
1390  $processedFile = $file->process(‪ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, $conf);
1391  $JSwindowExpand = isset($conf['JSwindow.']['expand.']) ? $this->‪stdWrap($conf['JSwindow.']['expand'], $conf['JSwindow.']['expand.']) : $conf['JSwindow.']['expand'];
1392  $offset = ‪GeneralUtility::intExplode(',', $JSwindowExpand . ',');
1393  $newWindow = isset($conf['JSwindow.']['newWindow.']) ? $this->‪stdWrap($conf['JSwindow.']['newWindow'], $conf['JSwindow.']['newWindow.']) : $conf['JSwindow.']['newWindow'];
1394  $params = [
1395  'width' => ($processedFile->getProperty('width') + $offset[0]),
1396  'height' => ($processedFile->getProperty('height') + $offset[1]),
1397  'status' => '0',
1398  'menubar' => '0'
1399  ];
1400  // params override existing parameters from above, or add more
1401  $windowParams = isset($conf['JSwindow.']['params.']) ? $this->‪stdWrap($conf['JSwindow.']['params'], $conf['JSwindow.']['params.']) : $conf['JSwindow.']['params'];
1402  $windowParams = explode(',', $windowParams);
1403  foreach ($windowParams as $windowParam) {
1404  [$paramKey, $paramValue] = explode('=', $windowParam);
1405  if ($paramValue !== '') {
1406  $params[$paramKey] = $paramValue;
1407  } else {
1408  unset($params[$paramKey]);
1409  }
1410  }
1411  $paramString = '';
1412  foreach ($params as $paramKey => $paramValue) {
1413  $paramString .= htmlspecialchars((string)$paramKey) . '=' . htmlspecialchars((string)$paramValue) . ',';
1414  }
1415 
1416  $onClick = 'openPic('
1417  . GeneralUtility::quoteJSvalue($this->‪getTypoScriptFrontendController()->baseUrlWrap($url)) . ','
1418  . '\'' . ($newWindow ? md5($url) : 'thePicture') . '\','
1419  . ‪GeneralUtility::quoteJSvalue(rtrim($paramString, ',')) . '); return false;';
1420  $a1 = '<a href="' . htmlspecialchars($url) . '"'
1421  . ' onclick="' . htmlspecialchars($onClick) . '"'
1422  . ($target !== '' ? ' target="' . htmlspecialchars($target) . '"' : '')
1423  . $this->‪getTypoScriptFrontendController()->ATagParams . '>';
1424  $a2 = '</a>';
1425  $this->‪getTypoScriptFrontendController()->‪setJS('openPic');
1426  } else {
1427  $conf['linkParams.']['directImageLink'] = (bool)$conf['directImageLink'];
1428  $conf['linkParams.']['parameter'] = $url;
1429  $string = $this->‪typoLink($string, $conf['linkParams.']);
1430  }
1431  if (isset($conf['stdWrap.'])) {
1432  $string = $this->‪stdWrap($string, $conf['stdWrap.']);
1433  }
1434  $content = $a1 . $string . $a2;
1435  }
1436  return $content;
1437  }
1438 
1447  public function ‪lastChanged($tstamp)
1448  {
1449  $tstamp = (int)$tstamp;
1450  $tsfe = $this->‪getTypoScriptFrontendController();
1451  if ($tstamp > (int)$tsfe->register['SYS_LASTCHANGED']) {
1452  $tsfe->register['SYS_LASTCHANGED'] = $tstamp;
1453  }
1454  }
1455 
1467  public function ‪linkWrap($content, $wrap)
1468  {
1469  trigger_error('cObj->linkWrap() will be removed in TYPO3 v11.0. This functionality is integrated into ImageContentObject.', E_USER_DEPRECATED);
1470  $wrapArr = explode('|', $wrap);
1471  if (preg_match('/\\{([0-9]*)\\}/', $wrapArr[0], $reg)) {
1472  $uid = $this->‪getTypoScriptFrontendController()->tmpl->rootLine[$reg[1]]['uid'] ?? null;
1473  if ($uid) {
1474  $wrapArr[0] = str_replace($reg[0], $uid, $wrapArr[0]);
1475  }
1476  }
1477  return trim($wrapArr[0] ?? '') . $content . trim($wrapArr[1] ?? '');
1478  }
1479 
1489  public function ‪getAltParam($conf, $longDesc = true)
1490  {
1491  trigger_error('cObj->getAltParam() will be removed in TYPO3 v11.0. This functionality is integrated into ImageContentObject.', E_USER_DEPRECATED);
1492  $altText = isset($conf['altText.']) ? trim($this->‪stdWrap($conf['altText'], $conf['altText.'])) : trim($conf['altText']);
1493  $titleText = isset($conf['titleText.']) ? trim($this->‪stdWrap($conf['titleText'], $conf['titleText.'])) : trim($conf['titleText']);
1494  if (isset($conf['longdescURL.']) && $this->‪getTypoScriptFrontendController()->config['config']['doctype'] !== 'html5') {
1495  $longDescUrl = $this->‪typoLink_URL($conf['longdescURL.']);
1496  } else {
1497  $longDescUrl = trim($conf['longdescURL']);
1498  }
1499  $longDescUrl = strip_tags($longDescUrl);
1500 
1501  // "alt":
1502  $altParam = ' alt="' . htmlspecialchars($altText) . '"';
1503  // "title":
1504  $emptyTitleHandling = isset($conf['emptyTitleHandling.']) ? $this->‪stdWrap($conf['emptyTitleHandling'], $conf['emptyTitleHandling.']) : $conf['emptyTitleHandling'];
1505  // Choices: 'keepEmpty' | 'useAlt' | 'removeAttr'
1506  if ($titleText || $emptyTitleHandling === 'keepEmpty') {
1507  $altParam .= ' title="' . htmlspecialchars($titleText) . '"';
1508  } elseif (!$titleText && $emptyTitleHandling === 'useAlt') {
1509  $altParam .= ' title="' . htmlspecialchars($altText) . '"';
1510  }
1511  // "longDesc" URL
1512  if ($longDesc && !empty($longDescUrl)) {
1513  $altParam .= ' longdesc="' . htmlspecialchars($longDescUrl) . '"';
1514  }
1515  return $altParam;
1516  }
1517 
1527  public function ‪getATagParams($conf, $addGlobal = 1)
1528  {
1529  $aTagParams = '';
1530  if ($conf['ATagParams.'] ?? false) {
1531  $aTagParams = ' ' . $this->‪stdWrap($conf['ATagParams'], $conf['ATagParams.']);
1532  } elseif ($conf['ATagParams'] ?? false) {
1533  $aTagParams = ' ' . $conf['ATagParams'];
1534  }
1535  if ($addGlobal) {
1536  $aTagParams = ' ' . trim($this->‪getTypoScriptFrontendController()->ATagParams . $aTagParams);
1537  }
1538  // Extend params
1539  $_params = [
1540  'conf' => &$conf,
1541  'aTagParams' => &$aTagParams
1542  ];
1543  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getATagParamsPostProc'] ?? [] as $className) {
1544  $processor = GeneralUtility::makeInstance($className);
1545  $aTagParams = $processor->process($_params, $this);
1546  }
1547 
1548  $aTagParams = trim($aTagParams);
1549  if (!empty($aTagParams)) {
1550  $aTagParams = ' ' . $aTagParams;
1551  }
1552 
1553  return $aTagParams;
1554  }
1555 
1565  public function ‪extLinkATagParams($URL, $TYPE)
1566  {
1567  $out = '';
1568  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['extLinkATagParamsHandler'])) {
1569  trigger_error('The hook $TYPO3_CONF_VARS[SC_OPTIONS][tslib/class.tslib_content.php][extLinkATagParamsHandler] will be removed in TYPO3 v11.0. Use a custom LinkHandler instead.', E_USER_DEPRECATED);
1570  $extLinkATagParamsHandler = GeneralUtility::makeInstance(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['extLinkATagParamsHandler']);
1571  if (method_exists($extLinkATagParamsHandler, 'main')) {
1572  $out .= trim($extLinkATagParamsHandler->main($URL, $TYPE, $this));
1573  }
1574  }
1575  return trim($out) ? ' ' . trim($out) : '';
1576  }
1577 
1578  /***********************************************
1579  *
1580  * HTML template processing functions
1581  *
1582  ***********************************************/
1583 
1589  public function ‪setCurrentFile($fileObject)
1590  {
1591  $this->currentFile = $fileObject;
1592  }
1593 
1599  public function ‪getCurrentFile()
1600  {
1601  return ‪$this->currentFile;
1602  }
1603 
1604  /***********************************************
1605  *
1606  * "stdWrap" + sub functions
1607  *
1608  ***********************************************/
1620  public function ‪stdWrap($content = '', $conf = [])
1621  {
1622  $content = (string)$content;
1623  // If there is any hook object, activate all of the process and override functions.
1624  // The hook interface ContentObjectStdWrapHookInterface takes care that all 4 methods exist.
1625  if ($this->stdWrapHookObjects) {
1626  $conf['stdWrapPreProcess'] = 1;
1627  $conf['stdWrapOverride'] = 1;
1628  $conf['stdWrapProcess'] = 1;
1629  $conf['stdWrapPostProcess'] = 1;
1630  }
1631 
1632  if (!is_array($conf) || !$conf) {
1633  return $content;
1634  }
1635 
1636  // Cache handling
1637  if (isset($conf['cache.']) && is_array($conf['cache.'])) {
1638  $conf['cache.']['key'] = $this->‪stdWrap($conf['cache.']['key'], $conf['cache.']['key.']);
1639  $conf['cache.']['tags'] = $this->‪stdWrap($conf['cache.']['tags'], $conf['cache.']['tags.']);
1640  $conf['cache.']['lifetime'] = $this->‪stdWrap($conf['cache.']['lifetime'], $conf['cache.']['lifetime.']);
1641  $conf['cacheRead'] = 1;
1642  $conf['cacheStore'] = 1;
1643  }
1644  // The configuration is sorted and filtered by intersection with the defined stdWrapOrder.
1645  $sortedConf = array_keys(array_intersect_key($this->stdWrapOrder, $conf));
1646  // Functions types that should not make use of nested stdWrap function calls to avoid conflicts with internal TypoScript used by these functions
1647  $stdWrapDisabledFunctionTypes = 'cObject,functionName,stdWrap';
1648  // Additional Array to check whether a function has already been executed
1649  $isExecuted = [];
1650  // Additional switch to make sure 'required', 'if' and 'fieldRequired'
1651  // will still stop rendering immediately in case they return FALSE
1652  $this->stdWrapRecursionLevel++;
1653  $this->stopRendering[‪$this->stdWrapRecursionLevel] = false;
1654  // execute each function in the predefined order
1655  foreach ($sortedConf as $stdWrapName) {
1656  // eliminate the second key of a pair 'key'|'key.' to make sure functions get called only once and check if rendering has been stopped
1657  if ((!isset($isExecuted[$stdWrapName]) || !$isExecuted[$stdWrapName]) && !$this->stopRendering[$this->stdWrapRecursionLevel]) {
1658  $functionName = rtrim($stdWrapName, '.');
1659  $functionProperties = $functionName . '.';
1660  $functionType = $this->stdWrapOrder[$functionName] ?? '';
1661  // If there is any code on the next level, check if it contains "official" stdWrap functions
1662  // if yes, execute them first - will make each function stdWrap aware
1663  // so additional stdWrap calls within the functions can be removed, since the result will be the same
1664  if (!empty($conf[$functionProperties]) && !GeneralUtility::inList($stdWrapDisabledFunctionTypes, $functionType)) {
1665  if (array_intersect_key($this->stdWrapOrder, $conf[$functionProperties])) {
1666  // Check if there's already content available before processing
1667  // any ifEmpty or ifBlank stdWrap properties
1668  if (($functionName === 'ifBlank' && $content !== '') ||
1669  ($functionName === 'ifEmpty' && trim($content) !== '')) {
1670  continue;
1671  }
1672 
1673  $conf[$functionName] = $this->‪stdWrap($conf[$functionName] ?? '', $conf[$functionProperties] ?? []);
1674  }
1675  }
1676  // Check if key is still containing something, since it might have been changed by next level stdWrap before
1677  if ((isset($conf[$functionName]) || $conf[$functionProperties])
1678  && ($functionType !== 'boolean' || $conf[$functionName])
1679  ) {
1680  // Get just that part of $conf that is needed for the particular function
1681  $singleConf = [
1682  $functionName => $conf[$functionName] ?? null,
1683  $functionProperties => $conf[$functionProperties] ?? null
1684  ];
1685  // Hand over the whole $conf array to the stdWrapHookObjects
1686  if ($functionType === 'hook') {
1687  $singleConf = $conf;
1688  }
1689  // Add both keys - with and without the dot - to the set of executed functions
1690  $isExecuted[$functionName] = true;
1691  $isExecuted[$functionProperties] = true;
1692  // Call the function with the prefix stdWrap_ to make sure nobody can execute functions just by adding their name to the TS Array
1693  $functionName = 'stdWrap_' . $functionName;
1694  $content = $this->{$functionName}($content, $singleConf);
1695  } elseif ($functionType === 'boolean' && !$conf[$functionName]) {
1696  $isExecuted[$functionName] = true;
1697  $isExecuted[$functionProperties] = true;
1698  }
1699  }
1700  }
1701  unset($this->stopRendering[$this->stdWrapRecursionLevel]);
1702  $this->stdWrapRecursionLevel--;
1703 
1704  return $content;
1705  }
1706 
1715  public function ‪stdWrapValue($key, array $config, $defaultValue = '')
1716  {
1717  if (isset($config[$key])) {
1718  if (!isset($config[$key . '.'])) {
1719  return $config[$key];
1720  }
1721  } elseif (isset($config[$key . '.'])) {
1722  $config[$key] = '';
1723  } else {
1724  return $defaultValue;
1725  }
1726  $stdWrapped = $this->‪stdWrap($config[$key], $config[$key . '.']);
1727  return $stdWrapped ?: $defaultValue;
1728  }
1729 
1739  public function ‪stdWrap_stdWrapPreProcess($content = '', $conf = [])
1740  {
1741  foreach ($this->stdWrapHookObjects as $hookObject) {
1743  $content = $hookObject->stdWrapPreProcess($content, $conf, $this);
1744  }
1745  return $content;
1746  }
1747 
1755  public function ‪stdWrap_cacheRead($content = '', $conf = [])
1756  {
1757  if (!isset($conf['cache.'])) {
1758  return $content;
1759  }
1760  $result = $this->‪getFromCache($conf['cache.']);
1761  return $result === false ? $content : $result;
1762  }
1763 
1771  public function ‪stdWrap_addPageCacheTags($content = '', $conf = [])
1772  {
1773  $tags = isset($conf['addPageCacheTags.'])
1774  ? $this->‪stdWrap($conf['addPageCacheTags'], $conf['addPageCacheTags.'])
1775  : $conf['addPageCacheTags'];
1776  if (!empty($tags)) {
1777  $cacheTags = ‪GeneralUtility::trimExplode(',', $tags, true);
1779  }
1780  return $content;
1781  }
1782 
1790  public function ‪stdWrap_setContentToCurrent($content = '')
1791  {
1792  $this->data[‪$this->currentValKey] = $content;
1793  return $content;
1794  }
1795 
1804  public function ‪stdWrap_setCurrent($content = '', $conf = [])
1805  {
1806  $this->data[‪$this->currentValKey] = $conf['setCurrent'] ?? null;
1807  return $content;
1808  }
1809 
1818  public function ‪stdWrap_lang($content = '', $conf = [])
1819  {
1820  $currentLanguageCode = $this->‪getTypoScriptFrontendController()->‪getLanguage()->getTypo3Language();
1821  if (!$currentLanguageCode) {
1822  return $content;
1823  }
1824  if (isset($conf['lang.'][$currentLanguageCode])) {
1825  $content = $conf['lang.'][$currentLanguageCode];
1826  } else {
1827  // Check language dependencies
1828  ‪$locales = GeneralUtility::makeInstance(Locales::class);
1829  foreach (‪$locales->getLocaleDependencies($currentLanguageCode) as $languageCode) {
1830  if (isset($conf['lang.'][$languageCode])) {
1831  $content = $conf['lang.'][$languageCode];
1832  break;
1833  }
1834  }
1835  }
1836  return $content;
1837  }
1838 
1847  public function ‪stdWrap_data($content = '', $conf = [])
1848  {
1849  $content = $this->‪getData($conf['data'], is_array($this->alternativeData) ? $this->alternativeData : $this->data);
1850  // This must be unset directly after
1851  $this->alternativeData = '';
1852  return $content;
1853  }
1854 
1863  public function ‪stdWrap_field($content = '', $conf = [])
1864  {
1865  return $this->‪getFieldVal($conf['field']);
1866  }
1867 
1877  public function ‪stdWrap_current($content = '', $conf = [])
1878  {
1879  return $this->data[‪$this->currentValKey];
1880  }
1881 
1891  public function ‪stdWrap_cObject($content = '', $conf = [])
1892  {
1893  return $this->‪cObjGetSingle($conf['cObject'] ?? '', $conf['cObject.'] ?? [], '/stdWrap/.cObject');
1894  }
1895 
1905  public function ‪stdWrap_numRows($content = '', $conf = [])
1906  {
1907  return $this->‪numRows($conf['numRows.']);
1908  }
1909 
1918  public function ‪stdWrap_preUserFunc($content = '', $conf = [])
1919  {
1920  return $this->‪callUserFunction($conf['preUserFunc'], $conf['preUserFunc.'] ?? [], $content);
1921  }
1922 
1932  public function ‪stdWrap_stdWrapOverride($content = '', $conf = [])
1933  {
1934  foreach ($this->stdWrapHookObjects as $hookObject) {
1936  $content = $hookObject->stdWrapOverride($content, $conf, $this);
1937  }
1938  return $content;
1939  }
1940 
1949  public function ‪stdWrap_override($content = '', $conf = [])
1950  {
1951  if (trim($conf['override'] ?? false)) {
1952  $content = $conf['override'];
1953  }
1954  return $content;
1955  }
1956 
1966  public function ‪stdWrap_preIfEmptyListNum($content = '', $conf = [])
1967  {
1968  return $this->‪listNum($content, $conf['preIfEmptyListNum'] ?? null, $conf['preIfEmptyListNum.']['splitChar'] ?? null);
1969  }
1970 
1979  public function ‪stdWrap_ifNull($content = '', $conf = [])
1980  {
1981  return $content ?? $conf['ifNull'];
1982  }
1983 
1993  public function ‪stdWrap_ifEmpty($content = '', $conf = [])
1994  {
1995  if (!trim($content)) {
1996  $content = $conf['ifEmpty'];
1997  }
1998  return $content;
1999  }
2000 
2010  public function ‪stdWrap_ifBlank($content = '', $conf = [])
2011  {
2012  if (trim($content) === '') {
2013  $content = $conf['ifBlank'];
2014  }
2015  return $content;
2016  }
2017 
2028  public function ‪stdWrap_listNum($content = '', $conf = [])
2029  {
2030  return $this->‪listNum($content, $conf['listNum'] ?? null, $conf['listNum.']['splitChar'] ?? null);
2031  }
2032 
2040  public function ‪stdWrap_trim($content = '')
2041  {
2042  return trim($content);
2043  }
2044 
2053  public function ‪stdWrap_strPad($content = '', $conf = [])
2054  {
2055  // Must specify a length in conf for this to make sense
2056  $length = 0;
2057  // Padding with space is PHP-default
2058  $padWith = ' ';
2059  // Padding on the right side is PHP-default
2060  $padType = STR_PAD_RIGHT;
2061  if (!empty($conf['strPad.']['length'])) {
2062  $length = isset($conf['strPad.']['length.']) ? $this->‪stdWrap($conf['strPad.']['length'], $conf['strPad.']['length.']) : $conf['strPad.']['length'];
2063  $length = (int)$length;
2064  }
2065  if (isset($conf['strPad.']['padWith']) && (string)$conf['strPad.']['padWith'] !== '') {
2066  $padWith = isset($conf['strPad.']['padWith.']) ? $this->‪stdWrap($conf['strPad.']['padWith'], $conf['strPad.']['padWith.']) : $conf['strPad.']['padWith'];
2067  }
2068  if (!empty($conf['strPad.']['type'])) {
2069  $type = isset($conf['strPad.']['type.']) ? $this->‪stdWrap($conf['strPad.']['type'], $conf['strPad.']['type.']) : $conf['strPad.']['type'];
2070  if (strtolower($type) === 'left') {
2071  $padType = STR_PAD_LEFT;
2072  } elseif (strtolower($type) === 'both') {
2073  $padType = STR_PAD_BOTH;
2074  }
2075  }
2076  return ‪StringUtility::multibyteStringPad($content, $length, $padWith, $padType);
2077  }
2078 
2090  public function ‪stdWrap_stdWrap($content = '', $conf = [])
2091  {
2092  return $this->‪stdWrap($content, $conf['stdWrap.']);
2093  }
2094 
2104  public function ‪stdWrap_stdWrapProcess($content = '', $conf = [])
2105  {
2106  foreach ($this->stdWrapHookObjects as $hookObject) {
2108  $content = $hookObject->stdWrapProcess($content, $conf, $this);
2109  }
2110  return $content;
2111  }
2112 
2121  public function ‪stdWrap_required($content = '')
2122  {
2123  if ((string)$content === '') {
2124  $content = '';
2125  $this->stopRendering[‪$this->stdWrapRecursionLevel] = true;
2126  }
2127  return $content;
2128  }
2129 
2139  public function ‪stdWrap_if($content = '', $conf = [])
2140  {
2141  if (empty($conf['if.']) || $this->‪checkIf($conf['if.'])) {
2142  return $content;
2143  }
2144  $this->stopRendering[‪$this->stdWrapRecursionLevel] = true;
2145  return '';
2146  }
2147 
2157  public function ‪stdWrap_fieldRequired($content = '', $conf = [])
2158  {
2159  if (!trim($this->data[$conf['fieldRequired'] ?? null] ?? '')) {
2160  $content = '';
2161  $this->stopRendering[‪$this->stdWrapRecursionLevel] = true;
2162  }
2163  return $content;
2164  }
2165 
2176  public function ‪stdWrap_csConv($content = '', $conf = [])
2177  {
2178  if (!empty($conf['csConv'])) {
2179  ‪$output = mb_convert_encoding($content, 'utf-8', trim(strtolower($conf['csConv'])));
2180  return ‪$output !== false && ‪$output !== '' ? ‪$output : $content;
2181  }
2182  return $content;
2183  }
2184 
2194  public function ‪stdWrap_parseFunc($content = '', $conf = [])
2195  {
2196  return $this->‪parseFunc($content, $conf['parseFunc.'], $conf['parseFunc']);
2197  }
2198 
2208  public function ‪stdWrap_HTMLparser($content = '', $conf = [])
2209  {
2210  if (isset($conf['HTMLparser.']) && is_array($conf['HTMLparser.'])) {
2211  $content = $this->‪HTMLparser_TSbridge($content, $conf['HTMLparser.']);
2212  }
2213  return $content;
2214  }
2215 
2225  public function ‪stdWrap_split($content = '', $conf = [])
2226  {
2227  return $this->‪splitObj($content, $conf['split.']);
2228  }
2229 
2238  public function ‪stdWrap_replacement($content = '', $conf = [])
2239  {
2240  return $this->‪replacement($content, $conf['replacement.']);
2241  }
2252  public function ‪stdWrap_prioriCalc($content = '', $conf = [])
2253  {
2255  if (!empty($conf['prioriCalc']) && $conf['prioriCalc'] === 'intval') {
2256  $content = (int)$content;
2257  }
2258  return $content;
2259  }
2260 
2272  public function ‪stdWrap_char($content = '', $conf = [])
2273  {
2274  return chr((int)$conf['char']);
2275  }
2276 
2284  public function ‪stdWrap_intval($content = '')
2285  {
2286  return (int)$content;
2287  }
2288 
2297  public function ‪stdWrap_hash($content = '', array $conf = [])
2298  {
2299  $algorithm = isset($conf['hash.']) ? $this->‪stdWrap($conf['hash'], $conf['hash.']) : $conf['hash'];
2300  if (function_exists('hash') && in_array($algorithm, hash_algos())) {
2301  return hash($algorithm, $content);
2302  }
2303  // Non-existing hashing algorithm
2304  return '';
2305  }
2306 
2315  public function ‪stdWrap_round($content = '', $conf = [])
2316  {
2317  return $this->‪round($content, $conf['round.']);
2318  }
2319 
2328  public function ‪stdWrap_numberFormat($content = '', $conf = [])
2329  {
2330  return $this->‪numberFormat((float)$content, $conf['numberFormat.'] ?? []);
2331  }
2332 
2340  public function ‪stdWrap_expandList($content = '')
2341  {
2342  return GeneralUtility::expandList($content);
2343  }
2344 
2354  public function ‪stdWrap_date($content = '', $conf = [])
2355  {
2356  // Check for zero length string to mimic default case of date/gmdate.
2357  $content = (string)$content === '' ? ‪$GLOBALS['EXEC_TIME'] : (int)$content;
2358  $content = !empty($conf['date.']['GMT']) ? gmdate($conf['date'] ?? null, $content) : date($conf['date'] ?? null, $content);
2359  return $content;
2360  }
2361 
2371  public function ‪stdWrap_strftime($content = '', $conf = [])
2372  {
2373  // Check for zero length string to mimic default case of strtime/gmstrftime
2374  $content = (string)$content === '' ? ‪$GLOBALS['EXEC_TIME'] : (int)$content;
2375  $content = (isset($conf['strftime.']['GMT']) && $conf['strftime.']['GMT'])
2376  ? gmstrftime($conf['strftime'] ?? null, $content)
2377  : strftime($conf['strftime'] ?? null, $content);
2378  if (!empty($conf['strftime.']['charset'])) {
2379  ‪$output = mb_convert_encoding($content, 'utf-8', trim(strtolower($conf['strftime.']['charset'])));
2380  return ‪$output ?: $content;
2381  }
2382  return $content;
2383  }
2384 
2393  public function ‪stdWrap_strtotime($content = '', $conf = [])
2394  {
2395  if ($conf['strtotime'] !== '1') {
2396  $content .= ' ' . $conf['strtotime'];
2397  }
2398  return strtotime($content, ‪$GLOBALS['EXEC_TIME']);
2399  }
2400 
2409  public function ‪stdWrap_age($content = '', $conf = [])
2410  {
2411  return $this->‪calcAge((int)(‪$GLOBALS['EXEC_TIME'] ?? 0) - (int)$content, $conf['age'] ?? null);
2412  }
2413 
2423  public function ‪stdWrap_case($content = '', $conf = [])
2424  {
2425  return $this->‪HTMLcaseshift($content, $conf['case']);
2426  }
2427 
2436  public function ‪stdWrap_bytes($content = '', $conf = [])
2437  {
2438  return GeneralUtility::formatSize((int)$content, $conf['bytes.']['labels'], $conf['bytes.']['base']);
2439  }
2440 
2449  public function ‪stdWrap_substring($content = '', $conf = [])
2450  {
2451  return $this->‪substring($content, $conf['substring']);
2452  }
2453 
2462  public function ‪stdWrap_cropHTML($content = '', $conf = [])
2463  {
2464  return $this->‪cropHTML($content, $conf['cropHTML'] ?? '');
2465  }
2466 
2474  public function ‪stdWrap_stripHtml($content = '')
2475  {
2476  return strip_tags($content);
2477  }
2478 
2487  public function ‪stdWrap_crop($content = '', $conf = [])
2488  {
2489  return $this->‪crop($content, $conf['crop']);
2490  }
2491 
2499  public function ‪stdWrap_rawUrlEncode($content = '')
2500  {
2501  return rawurlencode($content);
2502  }
2503 
2513  public function ‪stdWrap_htmlSpecialChars($content = '', $conf = [])
2514  {
2515  if (!empty($conf['htmlSpecialChars.']['preserveEntities'])) {
2516  $content = htmlspecialchars($content, ENT_COMPAT, 'UTF-8', false);
2517  } else {
2518  $content = htmlspecialchars($content);
2519  }
2520  return $content;
2521  }
2522 
2530  public function ‪stdWrap_encodeForJavaScriptValue($content = '')
2531  {
2532  return GeneralUtility::quoteJSvalue($content);
2533  }
2534 
2543  public function ‪stdWrap_doubleBrTag($content = '', $conf = [])
2544  {
2545  return preg_replace('/\R{1,2}[\t\x20]*\R{1,2}/', $conf['doubleBrTag'] ?? null, $content);
2546  }
2547 
2556  public function ‪stdWrap_br($content = '')
2557  {
2558  return nl2br($content, !empty($this->‪getTypoScriptFrontendController()->xhtmlDoctype));
2559  }
2560 
2569  public function ‪stdWrap_brTag($content = '', $conf = [])
2570  {
2571  return str_replace(LF, $conf['brTag'] ?? null, $content);
2572  }
2573 
2583  public function ‪stdWrap_encapsLines($content = '', $conf = [])
2584  {
2585  return $this->‪encaps_lineSplit($content, $conf['encapsLines.']);
2586  }
2587 
2595  public function ‪stdWrap_keywords($content = '')
2596  {
2597  return $this->‪keywords($content);
2598  }
2599 
2609  public function ‪stdWrap_innerWrap($content = '', $conf = [])
2610  {
2611  return $this->‪wrap($content, $conf['innerWrap'] ?? null);
2612  }
2613 
2623  public function ‪stdWrap_innerWrap2($content = '', $conf = [])
2624  {
2625  return $this->‪wrap($content, $conf['innerWrap2'] ?? null);
2626  }
2627 
2636  public function ‪stdWrap_preCObject($content = '', $conf = [])
2637  {
2638  return $this->‪cObjGetSingle($conf['preCObject'], $conf['preCObject.'], '/stdWrap/.preCObject') . $content;
2639  }
2640 
2649  public function ‪stdWrap_postCObject($content = '', $conf = [])
2650  {
2651  return $content . $this->‪cObjGetSingle($conf['postCObject'], $conf['postCObject.'], '/stdWrap/.postCObject');
2652  }
2653 
2663  public function ‪stdWrap_wrapAlign($content = '', $conf = [])
2664  {
2665  $wrapAlign = trim($conf['wrapAlign'] ?? '');
2666  if ($wrapAlign) {
2667  $content = $this->‪wrap($content, '<div style="text-align:' . htmlspecialchars($wrapAlign) . ';">|</div>');
2668  }
2669  return $content;
2670  }
2671 
2682  public function ‪stdWrap_typolink($content = '', $conf = [])
2683  {
2684  return $this->‪typoLink($content, $conf['typolink.']);
2685  }
2686 
2699  public function ‪stdWrap_wrap($content = '', $conf = [])
2700  {
2701  return $this->‪wrap(
2702  $content,
2703  $conf['wrap'] ?? null,
2704  $conf['wrap.']['splitChar'] ?? '|'
2705  );
2706  }
2707 
2717  public function ‪stdWrap_noTrimWrap($content = '', $conf = [])
2718  {
2719  $splitChar = isset($conf['noTrimWrap.']['splitChar.'])
2720  ? $this->‪stdWrap($conf['noTrimWrap.']['splitChar'] ?? '', $conf['noTrimWrap.']['splitChar.'])
2721  : $conf['noTrimWrap.']['splitChar'] ?? '';
2722  if ($splitChar === null || $splitChar === '') {
2723  $splitChar = '|';
2724  }
2725  $content = $this->‪noTrimWrap(
2726  $content,
2727  $conf['noTrimWrap'],
2728  $splitChar
2729  );
2730  return $content;
2731  }
2732 
2742  public function ‪stdWrap_wrap2($content = '', $conf = [])
2743  {
2744  return $this->‪wrap(
2745  $content,
2746  $conf['wrap2'] ?? null,
2747  $conf['wrap2.']['splitChar'] ?? '|'
2748  );
2749  }
2750 
2760  public function ‪stdWrap_dataWrap($content = '', $conf = [])
2761  {
2762  return $this->‪dataWrap($content, $conf['dataWrap']);
2763  }
2764 
2773  public function ‪stdWrap_prepend($content = '', $conf = [])
2774  {
2775  return $this->‪cObjGetSingle($conf['prepend'], $conf['prepend.'], '/stdWrap/.prepend') . $content;
2776  }
2777 
2786  public function ‪stdWrap_append($content = '', $conf = [])
2787  {
2788  return $content . $this->‪cObjGetSingle($conf['append'], $conf['append.'], '/stdWrap/.append');
2789  }
2790 
2800  public function ‪stdWrap_wrap3($content = '', $conf = [])
2801  {
2802  return $this->‪wrap(
2803  $content,
2804  $conf['wrap3'] ?? null,
2805  $conf['wrap3.']['splitChar'] ?? '|'
2806  );
2807  }
2808 
2817  public function ‪stdWrap_orderedStdWrap($content = '', $conf = [])
2818  {
2819  $sortedKeysArray = ‪ArrayUtility::filterAndSortByNumericKeys($conf['orderedStdWrap.'], true);
2820  foreach ($sortedKeysArray as $key) {
2821  $content = $this->‪stdWrap($content, $conf['orderedStdWrap.'][$key . '.'] ?? null);
2822  }
2823  return $content;
2824  }
2825 
2834  public function ‪stdWrap_outerWrap($content = '', $conf = [])
2835  {
2836  return $this->‪wrap($content, $conf['outerWrap'] ?? null);
2837  }
2838 
2846  public function ‪stdWrap_insertData($content = '')
2847  {
2848  return $this->‪insertData($content);
2849  }
2850 
2859  public function ‪stdWrap_postUserFunc($content = '', $conf = [])
2860  {
2861  return $this->‪callUserFunction($conf['postUserFunc'], $conf['postUserFunc.'] ?? [], $content);
2862  }
2863 
2873  public function ‪stdWrap_postUserFuncInt($content = '', $conf = [])
2874  {
2875  $substKey = 'INT_SCRIPT.' . $this->‪getTypoScriptFrontendController()->‪uniqueHash();
2876  $this->‪getTypoScriptFrontendController()->config['INTincScript'][$substKey] = [
2877  'content' => $content,
2878  'postUserFunc' => $conf['postUserFuncInt'],
2879  'conf' => $conf['postUserFuncInt.'],
2880  'type' => 'POSTUSERFUNC',
2881  'cObj' => serialize($this)
2882  ];
2883  $content = '<!--' . $substKey . '-->';
2884  return $content;
2885  }
2886 
2895  public function ‪stdWrap_prefixComment($content = '', $conf = [])
2896  {
2897  if (
2898  (!isset($this->‪getTypoScriptFrontendController()->config['config']['disablePrefixComment']) || !$this->‪getTypoScriptFrontendController()->config['config']['disablePrefixComment'])
2899  && !empty($conf['prefixComment'])
2900  ) {
2901  $content = $this->‪prefixComment($conf['prefixComment'], [], $content);
2902  }
2903  return $content;
2904  }
2905 
2914  public function ‪stdWrap_editIcons($content = '', $conf = [])
2915  {
2916  if ($this->‪getTypoScriptFrontendController()->isBackendUserLoggedIn() && $conf['editIcons']) {
2917  if (!isset($conf['editIcons.']) || !is_array($conf['editIcons.'])) {
2918  $conf['editIcons.'] = [];
2919  }
2920  $content = $this->‪editIcons($content, $conf['editIcons'], $conf['editIcons.']);
2921  }
2922  return $content;
2923  }
2924 
2933  public function ‪stdWrap_editPanel($content = '', $conf = [])
2934  {
2935  if ($this->‪getTypoScriptFrontendController()->isBackendUserLoggedIn()) {
2936  $content = $this->‪editPanel($content, $conf['editPanel.']);
2937  }
2938  return $content;
2939  }
2940 
2941  public function ‪stdWrap_htmlSanitize(string $content = '', array $conf = []): string
2942  {
2943  $build = $conf['build'] ?? 'default';
2944  if (class_exists($build) && is_a($build, BuilderInterface::class, true)) {
2945  $builder = GeneralUtility::makeInstance($build);
2946  } else {
2947  $factory = GeneralUtility::makeInstance(SanitizerBuilderFactory::class);
2948  $builder = $factory->build($build);
2949  }
2950  $sanitizer = $builder->build();
2951  $initiator = $this->‪shallDebug()
2952  ? GeneralUtility::makeInstance(SanitizerInitiator::class, ‪DebugUtility::debugTrail())
2953  : null;
2954  return $sanitizer->sanitize($content, $initiator);
2955  }
2956 
2964  public function ‪stdWrap_cacheStore($content = '', $conf = [])
2965  {
2966  if (!isset($conf['cache.'])) {
2967  return $content;
2968  }
2969  $key = $this->‪calculateCacheKey($conf['cache.']);
2970  if (empty($key)) {
2971  return $content;
2972  }
2974  $cacheFrontend = GeneralUtility::makeInstance(CacheManager::class)->getCache('hash');
2975  $tags = $this->‪calculateCacheTags($conf['cache.']);
2976  $lifetime = $this->‪calculateCacheLifetime($conf['cache.']);
2977  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['stdWrap_cacheStore'] ?? [] as $_funcRef) {
2978  $params = [
2979  'key' => $key,
2980  'content' => $content,
2981  'lifetime' => $lifetime,
2982  'tags' => $tags
2983  ];
2984  $ref = $this; // introduced for phpstan to not lose type information when passing $this into callUserFunction
2985  GeneralUtility::callUserFunction($_funcRef, $params, $ref);
2986  }
2987  $cacheFrontend->set($key, $content, $tags, $lifetime);
2988  return $content;
2989  }
2990 
3000  public function ‪stdWrap_stdWrapPostProcess($content = '', $conf = [])
3001  {
3002  foreach ($this->stdWrapHookObjects as $hookObject) {
3004  $content = $hookObject->stdWrapPostProcess($content, $conf, $this);
3005  }
3006  return $content;
3007  }
3008 
3016  public function ‪stdWrap_debug($content = '')
3017  {
3018  return '<pre>' . htmlspecialchars($content) . '</pre>';
3019  }
3020 
3029  public function ‪stdWrap_debugFunc($content = '', $conf = [])
3030  {
3031  ‪debug((int)$conf['debugFunc'] === 2 ? [$content] : $content);
3032  return $content;
3033  }
3034 
3042  public function ‪stdWrap_debugData($content = '')
3043  {
3044  ‪debug($this->data, '$cObj->data:');
3045  if (is_array($this->alternativeData)) {
3046  ‪debug($this->alternativeData, '$this->alternativeData');
3047  }
3048  return $content;
3049  }
3050 
3060  public function ‪numRows($conf)
3061  {
3062  $conf['select.']['selectFields'] = 'count(*)';
3063  $statement = $this->‪exec_getQuery($conf['table'], $conf['select.']);
3064 
3065  return (int)$statement->fetchColumn(0);
3066  }
3067 
3076  public function ‪listNum($content, $listNum, $char)
3077  {
3078  $char = $char ?: ',';
3080  $char = chr((int)$char);
3081  }
3082  $temp = explode($char, $content);
3083  if (empty($temp)) {
3084  return '';
3085  }
3086  $last = '' . (count($temp) - 1);
3087  // Take a random item if requested
3088  if ($listNum === 'rand') {
3089  $listNum = (string)random_int(0, count($temp) - 1);
3090  }
3091  $index = $this->‪calc(str_ireplace('last', $last, $listNum));
3092  return $temp[$index];
3093  }
3094 
3104  public function ‪checkIf($conf)
3105  {
3106  if (!is_array($conf)) {
3107  return true;
3108  }
3109  if (isset($conf['directReturn'])) {
3110  return (bool)$conf['directReturn'];
3111  }
3112  $flag = true;
3113  if (isset($conf['isNull.'])) {
3114  $isNull = $this->‪stdWrap('', $conf['isNull.']);
3115  if ($isNull !== null) {
3116  $flag = false;
3117  }
3118  }
3119  if (isset($conf['isTrue']) || isset($conf['isTrue.'])) {
3120  $isTrue = isset($conf['isTrue.']) ? trim($this->‪stdWrap($conf['isTrue'], $conf['isTrue.'])) : trim($conf['isTrue']);
3121  if (!$isTrue) {
3122  $flag = false;
3123  }
3124  }
3125  if (isset($conf['isFalse']) || isset($conf['isFalse.'])) {
3126  $isFalse = isset($conf['isFalse.']) ? trim($this->‪stdWrap($conf['isFalse'], $conf['isFalse.'])) : trim($conf['isFalse']);
3127  if ($isFalse) {
3128  $flag = false;
3129  }
3130  }
3131  if (isset($conf['isPositive']) || isset($conf['isPositive.'])) {
3132  $number = isset($conf['isPositive.']) ? $this->‪calc($this->‪stdWrap($conf['isPositive'], $conf['isPositive.'])) : $this->‪calc($conf['isPositive']);
3133  if ($number < 1) {
3134  $flag = false;
3135  }
3136  }
3137  if ($flag) {
3138  $value = isset($conf['value.'])
3139  ? trim($this->‪stdWrap($conf['value'] ?? '', $conf['value.']))
3140  : trim($conf['value'] ?? '');
3141  if (isset($conf['isGreaterThan']) || isset($conf['isGreaterThan.'])) {
3142  $number = isset($conf['isGreaterThan.']) ? trim($this->‪stdWrap($conf['isGreaterThan'], $conf['isGreaterThan.'])) : trim($conf['isGreaterThan']);
3143  if ($number <= $value) {
3144  $flag = false;
3145  }
3146  }
3147  if (isset($conf['isLessThan']) || isset($conf['isLessThan.'])) {
3148  $number = isset($conf['isLessThan.']) ? trim($this->‪stdWrap($conf['isLessThan'], $conf['isLessThan.'])) : trim($conf['isLessThan']);
3149  if ($number >= $value) {
3150  $flag = false;
3151  }
3152  }
3153  if (isset($conf['equals']) || isset($conf['equals.'])) {
3154  $number = isset($conf['equals.']) ? trim($this->‪stdWrap($conf['equals'], $conf['equals.'])) : trim($conf['equals']);
3155  if ($number != $value) {
3156  $flag = false;
3157  }
3158  }
3159  if (isset($conf['isInList']) || isset($conf['isInList.'])) {
3160  $number = isset($conf['isInList.']) ? trim($this->‪stdWrap($conf['isInList'], $conf['isInList.'])) : trim($conf['isInList']);
3161  if (!GeneralUtility::inList($value, $number)) {
3162  $flag = false;
3163  }
3164  }
3165  if (isset($conf['bitAnd']) || isset($conf['bitAnd.'])) {
3166  $number = (int)(isset($conf['bitAnd.']) ? trim($this->‪stdWrap($conf['bitAnd'], $conf['bitAnd.'])) : trim($conf['bitAnd']));
3167  if ((new BitSet($number))->get($value) === false) {
3168  $flag = false;
3169  }
3170  }
3171  }
3172  if ($conf['negate'] ?? false) {
3173  $flag = !$flag;
3174  }
3175  return $flag;
3176  }
3177 
3190  public function ‪HTMLparser_TSbridge($theValue, $conf)
3191  {
3192  $htmlParser = GeneralUtility::makeInstance(HtmlParser::class);
3193  $htmlParserCfg = $htmlParser->HTMLparserConfig($conf);
3194  return $htmlParser->HTMLcleaner($theValue, $htmlParserCfg[0], $htmlParserCfg[1], $htmlParserCfg[2], $htmlParserCfg[3]);
3195  }
3206  public function ‪dataWrap($content, $wrap)
3207  {
3208  return $this->‪wrap($content, $this->‪insertData($wrap));
3209  }
3210 
3226  public function ‪insertData($str)
3227  {
3228  $inside = 0;
3229  $newVal = '';
3230  $pointer = 0;
3231  $totalLen = strlen($str);
3232  do {
3233  if (!$inside) {
3234  $len = strcspn(substr($str, $pointer), '{');
3235  $newVal .= substr($str, $pointer, $len);
3236  $inside = true;
3237  if (substr($str, $pointer + $len + 1, 1) === '#') {
3238  $len2 = strcspn(substr($str, $pointer + $len), '}');
3239  $newVal .= substr($str, $pointer + $len, $len2);
3240  $len += $len2;
3241  $inside = false;
3242  }
3243  } else {
3244  $len = strcspn(substr($str, $pointer), '}') + 1;
3245  $newVal .= $this->‪getData(substr($str, $pointer + 1, $len - 2), $this->data);
3246  $inside = false;
3247  }
3248  $pointer += $len;
3249  } while ($pointer < $totalLen);
3250  return $newVal;
3251  }
3252 
3263  public function ‪prefixComment($str, $conf, $content)
3264  {
3265  if (empty($str)) {
3266  return $content;
3267  }
3268  $parts = explode('|', $str);
3269  $indent = (int)$parts[0];
3270  $comment = htmlspecialchars($this->‪insertData($parts[1]));
3271  ‪$output = LF
3272  . str_pad('', $indent, "\t") . '<!-- ' . $comment . ' [begin] -->' . LF
3273  . str_pad('', $indent + 1, "\t") . $content . LF
3274  . str_pad('', $indent, "\t") . '<!-- ' . $comment . ' [end] -->' . LF
3275  . str_pad('', $indent + 1, "\t");
3276  return ‪$output;
3277  }
3278 
3288  public function ‪substring($content, $options)
3289  {
3290  $options = ‪GeneralUtility::intExplode(',', $options . ',');
3291  if ($options[1]) {
3292  return mb_substr($content, $options[0], $options[1], 'utf-8');
3293  }
3294  return mb_substr($content, $options[0], null, 'utf-8');
3295  }
3296 
3306  public function ‪crop($content, $options)
3307  {
3308  $options = explode('|', $options);
3309  $chars = (int)$options[0];
3310  $afterstring = trim($options[1] ?? '');
3311  $crop2space = trim($options[2] ?? '');
3312  if ($chars) {
3313  if (mb_strlen($content, 'utf-8') > abs($chars)) {
3314  $truncatePosition = false;
3315  if ($chars < 0) {
3316  $content = mb_substr($content, $chars, null, 'utf-8');
3317  if ($crop2space) {
3318  $truncatePosition = strpos($content, ' ');
3319  }
3320  $content = $truncatePosition ? $afterstring . substr($content, $truncatePosition) : $afterstring . $content;
3321  } else {
3322  $content = mb_substr($content, 0, $chars, 'utf-8');
3323  if ($crop2space) {
3324  $truncatePosition = strrpos($content, ' ');
3325  }
3326  $content = $truncatePosition ? substr($content, 0, $truncatePosition) . $afterstring : $content . $afterstring;
3327  }
3328  }
3329  }
3330  return $content;
3331  }
3332 
3346  public function ‪cropHTML($content, $options)
3347  {
3348  $options = explode('|', $options);
3349  $chars = (int)$options[0];
3350  $absChars = abs($chars);
3351  $replacementForEllipsis = trim($options[1] ?? '');
3352  $crop2space = trim($options[2] ?? '') === '1';
3353  // Split $content into an array(even items in the array are outside the tags, odd numbers are tag-blocks).
3354  $tags = 'a|abbr|address|area|article|aside|audio|b|bdi|bdo|blockquote|body|br|button|caption|cite|code|col|colgroup|data|datalist|dd|del|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|font|footer|form|h1|h2|h3|h4|h5|h6|header|hr|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|main|map|mark|meter|nav|object|ol|optgroup|option|output|p|param|pre|progress|q|rb|rp|rt|rtc|ruby|s|samp|section|select|small|source|span|strong|sub|sup|table|tbody|td|textarea|tfoot|th|thead|time|tr|track|u|ul|ut|var|video|wbr';
3355  $tagsRegEx = '
3356  (
3357  (?:
3358  <!--.*?--> # a comment
3359  |
3360  <canvas[^>]*>.*?</canvas> # a canvas tag
3361  |
3362  <script[^>]*>.*?</script> # a script tag
3363  |
3364  <noscript[^>]*>.*?</noscript> # a noscript tag
3365  |
3366  <template[^>]*>.*?</template> # a template tag
3367  )
3368  |
3369  </?(?:' . $tags . ')+ # opening tag (\'<tag\') or closing tag (\'</tag\')
3370  (?:
3371  (?:
3372  (?:
3373  \\s+\\w[\\w-]* # EITHER spaces, followed by attribute names
3374  (?:
3375  \\s*=?\\s* # equals
3376  (?>
3377  ".*?" # attribute values in double-quotes
3378  |
3379  \'.*?\' # attribute values in single-quotes
3380  |
3381  [^\'">\\s]+ # plain attribute values
3382  )
3383  )?
3384  )
3385  | # OR a single dash (for TYPO3 link tag)
3386  (?:
3387  \\s+-
3388  )
3389  )+\\s*
3390  | # OR only spaces
3391  \\s*
3392  )
3393  /?> # closing the tag with \'>\' or \'/>\'
3394  )';
3395  $splittedContent = preg_split('%' . $tagsRegEx . '%xs', $content, -1, PREG_SPLIT_DELIM_CAPTURE);
3396  if ($splittedContent === false) {
3397  $this->logger->debug('Unable to split "' . $content . '" into tags.');
3398  $splittedContent = [];
3399  }
3400  // Reverse array if we are cropping from right.
3401  if ($chars < 0) {
3402  $splittedContent = array_reverse($splittedContent);
3403  }
3404  // Crop the text (chars of tag-blocks are not counted).
3405  $strLen = 0;
3406  // This is the offset of the content item which was cropped.
3407  $croppedOffset = null;
3408  $countSplittedContent = count($splittedContent);
3409  // @todo $maxCroppingLength of 962 was determined by hand as the highest
3410  // value to not lead to internal error (Compilation failed: regular
3411  // expression is too large ). Still questionable if we really can
3412  // rely on a fixed value here, or better to say need to be understood
3413  // why the value has to be this value to avoid regular expression
3414  // compilation error.
3415  $maxCroppingLength = 962;
3416  for ($offset = 0; $offset < $countSplittedContent; $offset++) {
3417  if ($offset % 2 === 0) {
3418  $fullTempContent = $splittedContent[$offset];
3419  $thisStrLen = mb_strlen(html_entity_decode($fullTempContent, ENT_COMPAT, 'UTF-8'), 'utf-8');
3420  if ($strLen + $thisStrLen > $absChars) {
3421  $tempProcessedContent = '';
3422  $croppedOffset = $offset;
3423  $cropPosition = $absChars - $strLen;
3424  $cropEnd = ($cropPosition > $maxCroppingLength) ? $maxCroppingLength : $cropPosition;
3425  $processed = 0;
3426  // we need to crop in multiple steps to avoid regexp length compilation errors
3427  do {
3428  // remove already processed string part
3429  $tempContent = mb_substr($fullTempContent, mb_strlen($tempProcessedContent));
3430  $patternMatchEntityAsSingleChar = '(&[^&\\s;]{2,8};|.)';
3431  $cropRegEx = $chars < 0 ? '#' . $patternMatchEntityAsSingleChar . '{0,' . ($cropEnd + 1) . '}$#uis' : '#^' . $patternMatchEntityAsSingleChar . '{0,' . ($cropEnd + 1) . '}#uis';
3432  if (preg_match($cropRegEx, $tempContent, $croppedMatch)) {
3433  $tempContentPlusOneCharacter = $croppedMatch[0];
3434  } else {
3435  $tempContentPlusOneCharacter = false;
3436  }
3437  $cropRegEx = $chars < 0 ? '#' . $patternMatchEntityAsSingleChar . '{0,' . $cropEnd . '}$#uis' : '#^' . $patternMatchEntityAsSingleChar . '{0,' . $cropEnd . '}#uis';
3438  if (preg_match($cropRegEx, $tempContent, $croppedMatch)) {
3439  $tempContent = $croppedMatch[0];
3440  if ($crop2space && $tempContentPlusOneCharacter !== false) {
3441  $cropRegEx = $chars < 0 ? '#(?<=\\s)' . $patternMatchEntityAsSingleChar . '{0,' . $cropEnd . '}$#uis' : '#^' . $patternMatchEntityAsSingleChar . '{0,' . $cropEnd . '}(?=\\s)#uis';
3442  if (preg_match($cropRegEx, $tempContentPlusOneCharacter, $croppedMatch)) {
3443  $tempContent = $croppedMatch[0];
3444  }
3445  }
3446  }
3447  $tempProcessedContent .= $tempContent;
3448  $processed += $cropEnd;
3449  $cropEnd = ($processed + $maxCroppingLength > $cropPosition ? ($cropPosition - $processed) : $maxCroppingLength);
3450  } while ($cropEnd > 0 && $cropEnd < $cropPosition);
3451  $splittedContent[$offset] = $tempProcessedContent;
3452  break;
3453  }
3454  $strLen += $thisStrLen;
3455  }
3456  }
3457  // Close cropped tags.
3458  $closingTags = [];
3459  if ($croppedOffset !== null) {
3460  $openingTagRegEx = '#^<(\\w+)(?:\\s|>)#';
3461  $closingTagRegEx = '#^</(\\w+)(?:\\s|>)#';
3462  for ($offset = $croppedOffset - 1; $offset >= 0; $offset = $offset - 2) {
3463  if (substr($splittedContent[$offset], -2) === '/>') {
3464  // Ignore empty element tags (e.g. <br />).
3465  continue;
3466  }
3467  preg_match($chars < 0 ? $closingTagRegEx : $openingTagRegEx, $splittedContent[$offset], $matches);
3468  $tagName = $matches[1] ?? null;
3469  if ($tagName !== null) {
3470  // Seek for the closing (or opening) tag.
3471  $countSplittedContent = count($splittedContent);
3472  for ($seekingOffset = $offset + 2; $seekingOffset < $countSplittedContent; $seekingOffset = $seekingOffset + 2) {
3473  preg_match($chars < 0 ? $openingTagRegEx : $closingTagRegEx, $splittedContent[$seekingOffset], $matches);
3474  $seekingTagName = $matches[1] ?? null;
3475  if ($tagName === $seekingTagName) {
3476  // We found a matching tag.
3477  // Add closing tag only if it occurs after the cropped content item.
3478  if ($seekingOffset > $croppedOffset) {
3479  $closingTags[] = $splittedContent[$seekingOffset];
3480  }
3481  break;
3482  }
3483  }
3484  }
3485  }
3486  // Drop the cropped items of the content array. The $closingTags will be added later on again.
3487  array_splice($splittedContent, $croppedOffset + 1);
3488  }
3489  $splittedContent = array_merge($splittedContent, [
3490  $croppedOffset !== null ? $replacementForEllipsis : ''
3491  ], $closingTags);
3492  // Reverse array once again if we are cropping from the end.
3493  if ($chars < 0) {
3494  $splittedContent = array_reverse($splittedContent);
3495  }
3496  return implode('', $splittedContent);
3497  }
3498 
3506  public function ‪calc($val)
3507  {
3508  $parts = GeneralUtility::splitCalc($val, '+-*/');
3509  $value = 0;
3510  foreach ($parts as $part) {
3511  $theVal = $part[1];
3512  $sign = $part[0];
3513  if ((string)(int)$theVal === (string)$theVal) {
3514  $theVal = (int)$theVal;
3515  } else {
3516  $theVal = 0;
3517  }
3518  if ($sign === '-') {
3519  $value -= $theVal;
3520  }
3521  if ($sign === '+') {
3522  $value += $theVal;
3523  }
3524  if ($sign === '/') {
3525  if ((int)$theVal) {
3526  $value /= (int)$theVal;
3527  }
3528  }
3529  if ($sign === '*') {
3530  $value *= $theVal;
3531  }
3532  }
3533  return $value;
3534  }
3535 
3548  public function ‪splitObj($value, $conf)
3549  {
3550  $conf['token'] = isset($conf['token.']) ? $this->‪stdWrap($conf['token'], $conf['token.']) : $conf['token'];
3551  if ($conf['token'] === '') {
3552  return $value;
3553  }
3554  $valArr = explode($conf['token'], $value);
3555 
3556  // return value directly by returnKey. No further processing
3557  if (!empty($valArr) && (‪MathUtility::canBeInterpretedAsInteger($conf['returnKey'] ?? null) || ($conf['returnKey.'] ?? false))
3558  ) {
3559  $key = isset($conf['returnKey.']) ? (int)$this->‪stdWrap($conf['returnKey'], $conf['returnKey.']) : (int)$conf['returnKey'];
3560  return $valArr[$key] ?? '';
3561  }
3562 
3563  // return the amount of elements. No further processing
3564  if (!empty($valArr) && ($conf['returnCount'] || $conf['returnCount.'])) {
3565  $returnCount = isset($conf['returnCount.']) ? (bool)$this->‪stdWrap($conf['returnCount'], $conf['returnCount.']) : (bool)$conf['returnCount'];
3566  return $returnCount ? count($valArr) : 0;
3567  }
3568 
3569  // calculate splitCount
3570  $splitCount = count($valArr);
3571  $max = isset($conf['max.']) ? (int)$this->‪stdWrap($conf['max'], $conf['max.']) : (int)$conf['max'];
3572  if ($max && $splitCount > $max) {
3573  $splitCount = $max;
3574  }
3575  $min = isset($conf['min.']) ? (int)$this->‪stdWrap($conf['min'], $conf['min.']) : (int)$conf['min'];
3576  if ($min && $splitCount < $min) {
3577  $splitCount = $min;
3578  }
3579  $wrap = isset($conf['wrap.']) ? (string)$this->‪stdWrap($conf['wrap'], $conf['wrap.']) : (string)$conf['wrap'];
3580  $cObjNumSplitConf = isset($conf['cObjNum.']) ? (string)$this->‪stdWrap($conf['cObjNum'], $conf['cObjNum.']) : (string)$conf['cObjNum'];
3581  $splitArr = [];
3582  if ($wrap !== '' || $cObjNumSplitConf !== '') {
3583  $splitArr['wrap'] = $wrap;
3584  $splitArr['cObjNum'] = $cObjNumSplitConf;
3585  $splitArr = GeneralUtility::makeInstance(TypoScriptService::class)
3586  ->explodeConfigurationForOptionSplit($splitArr, $splitCount);
3587  }
3588  $content = '';
3589  for ($a = 0; $a < $splitCount; $a++) {
3590  $this->‪getTypoScriptFrontendController()->register['SPLIT_COUNT'] = $a;
3591  $value = '' . $valArr[$a];
3592  $this->data[‪$this->currentValKey] = $value;
3593  if ($splitArr[$a]['cObjNum']) {
3594  $objName = (int)$splitArr[$a]['cObjNum'];
3595  $value = isset($conf[$objName . '.'])
3596  ? $this->‪stdWrap($this->‪cObjGet($conf[$objName . '.'], $objName . '.'), $conf[$objName . '.'])
3597  : $this->‪cObjGet($conf[$objName . '.'], $objName . '.');
3598  }
3599  $wrap = isset($splitArr[$a]['wrap.']) ? $this->‪stdWrap($splitArr[$a]['wrap'], $splitArr[$a]['wrap.']) : $splitArr[$a]['wrap'];
3600  if ($wrap) {
3601  $value = $this->‪wrap($value, $wrap);
3602  }
3603  $content .= $value;
3604  }
3605  return $content;
3606  }
3607 
3615  protected function ‪replacement($content, array $configuration)
3616  {
3617  // Sorts actions in configuration by numeric index
3618  ksort($configuration, SORT_NUMERIC);
3619  foreach ($configuration as $index => $action) {
3620  // Checks whether we have a valid action and a numeric key ending with a dot ("10.")
3621  if (is_array($action) && substr($index, -1) === '.' && ‪MathUtility::canBeInterpretedAsInteger(substr($index, 0, -1))) {
3622  $content = $this->‪replacementSingle($content, $action);
3623  }
3624  }
3625  return $content;
3626  }
3627 
3635  protected function ‪replacementSingle($content, array $configuration)
3636  {
3637  if ((isset($configuration['search']) || isset($configuration['search.'])) && (isset($configuration['replace']) || isset($configuration['replace.']))) {
3638  // Gets the strings
3639  $search = isset($configuration['search.']) ? $this->‪stdWrap($configuration['search'], $configuration['search.']) : $configuration['search'];
3640  $replace = isset($configuration['replace.'])
3641  ? $this->‪stdWrap($configuration['replace'] ?? null, $configuration['replace.'])
3642  : $configuration['replace'] ?? null;
3643  $useRegularExpression = false;
3644  // Determines whether regular expression shall be used
3645  if (isset($configuration['useRegExp'])
3646  || (isset($configuration['useRegExp.']) && $configuration['useRegExp.'])
3647  ) {
3648  $useRegularExpression = isset($configuration['useRegExp.']) ? (bool)$this->‪stdWrap($configuration['useRegExp'], $configuration['useRegExp.']) : (bool)$configuration['useRegExp'];
3649  }
3650  $useOptionSplitReplace = false;
3651  // Determines whether replace-pattern uses option-split
3652  if (isset($configuration['useOptionSplitReplace']) || isset($configuration['useOptionSplitReplace.'])) {
3653  $useOptionSplitReplace = isset($configuration['useOptionSplitReplace.']) ? (bool)$this->‪stdWrap($configuration['useOptionSplitReplace'], $configuration['useOptionSplitReplace.']) : (bool)$configuration['useOptionSplitReplace'];
3654  }
3655 
3656  // Performs a replacement by preg_replace()
3657  if ($useRegularExpression) {
3658  // Get separator-character which precedes the string and separates search-string from the modifiers
3659  $separator = $search[0];
3660  $startModifiers = strrpos($search, $separator);
3661  if ($separator !== false && $startModifiers > 0) {
3662  $modifiers = substr($search, $startModifiers + 1);
3663  // remove "e" (eval-modifier), which would otherwise allow to run arbitrary PHP-code
3664  $modifiers = str_replace('e', '', $modifiers);
3665  $search = substr($search, 0, $startModifiers + 1) . $modifiers;
3666  }
3667  if ($useOptionSplitReplace) {
3668  // init for replacement
3669  $splitCount = preg_match_all($search, $content, $matches);
3670  $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
3671  $replaceArray = $typoScriptService->explodeConfigurationForOptionSplit([$replace], $splitCount);
3672  $replaceCount = 0;
3673 
3674  $replaceCallback = function ($match) use ($replaceArray, $search, &$replaceCount) {
3675  $replaceCount++;
3676  return preg_replace($search, $replaceArray[$replaceCount - 1][0], $match[0]);
3677  };
3678  $content = preg_replace_callback($search, $replaceCallback, $content);
3679  } else {
3680  $content = preg_replace($search, $replace, $content);
3681  }
3682  } elseif ($useOptionSplitReplace) {
3683  // turn search-string into a preg-pattern
3684  $searchPreg = '#' . preg_quote($search, '#') . '#';
3685 
3686  // init for replacement
3687  $splitCount = preg_match_all($searchPreg, $content, $matches);
3688  $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
3689  $replaceArray = $typoScriptService->explodeConfigurationForOptionSplit([$replace], $splitCount);
3690  $replaceCount = 0;
3691 
3692  $replaceCallback = function () use ($replaceArray, &$replaceCount) {
3693  $replaceCount++;
3694  return $replaceArray[$replaceCount - 1][0];
3695  };
3696  $content = preg_replace_callback($searchPreg, $replaceCallback, $content);
3697  } else {
3698  $content = str_replace($search, $replace, $content);
3699  }
3700  }
3701  return $content;
3702  }
3703 
3712  protected function ‪round($content, array $conf = [])
3713  {
3714  $decimals = isset($conf['decimals.'])
3715  ? $this->‪stdWrap($conf['decimals'] ?? '', $conf['decimals.'])
3716  : ($conf['decimals'] ?? null);
3717  $type = isset($conf['roundType.'])
3718  ? $this->‪stdWrap($conf['roundType'] ?? '', $conf['roundType.'])
3719  : ($conf['roundType'] ?? null);
3720  $floatVal = (float)$content;
3721  switch ($type) {
3722  case 'ceil':
3723  $content = ceil($floatVal);
3724  break;
3725  case 'floor':
3726  $content = floor($floatVal);
3727  break;
3728  case 'round':
3729 
3730  default:
3731  $content = ‪round($floatVal, (int)$decimals);
3732  }
3733  return $content;
3734  }
3735 
3744  public function ‪numberFormat($content, $conf)
3745  {
3746  $decimals = isset($conf['decimals.'])
3747  ? (int)$this->‪stdWrap($conf['decimals'] ?? '', $conf['decimals.'])
3748  : (int)($conf['decimals'] ?? 0);
3749  $dec_point = isset($conf['dec_point.'])
3750  ? $this->‪stdWrap($conf['dec_point'] ?? '', $conf['dec_point.'])
3751  : ($conf['dec_point'] ?? null);
3752  $thousands_sep = isset($conf['thousands_sep.'])
3753  ? $this->‪stdWrap($conf['thousands_sep'] ?? '', $conf['thousands_sep.'])
3754  : ($conf['thousands_sep'] ?? null);
3755  return number_format((float)$content, $decimals, $dec_point, $thousands_sep);
3756  }
3757 
3777  public function ‪parseFunc($theValue, $conf, $ref = '')
3778  {
3779  // Fetch / merge reference, if any
3780  if ($ref) {
3781  $temp_conf = [
3782  'parseFunc' => $ref,
3783  'parseFunc.' => $conf
3784  ];
3785  $temp_conf = $this->‪mergeTSRef($temp_conf, 'parseFunc');
3786  $conf = $temp_conf['parseFunc.'];
3787  }
3788  // early return, no processing in case no configuration is given
3789  if (empty($conf)) {
3790  // @deprecated Invoking ContentObjectRenderer::parseFunc without any configuration will trigger an exception in TYPO3 v12.0
3791  trigger_error('Invoking ContentObjectRenderer::parseFunc without any configuration will trigger an exception in TYPO3 v12.0', E_USER_DEPRECATED);
3792  return $theValue;
3793  }
3794  // Handle HTML sanitizer invocation
3795  if (!isset($conf['htmlSanitize'])) {
3796  // @deprecated Property htmlSanitize was not defined, but will be mandatory in TYPO3 v12.0
3797  trigger_error('Property htmlSanitize was not defined, but will be mandatory in TYPO3 v12.0', E_USER_DEPRECATED);
3798  $features = GeneralUtility::makeInstance(Features::class);
3799  $conf['htmlSanitize'] = $features->isFeatureEnabled('security.frontend.htmlSanitizeParseFuncDefault');
3800  }
3801  $conf['htmlSanitize'] = (bool)$conf['htmlSanitize'];
3802 
3803  // Process:
3804  if ((string)($conf['externalBlocks'] ?? '') === '') {
3805  $result = $this->‪_parseFunc($theValue, $conf);
3806  if ($conf['htmlSanitize']) {
3807  $result = $this->‪stdWrap_htmlSanitize($result, $conf['htmlSanitize.'] ?? []);
3808  }
3809  return $result;
3810  }
3811  $tags = strtolower(implode(',', ‪GeneralUtility::trimExplode(',', $conf['externalBlocks'])));
3812  $htmlParser = GeneralUtility::makeInstance(HtmlParser::class);
3813  $parts = $htmlParser->splitIntoBlock($tags, $theValue);
3814  foreach ($parts as $k => $v) {
3815  if ($k % 2) {
3816  // font:
3817  $tagName = strtolower($htmlParser->getFirstTagName($v));
3818  $cfg = $conf['externalBlocks.'][$tagName . '.'];
3819  if ($cfg['stripNLprev'] || $cfg['stripNL']) {
3820  $parts[$k - 1] = preg_replace('/' . CR . '?' . LF . '[ ]*$/', '', $parts[$k - 1]);
3821  }
3822  if ($cfg['stripNLnext'] || $cfg['stripNL']) {
3823  $parts[$k + 1] = preg_replace('/^[ ]*' . CR . '?' . LF . '/', '', $parts[$k + 1]);
3824  }
3825  }
3826  }
3827  foreach ($parts as $k => $v) {
3828  if ($k % 2) {
3829  $tag = $htmlParser->getFirstTag($v);
3830  $tagName = strtolower($htmlParser->getFirstTagName($v));
3831  $cfg = $conf['externalBlocks.'][$tagName . '.'];
3832  if ($cfg['callRecursive']) {
3833  $parts[$k] = $this->‪parseFunc($htmlParser->removeFirstAndLastTag($v), $conf);
3834  if (!$cfg['callRecursive.']['dontWrapSelf']) {
3835  if ($cfg['callRecursive.']['alternativeWrap']) {
3836  $parts[$k] = $this->‪wrap($parts[$k], $cfg['callRecursive.']['alternativeWrap']);
3837  } else {
3838  if (is_array($cfg['callRecursive.']['tagStdWrap.'])) {
3839  $tag = $this->‪stdWrap($tag, $cfg['callRecursive.']['tagStdWrap.']);
3840  }
3841  $parts[$k] = $tag . $parts[$k] . '</' . $tagName . '>';
3842  }
3843  }
3844  } elseif ($cfg['HTMLtableCells']) {
3845  $rowParts = $htmlParser->splitIntoBlock('tr', $parts[$k]);
3846  foreach ($rowParts as $kk => $vv) {
3847  if ($kk % 2) {
3848  $colParts = $htmlParser->splitIntoBlock('td,th', $vv);
3849  $cc = 0;
3850  foreach ($colParts as $kkk => $vvv) {
3851  if ($kkk % 2) {
3852  $cc++;
3853  $tag = $htmlParser->getFirstTag($vvv);
3854  $tagName = strtolower($htmlParser->getFirstTagName($vvv));
3855  $colParts[$kkk] = $htmlParser->removeFirstAndLastTag($vvv);
3856  if ($cfg['HTMLtableCells.'][$cc . '.']['callRecursive'] || !isset($cfg['HTMLtableCells.'][$cc . '.']['callRecursive']) && $cfg['HTMLtableCells.']['default.']['callRecursive']) {
3857  if ($cfg['HTMLtableCells.']['addChr10BetweenParagraphs']) {
3858  $colParts[$kkk] = str_replace('</p><p>', '</p>' . LF . '<p>', $colParts[$kkk]);
3859  }
3860  $colParts[$kkk] = $this->‪parseFunc($colParts[$kkk], $conf);
3861  }
3862  $tagStdWrap = is_array($cfg['HTMLtableCells.'][$cc . '.']['tagStdWrap.'])
3863  ? $cfg['HTMLtableCells.'][$cc . '.']['tagStdWrap.']
3864  : $cfg['HTMLtableCells.']['default.']['tagStdWrap.'];
3865  if (is_array($tagStdWrap)) {
3866  $tag = $this->‪stdWrap($tag, $tagStdWrap);
3867  }
3868  $stdWrap = is_array($cfg['HTMLtableCells.'][$cc . '.']['stdWrap.'])
3869  ? $cfg['HTMLtableCells.'][$cc . '.']['stdWrap.']
3870  : $cfg['HTMLtableCells.']['default.']['stdWrap.'];
3871  if (is_array($stdWrap)) {
3872  $colParts[$kkk] = $this->‪stdWrap($colParts[$kkk], $stdWrap);
3873  }
3874  $colParts[$kkk] = $tag . $colParts[$kkk] . '</' . $tagName . '>';
3875  }
3876  }
3877  $rowParts[$kk] = implode('', $colParts);
3878  }
3879  }
3880  $parts[$k] = implode('', $rowParts);
3881  }
3882  if (is_array($cfg['stdWrap.'])) {
3883  $parts[$k] = $this->‪stdWrap($parts[$k], $cfg['stdWrap.']);
3884  }
3885  } else {
3886  $parts[$k] = $this->‪_parseFunc($parts[$k], $conf);
3887  }
3888  }
3889  $result = implode('', $parts);
3890  if ($conf['htmlSanitize']) {
3891  $result = $this->‪stdWrap_htmlSanitize($result, $conf['htmlSanitize.'] ?? []);
3892  }
3893  return $result;
3894  }
3895 
3905  public function ‪_parseFunc($theValue, $conf)
3906  {
3907  if (!empty($conf['if.']) && !$this->‪checkIf($conf['if.'])) {
3908  return $theValue;
3909  }
3910  // Indicates that the data is from within a tag.
3911  $inside = false;
3912  // Pointer to the total string position
3913  $pointer = 0;
3914  // Loaded with the current typo-tag if any.
3915  $currentTag = null;
3916  $stripNL = 0;
3917  $contentAccum = [];
3918  $contentAccumP = 0;
3919  $allowTags = strtolower(str_replace(' ', '', $conf['allowTags'] ?? ''));
3920  $denyTags = strtolower(str_replace(' ', '', $conf['denyTags'] ?? ''));
3921  $totalLen = strlen($theValue);
3922  do {
3923  if (!$inside) {
3924  if ($currentTag === null) {
3925  // These operations should only be performed on code outside the typotags...
3926  // data: this checks that we enter tags ONLY if the first char in the tag is alphanumeric OR '/'
3927  $len_p = 0;
3928  $c = 100;
3929  do {
3930  $len = strcspn(substr($theValue, $pointer + $len_p), '<');
3931  $len_p += $len + 1;
3932  $endChar = ord(strtolower(substr($theValue, $pointer + $len_p, 1)));
3933  $c--;
3934  } while ($c > 0 && $endChar && ($endChar < 97 || $endChar > 122) && $endChar != 47);
3935  $len = $len_p - 1;
3936  } else {
3937  $len = $this->‪getContentLengthOfCurrentTag($theValue, $pointer, (string)$currentTag[0]);
3938  }
3939  // $data is the content until the next <tag-start or end is detected.
3940  // In case of a currentTag set, this would mean all data between the start- and end-tags
3941  ‪$data = substr($theValue, $pointer, $len);
3942  if (‪$data !== false) {
3943  if ($stripNL) {
3944  // If the previous tag was set to strip NewLines in the beginning of the next data-chunk.
3945  ‪$data = preg_replace('/^[ ]*' . CR . '?' . LF . '/', '', ‪$data);
3946  if (‪$data === null) {
3947  $this->logger->debug('Stripping new lines failed for "' . ‪$data . '"');
3948  ‪$data = '';
3949  }
3950  }
3951  // These operations should only be performed on code outside the tags...
3952  if (!is_array($currentTag)) {
3953  // Constants
3954  $tsfe = $this->‪getTypoScriptFrontendController();
3955  $tmpConstants = $tsfe->tmpl->setup['constants.'] ?? null;
3956  if (!empty($conf['constants']) && is_array($tmpConstants)) {
3957  foreach ($tmpConstants as $key => $val) {
3958  if (is_string($val)) {
3959  ‪$data = str_replace('###' . $key . '###', $val, ‪$data);
3960  }
3961  }
3962  }
3963  // Short
3964  if (isset($conf['short.']) && is_array($conf['short.'])) {
3965  $shortWords = $conf['short.'];
3966  krsort($shortWords);
3967  foreach ($shortWords as $key => $val) {
3968  if (is_string($val)) {
3969  ‪$data = str_replace($key, $val, ‪$data);
3970  }
3971  }
3972  }
3973  // stdWrap
3974  if (isset($conf['plainTextStdWrap.']) && is_array($conf['plainTextStdWrap.'])) {
3975  ‪$data = $this->‪stdWrap($data, $conf['plainTextStdWrap.']);
3976  }
3977  // userFunc
3978  if ($conf['userFunc'] ?? false) {
3979  ‪$data = $this->‪callUserFunction($conf['userFunc'], $conf['userFunc.'] ?? [], ‪$data);
3980  }
3981  // Makelinks: (Before search-words as we need the links to be generated when searchwords go on...!)
3982  if ($conf['makelinks'] ?? false) {
3983  ‪$data = $this->‪http_makelinks($data, $conf['makelinks.']['http.']);
3984  ‪$data = $this->‪mailto_makelinks($data, $conf['makelinks.']['mailto.'] ?? []);
3985  }
3986  // Search Words:
3987  if ($tsfe->no_cache && $conf['sword'] && is_array($tsfe->sWordList) && $tsfe->sWordRegEx) {
3988  $newstring = '';
3989  do {
3990  $pregSplitMode = 'i';
3991  if (isset($tsfe->config['config']['sword_noMixedCase']) && !empty($tsfe->config['config']['sword_noMixedCase'])) {
3992  $pregSplitMode = '';
3993  }
3994  $pieces = preg_split('/' . $tsfe->sWordRegEx . '/' . $pregSplitMode, ‪$data, 2);
3995  $newstring .= $pieces[0];
3996  $match_len = strlen(‪$data) - (strlen($pieces[0]) + strlen($pieces[1]));
3997  $inTag = false;
3998  if (strpos($pieces[0], '<') !== false || strpos($pieces[0], '>') !== false) {
3999  // Returns TRUE, if a '<' is closer to the string-end than '>'.
4000  // This is the case if we're INSIDE a tag (that could have been
4001  // made by makelinks...) and we must secure, that the inside of a tag is
4002  // not marked up.
4003  $inTag = strrpos($pieces[0], '<') > strrpos($pieces[0], '>');
4004  }
4005  // The searchword:
4006  $match = substr(‪$data, strlen($pieces[0]), $match_len);
4007  if (trim($match) && strlen($match) > 1 && !$inTag) {
4008  $match = $this->‪wrap($match, $conf['sword']);
4009  }
4010  // Concatenate the Search Word again.
4011  $newstring .= $match;
4012  ‪$data = $pieces[1];
4013  } while ($pieces[1]);
4014  ‪$data = $newstring;
4015  }
4016  }
4017  // Search for tags to process in current data and
4018  // call this method recursively if found
4019  if (strpos(‪$data, '<') !== false && isset($conf['tags.']) && is_array($conf['tags.'])) {
4020  foreach ($conf['tags.'] as $tag => $tagConfig) {
4021  // only match tag `a` in `<a href"...">` but not in `<abbr>`
4022  if (preg_match('#<' . $tag . '[\s/>]#', ‪$data)) {
4023  ‪$data = $this->‪_parseFunc($data, $conf);
4024  break;
4025  }
4026  }
4027  }
4028  $contentAccum[$contentAccumP] = isset($contentAccum[$contentAccumP])
4029  ? $contentAccum[$contentAccumP] . ‪$data
4030  : ‪$data;
4031  }
4032  $inside = true;
4033  } else {
4034  // tags
4035  $len = strcspn(substr($theValue, $pointer), '>') + 1;
4036  ‪$data = substr($theValue, $pointer, $len);
4037  if (‪StringUtility::endsWith(‪$data, '/>') && strpos(‪$data, '<link ') !== 0) {
4038  $tagContent = substr(‪$data, 1, -2);
4039  } else {
4040  $tagContent = substr(‪$data, 1, -1);
4041  }
4042  $tag = explode(' ', trim($tagContent), 2);
4043  $tag[0] = strtolower($tag[0]);
4044  // end tag like </li>
4045  if ($tag[0][0] === '/') {
4046  $tag[0] = substr($tag[0], 1);
4047  $tag['out'] = 1;
4048  }
4049  if ($conf['tags.'][$tag[0]] ?? false) {
4050  $treated = false;
4051  $stripNL = false;
4052  // in-tag
4053  if (!$currentTag && (!isset($tag['out']) || !$tag['out'])) {
4054  // $currentTag (array!) is the tag we are currently processing
4055  $currentTag = $tag;
4056  $contentAccumP++;
4057  $treated = true;
4058  // in-out-tag: img and other empty tags
4059  if (preg_match('/^(area|base|br|col|hr|img|input|meta|param)$/i', (string)$tag[0])) {
4060  $tag['out'] = 1;
4061  }
4062  }
4063  // out-tag
4064  if ($currentTag[0] === $tag[0] && isset($tag['out']) && $tag['out']) {
4065  $theName = $conf['tags.'][$tag[0]];
4066  $theConf = $conf['tags.'][$tag[0] . '.'];
4067  // This flag indicates, that NL- (13-10-chars) should be stripped first and last.
4068  $stripNL = (bool)($theConf['stripNL'] ?? false);
4069  // This flag indicates, that this TypoTag section should NOT be included in the nonTypoTag content.
4070  $breakOut = (bool)($theConf['breakoutTypoTagContent'] ?? false);
4071  $this->parameters = [];
4072  if (isset($currentTag[1])) {
4073  // decode HTML entities in attributes, since they're processed
4074  $params = GeneralUtility::get_tag_attributes((string)$currentTag[1], true);
4075  if (is_array($params)) {
4076  foreach ($params as $option => $val) {
4077  // contains non-encoded values
4078  $this->parameters[strtolower($option)] = $val;
4079  }
4080  }
4081  $this->parameters['allParams'] = trim((string)$currentTag[1]);
4082  }
4083  // Removes NL in the beginning and end of the tag-content AND at the end of the currentTagBuffer.
4084  // $stripNL depends on the configuration of the current tag
4085  if ($stripNL) {
4086  $contentAccum[$contentAccumP - 1] = preg_replace('/' . CR . '?' . LF . '[ ]*$/', '', $contentAccum[$contentAccumP - 1]);
4087  $contentAccum[$contentAccumP] = preg_replace('/^[ ]*' . CR . '?' . LF . '/', '', $contentAccum[$contentAccumP]);
4088  $contentAccum[$contentAccumP] = preg_replace('/' . CR . '?' . LF . '[ ]*$/', '', $contentAccum[$contentAccumP]);
4089  }
4090  $this->data[‪$this->currentValKey] = $contentAccum[$contentAccumP];
4091  $newInput = $this->‪cObjGetSingle($theName, $theConf, '/parseFunc/.tags.' . $tag[0]);
4092  // fetch the content object
4093  $contentAccum[$contentAccumP] = $newInput;
4094  $contentAccumP++;
4095  // If the TypoTag section
4096  if (!$breakOut) {
4097  if (!isset($contentAccum[$contentAccumP - 2])) {
4098  $contentAccum[$contentAccumP - 2] = '';
4099  }
4100  $contentAccum[$contentAccumP - 2] .= ($contentAccum[$contentAccumP - 1] ?? '') . ($contentAccum[$contentAccumP] ?? '');
4101  unset($contentAccum[$contentAccumP]);
4102  unset($contentAccum[$contentAccumP - 1]);
4103  $contentAccumP -= 2;
4104  }
4105  $currentTag = null;
4106  $treated = true;
4107  }
4108  // other tags
4109  if (!$treated) {
4110  $contentAccum[$contentAccumP] .= ‪$data;
4111  }
4112  } else {
4113  // If a tag was not a typo tag, then it is just added to the content
4114  $stripNL = false;
4115  if (GeneralUtility::inList($allowTags, (string)$tag[0]) ||
4116  ($denyTags !== '*' && !GeneralUtility::inList($denyTags, (string)$tag[0]))) {
4117  $contentAccum[$contentAccumP] = isset($contentAccum[$contentAccumP])
4118  ? $contentAccum[$contentAccumP] . ‪$data
4119  : ‪$data;
4120  } else {
4121  $contentAccum[$contentAccumP] = isset($contentAccum[$contentAccumP])
4122  ? $contentAccum[$contentAccumP] . htmlspecialchars(‪$data)
4123  : htmlspecialchars(‪$data);
4124  }
4125  }
4126  $inside = false;
4127  }
4128  $pointer += $len;
4129  } while ($pointer < $totalLen);
4130  // Parsing nonTypoTag content (all even keys):
4131  reset($contentAccum);
4132  $contentAccumCount = count($contentAccum);
4133  for ($a = 0; $a < $contentAccumCount; $a++) {
4134  if ($a % 2 != 1) {
4135  // stdWrap
4136  if (isset($conf['nonTypoTagStdWrap.']) && is_array($conf['nonTypoTagStdWrap.'])) {
4137  $contentAccum[$a] = $this->‪stdWrap((string)($contentAccum[$a] ?? ''), $conf['nonTypoTagStdWrap.']);
4138  }
4139  // userFunc
4140  if (!empty($conf['nonTypoTagUserFunc'])) {
4141  $contentAccum[$a] = $this->‪callUserFunction($conf['nonTypoTagUserFunc'], $conf['nonTypoTagUserFunc.'] ?? [], (string)($contentAccum[$a] ?? ''));
4142  }
4143  }
4144  }
4145  return implode('', $contentAccum);
4146  }
4147 
4156  public function ‪encaps_lineSplit($theValue, $conf)
4157  {
4158  if ((string)$theValue === '') {
4159  return '';
4160  }
4161  $lParts = explode(LF, $theValue);
4162 
4163  // When the last element is an empty linebreak we need to remove it, otherwise we will have a duplicate empty line.
4164  $lastPartIndex = count($lParts) - 1;
4165  if ($lParts[$lastPartIndex] === '' && trim($lParts[$lastPartIndex - 1], CR) === '') {
4166  array_pop($lParts);
4167  }
4168 
4169  $encapTags = ‪GeneralUtility::trimExplode(',', strtolower($conf['encapsTagList']), true);
4170  $nonWrappedTag = $conf['nonWrappedTag'];
4171  $defaultAlign = isset($conf['defaultAlign.'])
4172  ? trim($this->‪stdWrap($conf['defaultAlign'] ?? '', $conf['defaultAlign.']))
4173  : trim($conf['defaultAlign'] ?? '');
4174 
4175  $str_content = '';
4176  foreach ($lParts as $k => $l) {
4177  $sameBeginEnd = 0;
4178  $emptyTag = false;
4179  $l = trim($l);
4180  $attrib = [];
4181  $nonWrapped = false;
4182  $tagName = '';
4183  if (isset($l[0]) && $l[0] === '<' && substr($l, -1) === '>') {
4184  $fwParts = explode('>', substr($l, 1), 2);
4185  [$tagName] = explode(' ', $fwParts[0], 2);
4186  if (!$fwParts[1]) {
4187  if (substr($tagName, -1) === '/') {
4188  $tagName = substr($tagName, 0, -1);
4189  }
4190  if (substr($fwParts[0], -1) === '/') {
4191  $sameBeginEnd = 1;
4192  $emptyTag = true;
4193  // decode HTML entities, they're encoded later again
4194  $attrib = GeneralUtility::get_tag_attributes('<' . substr($fwParts[0], 0, -1) . '>', true);
4195  }
4196  } else {
4197  $backParts = ‪GeneralUtility::revExplode('<', substr($fwParts[1], 0, -1), 2);
4198  // decode HTML entities, they're encoded later again
4199  $attrib = GeneralUtility::get_tag_attributes('<' . $fwParts[0] . '>', true);
4200  $str_content = $backParts[0];
4201  $sameBeginEnd = substr(strtolower($backParts[1]), 1, strlen($tagName)) === strtolower($tagName);
4202  }
4203  }
4204  if ($sameBeginEnd && in_array(strtolower($tagName), $encapTags)) {
4205  $uTagName = strtoupper($tagName);
4206  $uTagName = strtoupper($conf['remapTag.'][$uTagName] ?? $uTagName);
4207  } else {
4208  $uTagName = strtoupper($nonWrappedTag);
4209  // The line will be wrapped: $uTagName should not be an empty tag
4210  $emptyTag = false;
4211  $str_content = $lParts[$k];
4212  $nonWrapped = true;
4213  $attrib = [];
4214  }
4215  // Wrapping all inner-content:
4216  if (is_array($conf['innerStdWrap_all.'])) {
4217  $str_content = $this->‪stdWrap($str_content, $conf['innerStdWrap_all.']);
4218  }
4219  if ($uTagName) {
4220  // Setting common attributes
4221  if (isset($conf['addAttributes.'][$uTagName . '.']) && is_array($conf['addAttributes.'][$uTagName . '.'])) {
4222  foreach ($conf['addAttributes.'][$uTagName . '.'] as $kk => $vv) {
4223  if (!is_array($vv)) {
4224  if ((string)$conf['addAttributes.'][$uTagName . '.'][$kk . '.']['setOnly'] === 'blank') {
4225  if ((string)($attrib[$kk] ?? '') === '') {
4226  $attrib[$kk] = $vv;
4227  }
4228  } elseif ((string)$conf['addAttributes.'][$uTagName . '.'][$kk . '.']['setOnly'] === 'exists') {
4229  if (!isset($attrib[$kk])) {
4230  $attrib[$kk] = $vv;
4231  }
4232  } else {
4233  $attrib[$kk] = $vv;
4234  }
4235  }
4236  }
4237  }
4238  // Wrapping all inner-content:
4239  if (isset($conf['encapsLinesStdWrap.'][$uTagName . '.']) && is_array($conf['encapsLinesStdWrap.'][$uTagName . '.'])) {
4240  $str_content = $this->‪stdWrap($str_content, $conf['encapsLinesStdWrap.'][$uTagName . '.']);
4241  }
4242  // Default align
4243  if ((!isset($attrib['align']) || !$attrib['align']) && $defaultAlign) {
4244  $attrib['align'] = $defaultAlign;
4245  }
4246  // implode (insecure) attributes, that's why `htmlspecialchars` is used here
4247  $params = GeneralUtility::implodeAttributes($attrib, true);
4248  if (!isset($conf['removeWrapping']) || !$conf['removeWrapping'] || ($emptyTag && $conf['removeWrapping.']['keepSingleTag'])) {
4249  $selfClosingTagList = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
4250  if ($emptyTag && in_array(strtolower($uTagName), $selfClosingTagList, true)) {
4251  $str_content = '<' . strtolower($uTagName) . (trim($params) ? ' ' . trim($params) : '') . ' />';
4252  } else {
4253  $str_content = '<' . strtolower($uTagName) . (trim($params) ? ' ' . trim($params) : '') . '>' . $str_content . '</' . strtolower($uTagName) . '>';
4254  }
4255  }
4256  }
4257  if ($nonWrapped && isset($conf['wrapNonWrappedLines']) && $conf['wrapNonWrappedLines']) {
4258  $str_content = $this->‪wrap($str_content, $conf['wrapNonWrappedLines']);
4259  }
4260  $lParts[$k] = $str_content;
4261  }
4262  return implode(LF, $lParts);
4263  }
4264 
4275  public function ‪http_makelinks(‪$data, $conf)
4276  {
4277  $parts = [];
4278  $aTagParams = $this->‪getATagParams($conf);
4279  $textstr = '';
4280  foreach (['http://', 'https://'] as $scheme) {
4281  $textpieces = explode($scheme, ‪$data);
4282  $pieces = count($textpieces);
4283  $textstr = $textpieces[0];
4284  for ($i = 1; $i < $pieces; $i++) {
4285  $len = strcspn($textpieces[$i], chr(32) . "\t" . CRLF);
4286  if (trim(substr($textstr, -1)) === '' && $len) {
4287  $lastChar = substr($textpieces[$i], $len - 1, 1);
4288  if (!preg_match('/[A-Za-z0-9\\/#_-]/', $lastChar)) {
4289  $len--;
4290  }
4291  // Included '\/' 3/12
4292  $parts[0] = substr($textpieces[$i], 0, $len);
4293  $parts[1] = substr($textpieces[$i], $len);
4294  $keep = $conf['keep'];
4295  $linkParts = parse_url($scheme . $parts[0]);
4296  $linktxt = '';
4297  if (strpos($keep, 'scheme') !== false) {
4298  $linktxt = $scheme;
4299  }
4300  $linktxt .= $linkParts['host'];
4301  if (strpos($keep, 'path') !== false) {
4302  $linktxt .= $linkParts['path'];
4303  // Added $linkParts['query'] 3/12
4304  if (strpos($keep, 'query') !== false && $linkParts['query']) {
4305  $linktxt .= '?' . $linkParts['query'];
4306  } elseif ($linkParts['path'] === '/') {
4307  $linktxt = substr($linktxt, 0, -1);
4308  }
4309  }
4310  if (isset($conf['extTarget'])) {
4311  if (isset($conf['extTarget.'])) {
4312  $target = $this->‪stdWrap($conf['extTarget'], $conf['extTarget.']);
4313  } else {
4314  $target = $conf['extTarget'];
4315  }
4316  } else {
4317  $target = $this->‪getTypoScriptFrontendController()->extTarget;
4318  }
4319 
4320  // check for jump URLs or similar
4321  $linkUrl = $this->‪processUrl(‪UrlProcessorInterface::CONTEXT_COMMON, $scheme . $parts[0], $conf) ?? '';
4323  $res = '<a href="' . htmlspecialchars($linkUrl) . '"'
4324  . ($target !== '' ? ' target="' . htmlspecialchars($target) . '"' : '')
4325  . $aTagParams . $this->‪extLinkATagParams('http://' . $parts[0], 'url') . '>';
4326 
4327  $wrap = isset($conf['wrap.']) ? $this->‪stdWrap($conf['wrap'], $conf['wrap.']) : $conf['wrap'];
4328  if ((string)$conf['ATagBeforeWrap'] !== '') {
4329  $res = $res . $this->‪wrap($linktxt, $wrap) . '</a>';
4330  } else {
4331  $res = $this->‪wrap($res . $linktxt . '</a>', $wrap);
4332  }
4333  $textstr .= $res . $parts[1];
4334  } else {
4335  $textstr .= $scheme . $textpieces[$i];
4336  }
4337  }
4338  ‪$data = $textstr;
4339  }
4340  return $textstr;
4341  }
4342 
4352  public function ‪mailto_makelinks(‪$data, $conf)
4353  {
4354  $conf = (array)$conf;
4355  $parts = [];
4356  // http-split
4357  $aTagParams = $this->‪getATagParams($conf);
4358  $textpieces = explode('mailto:', ‪$data);
4359  $pieces = count($textpieces);
4360  $textstr = $textpieces[0];
4361  $tsfe = $this->‪getTypoScriptFrontendController();
4362  for ($i = 1; $i < $pieces; $i++) {
4363  $len = strcspn($textpieces[$i], chr(32) . "\t" . CRLF);
4364  if (trim(substr($textstr, -1)) === '' && $len) {
4365  $lastChar = substr($textpieces[$i], $len - 1, 1);
4366  if (!preg_match('/[A-Za-z0-9]/', $lastChar)) {
4367  $len--;
4368  }
4369  $parts[0] = substr($textpieces[$i], 0, $len);
4370  $parts[1] = substr($textpieces[$i], $len);
4371  $linktxt = (string)preg_replace('/\\?.*/', '', $parts[0]);
4372  [$mailToUrl, $linktxt] = $this->‪getMailTo($parts[0], $linktxt);
4373  $mailToUrl = $tsfe->spamProtectEmailAddresses === 'ascii' ? $mailToUrl : htmlspecialchars($mailToUrl);
4374  $res = '<a href="' . $mailToUrl . '"' . $aTagParams . '>';
4375  $wrap = isset($conf['wrap.']) ? $this->‪stdWrap($conf['wrap'], $conf['wrap.']) : $conf['wrap'];
4376  if ((string)$conf['ATagBeforeWrap'] !== '') {
4377  $res = $res . $this->‪wrap($linktxt, $wrap) . '</a>';
4378  } else {
4379  $res = $this->‪wrap($res . $linktxt . '</a>', $wrap);
4380  }
4381  $textstr .= $res . $parts[1];
4382  } else {
4383  $textstr .= 'mailto:' . $textpieces[$i];
4384  }
4385  }
4386  return $textstr;
4387  }
4388 
4414  public function ‪getImgResource($file, $fileArray)
4415  {
4416  $importedFile = null;
4417  if (empty($file) && empty($fileArray)) {
4418  return null;
4419  }
4420  if (!is_array($fileArray)) {
4421  $fileArray = (array)$fileArray;
4422  }
4423  $imageResource = null;
4424  if ($file === 'GIFBUILDER') {
4425  $gifCreator = GeneralUtility::makeInstance(GifBuilder::class);
4426  $theImage = '';
4427  if (‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib']) {
4428  $gifCreator->start($fileArray, $this->data);
4429  $theImage = $gifCreator->gifBuild();
4430  }
4431  $imageResource = $gifCreator->getImageDimensions($theImage);
4432  $imageResource['origFile'] = $theImage;
4433  } else {
4434  if ($file instanceof File) {
4435  $fileObject = $file;
4436  } elseif ($file instanceof FileReference) {
4437  $fileObject = $file->getOriginalFile();
4438  } else {
4439  try {
4440  if (isset($fileArray['import.']) && $fileArray['import.']) {
4441  $importedFile = trim($this->‪stdWrap('', $fileArray['import.']));
4442  if (!empty($importedFile)) {
4443  $file = $importedFile;
4444  }
4445  }
4446 
4448  $treatIdAsReference = isset($fileArray['treatIdAsReference.']) ? $this->‪stdWrap($fileArray['treatIdAsReference'], $fileArray['treatIdAsReference.']) : $fileArray['treatIdAsReference'];
4449  if (!empty($treatIdAsReference)) {
4450  $file = $this->‪getResourceFactory()->‪getFileReferenceObject($file);
4451  $fileObject = $file->‪getOriginalFile();
4452  } else {
4453  $fileObject = $this->‪getResourceFactory()->‪getFileObject($file);
4454  }
4455  } elseif (preg_match('/^(0|[1-9][0-9]*):/', $file)) { // combined identifier
4456  $fileObject = $this->‪getResourceFactory()->‪retrieveFileOrFolderObject($file);
4457  } else {
4458  if (isset($importedFile) && !empty($importedFile) && !empty($fileArray['import'])) {
4459  $file = $fileArray['import'] . $file;
4460  }
4461  $fileObject = $this->‪getResourceFactory()->‪retrieveFileOrFolderObject($file);
4462  }
4463  } catch (Exception $exception) {
4464  $this->logger->warning('The image "' . $file . '" could not be found and won\'t be included in frontend output', ['exception' => $exception]);
4465  return null;
4466  }
4467  }
4468  if ($fileObject instanceof File) {
4469  $processingConfiguration = [];
4470  $processingConfiguration['width'] = isset($fileArray['width.']) ? $this->‪stdWrap($fileArray['width'], $fileArray['width.']) : $fileArray['width'];
4471  $processingConfiguration['height'] = isset($fileArray['height.']) ? $this->‪stdWrap($fileArray['height'], $fileArray['height.']) : $fileArray['height'];
4472  $processingConfiguration['fileExtension'] = isset($fileArray['ext.']) ? $this->‪stdWrap($fileArray['ext'], $fileArray['ext.']) : $fileArray['ext'];
4473  $processingConfiguration['maxWidth'] = isset($fileArray['maxW.']) ? (int)$this->‪stdWrap($fileArray['maxW'], $fileArray['maxW.']) : (int)$fileArray['maxW'];
4474  $processingConfiguration['maxHeight'] = isset($fileArray['maxH.']) ? (int)$this->‪stdWrap($fileArray['maxH'], $fileArray['maxH.']) : (int)$fileArray['maxH'];
4475  $processingConfiguration['minWidth'] = isset($fileArray['minW.']) ? (int)$this->‪stdWrap($fileArray['minW'], $fileArray['minW.']) : (int)$fileArray['minW'];
4476  $processingConfiguration['minHeight'] = isset($fileArray['minH.']) ? (int)$this->‪stdWrap($fileArray['minH'], $fileArray['minH.']) : (int)$fileArray['minH'];
4477  $processingConfiguration['noScale'] = isset($fileArray['noScale.']) ? $this->‪stdWrap($fileArray['noScale'], $fileArray['noScale.']) : $fileArray['noScale'];
4478  $processingConfiguration['additionalParameters'] = isset($fileArray['params.']) ? $this->‪stdWrap($fileArray['params'], $fileArray['params.']) : $fileArray['params'];
4479  $processingConfiguration['frame'] = isset($fileArray['frame.']) ? (int)$this->‪stdWrap($fileArray['frame'], $fileArray['frame.']) : (int)$fileArray['frame'];
4480  if ($file instanceof FileReference) {
4481  $processingConfiguration['crop'] = $this->‪getCropAreaFromFileReference($file, $fileArray);
4482  } else {
4483  $processingConfiguration['crop'] = $this->‪getCropAreaFromFromTypoScriptSettings($fileObject, $fileArray);
4484  }
4485 
4486  // Possibility to cancel/force profile extraction
4487  // see $GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_stripColorProfileCommand']
4488  if (isset($fileArray['stripProfile'])) {
4489  $processingConfiguration['stripProfile'] = $fileArray['stripProfile'];
4490  }
4491  // Check if we can handle this type of file for editing
4492  if ($fileObject->isImage()) {
4493  $maskArray = $fileArray['m.'];
4494  // Must render mask images and include in hash-calculating
4495  // - otherwise we cannot be sure the filename is unique for the setup!
4496  if (is_array($maskArray)) {
4497  $mask = $this->‪getImgResource($maskArray['mask'], $maskArray['mask.']);
4498  $bgImg = $this->‪getImgResource($maskArray['bgImg'], $maskArray['bgImg.']);
4499  $bottomImg = $this->‪getImgResource($maskArray['bottomImg'], $maskArray['bottomImg.']);
4500  $bottomImg_mask = $this->‪getImgResource($maskArray['bottomImg_mask'], $maskArray['bottomImg_mask.']);
4501 
4502  $processingConfiguration['maskImages']['maskImage'] = $mask['processedFile'];
4503  $processingConfiguration['maskImages']['backgroundImage'] = $bgImg['processedFile'];
4504  $processingConfiguration['maskImages']['maskBottomImage'] = $bottomImg['processedFile'];
4505  $processingConfiguration['maskImages']['maskBottomImageMask'] = $bottomImg_mask['processedFile'];
4506  }
4507  $processedFileObject = $fileObject->process(‪ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, $processingConfiguration);
4508  if ($processedFileObject->isProcessed()) {
4509  $imageResource = [
4510  0 => (int)$processedFileObject->getProperty('width'),
4511  1 => (int)$processedFileObject->getProperty('height'),
4512  2 => $processedFileObject->getExtension(),
4513  3 => $processedFileObject->getPublicUrl(),
4514  'origFile' => $fileObject->getPublicUrl(),
4515  'origFile_mtime' => $fileObject->getModificationTime(),
4516  // This is needed by \TYPO3\CMS\Frontend\Imaging\GifBuilder,
4517  // in order for the setup-array to create a unique filename hash.
4518  'originalFile' => $fileObject,
4519  'processedFile' => $processedFileObject
4520  ];
4521  }
4522  }
4523  }
4524  }
4525  // If image was processed by GIFBUILDER:
4526  // ($imageResource indicates that it was processed the regular way)
4527  if (!isset($imageResource)) {
4528  try {
4529  $theImage = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize((string)$file);
4530  $info = GeneralUtility::makeInstance(GifBuilder::class)->imageMagickConvert($theImage, 'WEB');
4531  $info['origFile'] = $theImage;
4532  // This is needed by \TYPO3\CMS\Frontend\Imaging\GifBuilder, ln 100ff in order for the setup-array to create a unique filename hash.
4533  $info['origFile_mtime'] = @filemtime($theImage);
4534  $imageResource = $info;
4535  } catch (Exception $e) {
4536  // do nothing in case the file path is invalid
4537  }
4538  }
4539  // Hook 'getImgResource': Post-processing of image resources
4540  if (isset($imageResource)) {
4542  foreach ($this->‪getGetImgResourceHookObjects() as $hookObject) {
4543  $imageResource = $hookObject->getImgResourcePostProcess($file, (array)$fileArray, $imageResource, $this);
4544  }
4545  }
4546  return $imageResource;
4547  }
4548 
4566  protected function ‪getCropAreaFromFileReference(FileReference $fileReference, array $fileArray)
4567  {
4568  // Use cropping area from file reference if nothing is configured in TypoScript.
4569  if (!isset($fileArray['crop']) && !isset($fileArray['crop.'])) {
4570  // Set crop variant from TypoScript settings. If not set, use default.
4571  $cropVariant = $fileArray['cropVariant'] ?? 'default';
4572  $fileCropArea = $this->‪createCropAreaFromJsonString((string)$fileReference->getProperty('crop'), $cropVariant);
4573  return $fileCropArea->isEmpty() ? null : $fileCropArea->makeAbsoluteBasedOnFile($fileReference);
4574  }
4575 
4576  return $this->‪getCropAreaFromFromTypoScriptSettings($fileReference, $fileArray);
4577  }
4578 
4587  protected function ‪getCropAreaFromFromTypoScriptSettings(FileInterface $file, array $fileArray)
4588  {
4590  $cropArea = null;
4591  // Resolve TypoScript configured cropping.
4592  $cropSettings = isset($fileArray['crop.'])
4593  ? $this->‪stdWrap($fileArray['crop'], $fileArray['crop.'])
4594  : ($fileArray['crop'] ?? null);
4595 
4596  if (is_string($cropSettings)) {
4597  // Set crop variant from TypoScript settings. If not set, use default.
4598  $cropVariant = $fileArray['cropVariant'] ?? 'default';
4599  // Get cropArea from CropVariantCollection, if cropSettings is a valid json.
4600  // CropVariantCollection::create does json_decode.
4601  $jsonCropArea = $this->‪createCropAreaFromJsonString($cropSettings, $cropVariant);
4602  $cropArea = $jsonCropArea->isEmpty() ? null : $jsonCropArea->makeAbsoluteBasedOnFile($file);
4603 
4604  // Cropping is configured in TypoScript in the following way: file.crop = 50,50,100,100
4605  if ($jsonCropArea->isEmpty() && preg_match('/^[0-9]+,[0-9]+,[0-9]+,[0-9]+$/', $cropSettings)) {
4606  $cropSettings = explode(',', $cropSettings);
4607  if (count($cropSettings) === 4) {
4608  $stringCropArea = GeneralUtility::makeInstance(
4609  Area::class,
4610  ...$cropSettings
4611  );
4612  $cropArea = $stringCropArea->isEmpty() ? null : $stringCropArea;
4613  }
4614  }
4615  }
4616 
4617  return $cropArea;
4618  }
4619 
4628  protected function ‪createCropAreaFromJsonString(string $cropSettings, string $cropVariant): Area
4629  {
4630  return ‪CropVariantCollection::create($cropSettings)->‪getCropArea($cropVariant);
4631  }
4632 
4633  /***********************************************
4634  *
4635  * Data retrieval etc.
4636  *
4637  ***********************************************/
4644  public function ‪getFieldVal($field)
4645  {
4646  if (strpos($field, '//') === false) {
4647  return $this->data[trim($field)] ?? null;
4648  }
4649  $sections = ‪GeneralUtility::trimExplode('//', $field, true);
4650  foreach ($sections as $k) {
4651  if ((string)$this->data[$k] !== '') {
4652  return $this->data[$k];
4653  }
4654  }
4655 
4656  return '';
4657  }
4658 
4667  public function ‪getData($string, $fieldArray = null)
4668  {
4669  $tsfe = $this->‪getTypoScriptFrontendController();
4670  if (!is_array($fieldArray)) {
4671  $fieldArray = $tsfe->page;
4672  }
4673  $retVal = '';
4674  $sections = explode('//', $string);
4675  foreach ($sections as $secKey => $secVal) {
4676  if ($retVal) {
4677  break;
4678  }
4679  $parts = explode(':', $secVal, 2);
4680  $type = strtolower(trim($parts[0]));
4681  $typesWithOutParameters = ['level', 'date', 'current', 'pagelayout'];
4682  $key = trim($parts[1] ?? '');
4683  if (($key != '') || in_array($type, $typesWithOutParameters)) {
4684  switch ($type) {
4685  case 'gp':
4686  // Merge GET and POST and get $key out of the merged array
4687  $getPostArray = GeneralUtility::_GET();
4688  ‪ArrayUtility::mergeRecursiveWithOverrule($getPostArray, GeneralUtility::_POST());
4689  $retVal = $this->‪getGlobal($key, $getPostArray);
4690  break;
4691  case 'tsfe':
4692  $retVal = $this->‪getGlobal('TSFE|' . $key);
4693  break;
4694  case 'getenv':
4695  $retVal = getenv($key);
4696  break;
4697  case 'getindpenv':
4698  $retVal = $this->‪getEnvironmentVariable($key);
4699  break;
4700  case 'field':
4701  $retVal = $this->‪getGlobal($key, $fieldArray);
4702  break;
4703  case 'file':
4704  $retVal = $this->‪getFileDataKey($key);
4705  break;
4706  case 'parameters':
4707  $retVal = $this->parameters[$key];
4708  break;
4709  case 'register':
4710  $retVal = $tsfe->register[$key] ?? null;
4711  break;
4712  case 'global':
4713  $retVal = $this->‪getGlobal($key);
4714  break;
4715  case 'level':
4716  $retVal = count($tsfe->tmpl->rootLine) - 1;
4717  break;
4718  case 'leveltitle':
4719  $keyParts = ‪GeneralUtility::trimExplode(',', $key);
4720  $pointer = (int)($keyParts[0] ?? 0);
4721  $slide = (string)($keyParts[1] ?? '');
4722 
4723  $numericKey = $this->‪getKey($pointer, $tsfe->tmpl->rootLine);
4724  $retVal = $this->‪rootLineValue($numericKey, 'title', strtolower($slide) === 'slide');
4725  break;
4726  case 'levelmedia':
4727  $keyParts = ‪GeneralUtility::trimExplode(',', $key);
4728  $pointer = (int)($keyParts[0] ?? 0);
4729  $slide = (string)($keyParts[1] ?? '');
4730 
4731  $numericKey = $this->‪getKey($pointer, $tsfe->tmpl->rootLine);
4732  $retVal = $this->‪rootLineValue($numericKey, 'media', strtolower($slide) === 'slide');
4733  break;
4734  case 'leveluid':
4735  $numericKey = $this->‪getKey((int)$key, $tsfe->tmpl->rootLine);
4736  $retVal = $this->‪rootLineValue($numericKey, 'uid');
4737  break;
4738  case 'levelfield':
4739  $keyParts = ‪GeneralUtility::trimExplode(',', $key);
4740  $pointer = (int)($keyParts[0] ?? 0);
4741  $field = (string)($keyParts[1] ?? '');
4742  $slide = (string)($keyParts[2] ?? '');
4743 
4744  $numericKey = $this->‪getKey($pointer, $tsfe->tmpl->rootLine);
4745  $retVal = $this->‪rootLineValue($numericKey, $field, strtolower($slide) === 'slide');
4746  break;
4747  case 'fullrootline':
4748  $keyParts = ‪GeneralUtility::trimExplode(',', $key);
4749  $pointer = (int)($keyParts[0] ?? 0);
4750  $field = (string)($keyParts[1] ?? '');
4751  $slide = (string)($keyParts[2] ?? '');
4752 
4753  $fullKey = (int)($pointer - count($tsfe->tmpl->rootLine) + count($tsfe->rootLine));
4754  if ($fullKey >= 0) {
4755  $retVal = $this->‪rootLineValue($fullKey, $field, stristr($slide, 'slide') !== false, $tsfe->rootLine);
4756  }
4757  break;
4758  case 'date':
4759  if (!$key) {
4760  $key = 'd/m Y';
4761  }
4762  $retVal = date($key, ‪$GLOBALS['EXEC_TIME']);
4763  break;
4764  case 'page':
4765  $retVal = $tsfe->page[$key];
4766  break;
4767  case 'pagelayout':
4768  $retVal = GeneralUtility::makeInstance(PageLayoutResolver::class)
4769  ->getLayoutForPage($tsfe->page, $tsfe->rootLine);
4770  break;
4771  case 'current':
4772  $retVal = $this->data[‪$this->currentValKey] ?? null;
4773  break;
4774  case 'db':
4775  $selectParts = ‪GeneralUtility::trimExplode(':', $key);
4776  $db_rec = $tsfe->sys_page->getRawRecord($selectParts[0], $selectParts[1]);
4777  if (is_array($db_rec) && $selectParts[2]) {
4778  $retVal = $db_rec[$selectParts[2]];
4779  }
4780  break;
4781  case 'lll':
4782  $retVal = $tsfe->sL('LLL:' . $key);
4783  break;
4784  case 'path':
4785  try {
4786  $retVal = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($key);
4787  } catch (Exception $e) {
4788  // do nothing in case the file path is invalid
4789  $retVal = null;
4790  }
4791  break;
4792  case 'cobj':
4793  switch ($key) {
4794  case 'parentRecordNumber':
4795  $retVal = ‪$this->parentRecordNumber;
4796  break;
4797  }
4798  break;
4799  case 'debug':
4800  switch ($key) {
4801  case 'rootLine':
4802  $retVal = ‪DebugUtility::viewArray($tsfe->tmpl->rootLine);
4803  break;
4804  case 'fullRootLine':
4805  $retVal = ‪DebugUtility::viewArray($tsfe->rootLine);
4806  break;
4807  case 'data':
4808  $retVal = ‪DebugUtility::viewArray($this->data);
4809  break;
4810  case 'register':
4811  $retVal = ‪DebugUtility::viewArray($tsfe->register);
4812  break;
4813  case 'page':
4814  $retVal = ‪DebugUtility::viewArray($tsfe->page);
4815  break;
4816  }
4817  break;
4818  case 'flexform':
4819  $keyParts = ‪GeneralUtility::trimExplode(':', $key, true);
4820  if (count($keyParts) === 2 && isset($this->data[$keyParts[0]])) {
4821  $flexFormContent = $this->data[$keyParts[0]];
4822  if (!empty($flexFormContent)) {
4823  $flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
4824  $flexFormKey = str_replace('.', '|', $keyParts[1]);
4825  $settings = $flexFormService->convertFlexFormContentToArray($flexFormContent);
4826  $retVal = $this->‪getGlobal($flexFormKey, $settings);
4827  }
4828  }
4829  break;
4830  case 'session':
4831  $keyParts = ‪GeneralUtility::trimExplode('|', $key, true);
4832  $sessionKey = array_shift($keyParts);
4833  $retVal = $this->‪getTypoScriptFrontendController()->fe_user->getSessionData($sessionKey);
4834  foreach ($keyParts as $keyPart) {
4835  if (is_object($retVal)) {
4836  $retVal = $retVal->{$keyPart};
4837  } elseif (is_array($retVal)) {
4838  $retVal = $retVal[$keyPart];
4839  } else {
4840  $retVal = '';
4841  break;
4842  }
4843  }
4844  if (!is_scalar($retVal)) {
4845  $retVal = '';
4846  }
4847  break;
4848  case 'context':
4849  $context = GeneralUtility::makeInstance(Context::class);
4850  [$aspectName, $propertyName] = ‪GeneralUtility::trimExplode(':', $key, true, 2);
4851  $retVal = $context->getPropertyFromAspect($aspectName, $propertyName, '');
4852  if (is_array($retVal)) {
4853  $retVal = implode(',', $retVal);
4854  }
4855  if (!is_scalar($retVal)) {
4856  $retVal = '';
4857  }
4858  break;
4859  case 'site':
4860  $site = $this->‪getTypoScriptFrontendController()->‪getSite();
4861  if ($key === 'identifier') {
4862  $retVal = $site->getIdentifier();
4863  } elseif ($key === 'base') {
4864  $retVal = $site->getBase();
4865  } else {
4866  try {
4867  $retVal = ‪ArrayUtility::getValueByPath($site->getConfiguration(), $key, '.');
4868  } catch (MissingArrayPathException $exception) {
4869  $this->logger->notice(sprintf('Configuration "%s" is not defined for site "%s"', $key, $site->getIdentifier()), ['exception' => $exception]);
4870  }
4871  }
4872  break;
4873  case 'sitelanguage':
4875  $config = $siteLanguage->toArray();
4876  if (isset($config[$key])) {
4877  $retVal = $config[$key];
4878  }
4879  break;
4880  }
4881  }
4882 
4883  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getData'] ?? [] as $className) {
4884  $hookObject = GeneralUtility::makeInstance($className);
4885  if (!$hookObject instanceof ContentObjectGetDataHookInterface) {
4886  throw new \UnexpectedValueException('$hookObject must implement interface ' . ContentObjectGetDataHookInterface::class, 1195044480);
4887  }
4888  $ref = $this; // introduced for phpstan to not lose type information when passing $this into callUserFunction
4889  $retVal = $hookObject->getDataExtension($string, $fieldArray, $secVal, $retVal, $ref);
4890  }
4891  }
4892  return $retVal;
4893  }
4894 
4904  protected function getFileDataKey($key)
4905  {
4906  [$fileUidOrCurrentKeyword, $requestedFileInformationKey] = ‪GeneralUtility::trimExplode(':', $key, false, 3);
4907  try {
4908  if ($fileUidOrCurrentKeyword === 'current') {
4909  $fileObject = $this->getCurrentFile();
4910  } elseif (‪MathUtility::canBeInterpretedAsInteger($fileUidOrCurrentKeyword)) {
4912  $fileFactory = GeneralUtility::makeInstance(ResourceFactory::class);
4913  $fileObject = $fileFactory->getFileObject($fileUidOrCurrentKeyword);
4914  } else {
4915  $fileObject = null;
4916  }
4917  } catch (Exception $exception) {
4918  $this->logger->warning('The file "' . $fileUidOrCurrentKeyword . '" could not be found and won\'t be included in frontend output', ['exception' => $exception]);
4919  $fileObject = null;
4920  }
4921 
4922  if ($fileObject instanceof FileInterface) {
4923  // All properties of the \TYPO3\CMS\Core\Resource\FileInterface are available here:
4924  switch ($requestedFileInformationKey) {
4925  case 'name':
4926  return $fileObject->getName();
4927  case 'uid':
4928  if (method_exists($fileObject, 'getUid')) {
4929  return $fileObject->getUid();
4930  }
4931  return 0;
4932  case 'originalUid':
4933  if ($fileObject instanceof FileReference) {
4934  return $fileObject->getOriginalFile()->getUid();
4935  }
4936  return null;
4937  case 'size':
4938  return $fileObject->getSize();
4939  case 'sha1':
4940  return $fileObject->getSha1();
4941  case 'extension':
4942  return $fileObject->getExtension();
4943  case 'mimetype':
4944  return $fileObject->getMimeType();
4945  case 'contents':
4946  return $fileObject->getContents();
4947  case 'publicUrl':
4948  return $fileObject->getPublicUrl();
4949  default:
4950  // Generic alternative here
4951  return $fileObject->getProperty($requestedFileInformationKey);
4952  }
4953  } else {
4954  // @todo fail silently as is common in tslib_content
4955  return 'Error: no file object';
4956  }
4957  }
4958 
4970  public function rootLineValue($key, $field, $slideBack = false, $altRootLine = '')
4971  {
4972  $rootLine = is_array($altRootLine) ? $altRootLine : $this->getTypoScriptFrontendController()->tmpl->rootLine;
4973  if (!$slideBack) {
4974  return $rootLine[$key][$field];
4975  }
4976  for ($a = $key; $a >= 0; $a--) {
4977  $val = $rootLine[$a][$field];
4978  if ($val) {
4979  return $val;
4980  }
4981  }
4982 
4983  return '';
4984  }
4985 
4995  public function getGlobal($keyString, $source = null)
4996  {
4997  $keys = explode('|', $keyString);
4998  $numberOfLevels = count($keys);
4999  $rootKey = trim($keys[0]);
5000  $value = isset($source) ? $source[$rootKey] : ‪$GLOBALS[$rootKey];
5001  for ($i = 1; $i < $numberOfLevels && isset($value); $i++) {
5002  $currentKey = trim($keys[$i]);
5003  if (is_object($value)) {
5004  $value = $value->{$currentKey};
5005  } elseif (is_array($value)) {
5006  $value = $value[$currentKey];
5007  } else {
5008  $value = '';
5009  break;
5010  }
5011  }
5012  if (!is_scalar($value)) {
5013  $value = '';
5014  }
5015  return $value;
5016  }
5017 
5028  public function getKey($key, $arr)
5029  {
5030  $key = (int)$key;
5031  if (is_array($arr)) {
5032  if ($key < 0) {
5033  $key = count($arr) + $key;
5034  }
5035  if ($key < 0) {
5036  $key = 0;
5037  }
5038  }
5039  return $key;
5040  }
5041 
5042  /***********************************************
5043  *
5044  * Link functions (typolink)
5045  *
5046  ***********************************************/
5061  protected function resolveMixedLinkParameter($linkText, $mixedLinkParameter, &$configuration = [])
5062  {
5063  $linkParameter = null;
5064 
5065  // Link parameter value = first part
5066  $linkParameterParts = GeneralUtility::makeInstance(TypoLinkCodecService::class)->decode($mixedLinkParameter);
5067 
5068  // Check for link-handler keyword
5069  $linkHandlerExploded = explode(':', $linkParameterParts['url'], 2);
5070  $linkHandlerKeyword = (string)($linkHandlerExploded[0] ?? '');
5071  $linkHandlerValue = (string)($linkHandlerExploded[1] ?? '');
5072  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['typolinkLinkHandler'][$linkHandlerKeyword])
5073  && $linkHandlerValue !== ''
5074  ) {
5075  trigger_error('The hook $TYPO3_CONF_VARS[SC_OPTIONS][tslib/class.tslib_content.php][typolinkLinkHandler] will be removed in TYPO3 v11.0. Use a custom LinkHandler instead. The used link handler keyword was: ' . $linkHandlerKeyword, E_USER_DEPRECATED);
5076  $linkHandlerObj = GeneralUtility::makeInstance(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['typolinkLinkHandler'][$linkHandlerKeyword]);
5077  if (method_exists($linkHandlerObj, 'main')) {
5078  return $linkHandlerObj->main($linkText, $configuration, $linkHandlerKeyword, $linkHandlerValue, $mixedLinkParameter, $this);
5079  }
5080  }
5081 
5082  if (in_array(strtolower((string)preg_replace('#\s|[[:cntrl:]]#', '', $linkHandlerKeyword)), ['javascript', 'data'], true)) {
5083  // Disallow insecure scheme's like javascript: or data:
5084  return $linkText;
5085  }
5086  $linkParameter = $linkParameterParts['url'];
5087 
5088  // additional parameters that need to be set
5089  if ($linkParameterParts['additionalParams'] !== '') {
5090  $forceParams = $linkParameterParts['additionalParams'];
5091  // params value
5092  $configuration['additionalParams'] .= $forceParams[0] === '&' ? $forceParams : '&' . $forceParams;
5093  }
5094 
5095  return [
5096  'href' => $linkParameter,
5097  'target' => $linkParameterParts['target'],
5098  'class' => $linkParameterParts['class'],
5099  'title' => $linkParameterParts['title']
5100  ];
5101  }
5102 
5118  public function typoLink($linkText, $conf)
5119  {
5120  $linkText = (string)$linkText;
5121  $tsfe = $this->getTypoScriptFrontendController();
5122 
5123  $linkParameter = trim(
5124  (isset($conf['parameter.']))
5125  ? $this->stdWrap($conf['parameter'] ?? '', $conf['parameter.'])
5126  : ($conf['parameter'] ?? '')
5127  );
5128  $this->lastTypoLinkUrl = '';
5129  $this->lastTypoLinkTarget = '';
5130 
5131  $resolvedLinkParameters = $this->resolveMixedLinkParameter($linkText, $linkParameter, $conf);
5132  // check if the link handler hook has resolved the link completely already
5133  if (!is_array($resolvedLinkParameters)) {
5134  return $resolvedLinkParameters;
5135  }
5136  $linkParameter = $resolvedLinkParameters['href'];
5137  $target = $resolvedLinkParameters['target'];
5138  $title = $resolvedLinkParameters['title'];
5139 
5140  if (!$linkParameter) {
5141  return $this->resolveAnchorLink($linkText, $conf ?? []);
5142  }
5143 
5144  // Detecting kind of link and resolve all necessary parameters
5145  $linkService = GeneralUtility::makeInstance(LinkService::class);
5146  try {
5147  $linkDetails = $linkService->resolve($linkParameter);
5148  } catch (UnknownLinkHandlerException | InvalidPathException $exception) {
5149  $this->logger->warning('The link could not be generated', ['exception' => $exception]);
5150  return $linkText;
5151  }
5152 
5153  $linkDetails['typoLinkParameter'] = $linkParameter;
5154  if (isset($linkDetails['type']) && isset(‪$GLOBALS['TYPO3_CONF_VARS']['FE']['typolinkBuilder'][$linkDetails['type']])) {
5156  $linkBuilder = GeneralUtility::makeInstance(
5157  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['typolinkBuilder'][$linkDetails['type']],
5158  $this,
5159  $tsfe
5160  );
5161  try {
5162  [$this->lastTypoLinkUrl, $linkText, $target] = $linkBuilder->build($linkDetails, $linkText, $target, $conf);
5163  $this->lastTypoLinkTarget = htmlspecialchars($target);
5164  $this->lastTypoLinkLD['target'] = htmlspecialchars($target);
5165  $this->lastTypoLinkLD['totalUrl'] = $this->lastTypoLinkUrl;
5166  } catch (UnableToLinkException $e) {
5167  $this->logger->debug(sprintf('Unable to link "%s": %s', $e->getLinkText(), $e->getMessage()), ['exception' => $e]);
5168 
5169  // Only return the link text directly
5170  return $e->getLinkText();
5171  }
5172  } elseif (isset($linkDetails['url'])) {
5173  $this->lastTypoLinkUrl = $linkDetails['url'];
5174  $this->lastTypoLinkTarget = htmlspecialchars($target);
5175  $this->lastTypoLinkLD['target'] = htmlspecialchars($target);
5176  $this->lastTypoLinkLD['totalUrl'] = $this->lastTypoLinkUrl;
5177  } else {
5178  return $linkText;
5179  }
5180 
5181  // We need to backup the URL because ATagParams might call typolink again and change the last URL.
5182  $url = $this->lastTypoLinkUrl;
5183  $finalTagParts = [
5184  'aTagParams' => $this->getATagParams($conf) . $this->extLinkATagParams($this->lastTypoLinkUrl, $linkDetails['type']),
5185  'url' => $url,
5186  'TYPE' => $linkDetails['type']
5187  ];
5188 
5189  // Ensure "href" is not in the list of aTagParams to avoid double tags, usually happens within buggy parseFunc settings
5190  if (!empty($finalTagParts['aTagParams'])) {
5191  $aTagParams = GeneralUtility::get_tag_attributes($finalTagParts['aTagParams'], true);
5192  if (isset($aTagParams['href'])) {
5193  unset($aTagParams['href']);
5194  $finalTagParts['aTagParams'] = GeneralUtility::implodeAttributes($aTagParams, true);
5195  }
5196  }
5197 
5198  // Building the final <a href=".."> tag
5199  $tagAttributes = [];
5200 
5201  // Title attribute
5202  if (empty($title)) {
5203  $title = $conf['title'] ?? '';
5204  if (isset($conf['title.']) && is_array($conf['title.'])) {
5205  $title = $this->stdWrap($title, $conf['title.']);
5206  }
5207  }
5208 
5209  // Check, if the target is coded as a JS open window link:
5210  $JSwindowParts = [];
5211  $JSwindowParams = '';
5212  if ($target && preg_match('/^([0-9]+)x([0-9]+)(:(.*)|.*)$/', $target, $JSwindowParts)) {
5213  // Take all pre-configured and inserted parameters and compile parameter list, including width+height:
5214  $JSwindow_tempParamsArr = GeneralUtility::trimExplode(',', strtolower(($conf['JSwindow_params'] ?? '') . ',' . ($JSwindowParts[4] ?? '')), true);
5215  $JSwindow_paramsArr = [];
5216  $target = $conf['target'] ?? 'FEopenLink';
5217  foreach ($JSwindow_tempParamsArr as $JSv) {
5218  [$JSp, $JSv] = explode('=', $JSv, 2);
5219  // If the target is set as JS param, this is extracted
5220  if ($JSp === 'target') {
5221  $target = $JSv;
5222  } else {
5223  $JSwindow_paramsArr[$JSp] = $JSp . '=' . $JSv;
5224  }
5225  }
5226  // Add width/height:
5227  $JSwindow_paramsArr['width'] = 'width=' . $JSwindowParts[1];
5228  $JSwindow_paramsArr['height'] = 'height=' . $JSwindowParts[2];
5229  // Imploding into string:
5230  $JSwindowParams = implode(',', $JSwindow_paramsArr);
5231  }
5232 
5233  if (!$JSwindowParams && $linkDetails['type'] === LinkService::TYPE_EMAIL && $tsfe->spamProtectEmailAddresses === 'ascii') {
5234  $tagAttributes['href'] = $finalTagParts['url'];
5235  } else {
5236  $tagAttributes['href'] = htmlspecialchars($finalTagParts['url']);
5237  }
5238  if (!empty($title)) {
5239  $tagAttributes['title'] = htmlspecialchars($title);
5240  }
5241 
5242  // Target attribute
5243  if (!empty($target)) {
5244  $tagAttributes['target'] = htmlspecialchars($target);
5245  }
5246  if ($JSwindowParams && in_array($tsfe->xhtmlDoctype, ['xhtml_strict', 'xhtml_11'], true)) {
5247  // Create TARGET-attribute only if the right doctype is used
5248  unset($tagAttributes['target']);
5249  }
5250 
5251  if ($JSwindowParams) {
5252  $onClick = 'openPic(' . GeneralUtility::quoteJSvalue($tsfe->baseUrlWrap($finalTagParts['url']))
5253  . ',' . GeneralUtility::quoteJSvalue($target) . ','
5254  . GeneralUtility::quoteJSvalue($JSwindowParams)
5255  . ');return false;';
5256  $tagAttributes['onclick'] = htmlspecialchars($onClick);
5257  GeneralUtility::makeInstance(AssetCollector::class)->addInlineJavaScript('openPic', 'function openPic(url, winName, winParams) { var theWindow = window.open(url, winName, winParams); if (theWindow) { theWindow.focus(); } }');
5258  }
5259 
5260  if (!empty($resolvedLinkParameters['class'])) {
5261  $tagAttributes['class'] = htmlspecialchars($resolvedLinkParameters['class']);
5262  }
5263 
5264  // Prevent trouble with double and missing spaces between attributes and merge params before implode
5265  // (skip decoding HTML entities, since `$tagAttributes` are expected to be encoded already)
5266  $finalTagAttributes = array_merge($tagAttributes, GeneralUtility::get_tag_attributes($finalTagParts['aTagParams']));
5267  $finalTagAttributes = $this->addSecurityRelValues($finalTagAttributes, $target, $tagAttributes['href']);
5268  $finalAnchorTag = '<a ' . GeneralUtility::implodeAttributes($finalTagAttributes) . '>';
5269 
5270  // kept for backwards-compatibility in hooks
5271  $finalTagParts['targetParams'] = !empty($tagAttributes['target']) ? ' target="' . $tagAttributes['target'] . '"' : '';
5272  $this->lastTypoLinkTarget = $target;
5273 
5274  // Call user function:
5275  if ($conf['userFunc'] ?? false) {
5276  $finalTagParts['TAG'] = $finalAnchorTag;
5277  $finalAnchorTag = $this->callUserFunction($conf['userFunc'], $conf['userFunc.'] ?? [], $finalTagParts);
5278  }
5279 
5280  // Hook: Call post processing function for link rendering:
5281  $_params = [
5282  'conf' => &$conf,
5283  'linktxt' => &$linkText,
5284  'finalTag' => &$finalAnchorTag,
5285  'finalTagParts' => &$finalTagParts,
5286  'linkDetails' => &$linkDetails,
5287  'tagAttributes' => &$finalTagAttributes
5288  ];
5289  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['typoLink_PostProc'] ?? [] as $_funcRef) {
5290  $ref = $this; // introduced for phpstan to not lose type information when passing $this into callUserFunction
5291  GeneralUtility::callUserFunction($_funcRef, $_params, $ref);
5292  }
5293 
5294  // If flag "returnLastTypoLinkUrl" set, then just return the latest URL made:
5295  if ($conf['returnLast'] ?? false) {
5296  switch ($conf['returnLast']) {
5297  case 'url':
5298  return $this->lastTypoLinkUrl;
5299  case 'target':
5300  return $this->lastTypoLinkTarget;
5301  }
5302  }
5303 
5304  $wrap = isset($conf['wrap.'])
5305  ? $this->stdWrap($conf['wrap'] ?? '', $conf['wrap.'])
5306  : $conf['wrap'] ?? '';
5307 
5308  if ($conf['ATagBeforeWrap'] ?? false) {
5309  return $finalAnchorTag . $this->wrap($linkText, $wrap) . '</a>';
5310  }
5311  return $this->wrap($finalAnchorTag . $linkText . '</a>', $wrap);
5312  }
5313 
5314  protected function addSecurityRelValues(array $tagAttributes, ?string $target, string $url): array
5315  {
5316  $relAttribute = 'noreferrer';
5317  if (in_array($target, ['', null, '_self', '_parent', '_top'], true) || $this->isInternalUrl($url)) {
5318  return $tagAttributes;
5319  }
5320 
5321  if (!isset($tagAttributes['rel'])) {
5322  $tagAttributes['rel'] = $relAttribute;
5323  return $tagAttributes;
5324  }
5325 
5326  $tagAttributes['rel'] = implode(' ', array_unique(array_merge(
5327  GeneralUtility::trimExplode(' ', $relAttribute),
5328  GeneralUtility::trimExplode(' ', $tagAttributes['rel'])
5329  )));
5330 
5331  return $tagAttributes;
5332  }
5333 
5344  protected function isInternalUrl(string $url): bool
5345  {
5346  $cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('runtime');
5347  $parsedUrl = parse_url($url);
5348  $foundDomains = 0;
5349  if (!isset($parsedUrl['host'])) {
5350  return true;
5351  }
5352 
5353  $cacheIdentifier = sha1('isInternalDomain' . $parsedUrl['host']);
5354 
5355  if ($cache->has($cacheIdentifier) === false) {
5356  foreach (GeneralUtility::makeInstance(SiteFinder::class)->getAllSites() as $site) {
5357  if ($site->getBase()->getHost() === $parsedUrl['host']) {
5358  ++$foundDomains;
5359  break;
5360  }
5361 
5362  if ($site->getBase()->getHost() === '' && GeneralUtility::isOnCurrentHost($url)) {
5363  ++$foundDomains;
5364  break;
5365  }
5366  }
5367 
5368  $cache->set($cacheIdentifier, $foundDomains > 0);
5369  }
5371  return (bool)$cache->get($cacheIdentifier);
5372  }
5373 
5381  public function typoLink_URL($conf)
5382  {
5383  $this->typoLink('|', $conf);
5384  return $this->lastTypoLinkUrl;
5385  }
5386 
5400  public function getTypoLink($label, $params, $urlParameters = [], $target = '')
5401  {
5402  $conf = [];
5403  $conf['parameter'] = $params;
5404  if ($target) {
5405  $conf['target'] = $target;
5406  $conf['extTarget'] = $target;
5407  $conf['fileTarget'] = $target;
5408  }
5409  if (is_array($urlParameters)) {
5410  if (!empty($urlParameters)) {
5411  $conf['additionalParams'] .= HttpUtility::buildQueryString($urlParameters, '&');
5412  }
5413  } else {
5414  $conf['additionalParams'] .= $urlParameters;
5415  }
5416  $out = $this->typoLink($label, $conf);
5417  return $out;
5418  }
5419 
5427  public function getUrlToCurrentLocation($addQueryString = true)
5428  {
5429  $conf = [];
5430  $conf['parameter'] = $this->getTypoScriptFrontendController()->id . ',' . $this->getTypoScriptFrontendController()->type;
5431  if ($addQueryString) {
5432  $conf['addQueryString'] = '1';
5433  $linkVars = implode(',', array_keys(GeneralUtility::explodeUrl2Array($this->getTypoScriptFrontendController()->linkVars)));
5434  $conf['addQueryString.'] = [
5435  'method' => 'GET',
5436  'exclude' => 'id,type,cHash' . ($linkVars ? ',' . $linkVars : '')
5437  ];
5438  }
5439 
5440  return $this->typoLink_URL($conf);
5441  }
5442 
5452  public function getTypoLink_URL($params, $urlParameters = [], $target = '')
5453  {
5454  $this->getTypoLink('', $params, $urlParameters, $target);
5455  return $this->lastTypoLinkUrl;
5456  }
5457 
5467  protected function processUrl($context, $url, $typolinkConfiguration = [])
5468  {
5469  $urlProcessors = ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['urlProcessing']['urlProcessors'] ?? [];
5470  if (empty($urlProcessors)) {
5471  return $url;
5472  }
5473 
5474  foreach ($urlProcessors as $identifier => $configuration) {
5475  if (empty($configuration) || !is_array($configuration)) {
5476  throw new \RuntimeException('Missing configuration for URI processor "' . $identifier . '".', 1442050529);
5477  }
5478  if (!is_string($configuration['processor']) || empty($configuration['processor']) || !class_exists($configuration['processor']) || !is_subclass_of($configuration['processor'], UrlProcessorInterface::class)) {
5479  throw new \RuntimeException('The URI processor "' . $identifier . '" defines an invalid provider. Ensure the class exists and implements the "' . UrlProcessorInterface::class . '".', 1442050579);
5480  }
5481  }
5482 
5483  $orderedProcessors = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies($urlProcessors);
5484  $keepProcessing = true;
5485 
5486  foreach ($orderedProcessors as $configuration) {
5488  $urlProcessor = GeneralUtility::makeInstance($configuration['processor']);
5489  $url = $urlProcessor->process($context, $url, $typolinkConfiguration, $this, $keepProcessing);
5490  if (!$keepProcessing) {
5491  break;
5492  }
5493  }
5494 
5495  return $url;
5496  }
5497 
5507  public function getMailTo($mailAddress, $linktxt)
5508  {
5509  $mailAddress = (string)$mailAddress;
5510  if ((string)$linktxt === '') {
5511  $linktxt = htmlspecialchars($mailAddress);
5512  }
5513 
5514  $originalMailToUrl = 'mailto:' . $mailAddress;
5515  $mailToUrl = $this->processUrl(UrlProcessorInterface::CONTEXT_MAIL, $originalMailToUrl);
5516 
5517  // no processing happened, therefore, the default processing kicks in
5518  if ($mailToUrl === $originalMailToUrl) {
5519  $tsfe = $this->getTypoScriptFrontendController();
5520  if ($tsfe->spamProtectEmailAddresses) {
5521  $mailToUrl = $this->‪encryptEmail($mailToUrl, $tsfe->spamProtectEmailAddresses);
5522  if ($tsfe->spamProtectEmailAddresses !== 'ascii') {
5523  $encodedForJsAndHref = rawurlencode(GeneralUtility::quoteJSvalue($mailToUrl));
5524  $mailToUrl = 'javascript:linkTo_UnCryptMailto(' . $encodedForJsAndHref . ');';
5525  }
5526  $atLabel = trim($tsfe->config['config']['spamProtectEmailAddresses_atSubst']) ?: '(at)';
5527  $spamProtectedMailAddress = str_replace('@', $atLabel, htmlspecialchars($mailAddress));
5528  if ($tsfe->config['config']['spamProtectEmailAddresses_lastDotSubst']) {
5529  $lastDotLabel = trim($tsfe->config['config']['spamProtectEmailAddresses_lastDotSubst']);
5530  $lastDotLabel = $lastDotLabel ?: '(dot)';
5531  $spamProtectedMailAddress = preg_replace('/\\.([^\\.]+)$/', $lastDotLabel . '$1', $spamProtectedMailAddress);
5532  if ($spamProtectedMailAddress === null) {
5533  $this->logger->debug('Error replacing the last dot in email address "' . $spamProtectedMailAddress . '"');
5534  $spamProtectedMailAddress = '';
5535  }
5536  }
5537  $linktxt = str_ireplace($mailAddress, $spamProtectedMailAddress, $linktxt);
5538  }
5539  }
5540 
5541  return [$mailToUrl, $linktxt];
5542  }
5543 
5551  protected function encryptEmail(string $string, $type): string
5552  {
5553  $out = '';
5554  // obfuscates using the decimal HTML entity references for each character
5555  if ($type === 'ascii') {
5556  foreach (preg_split('//u', $string, -1, PREG_SPLIT_NO_EMPTY) as $char) {
5557  $out .= '&#' . mb_ord($char) . ';';
5558  }
5559  } else {
5560  // like str_rot13() but with a variable offset and a wider character range
5561  $len = strlen($string);
5562  $offset = (int)$type;
5563  for ($i = 0; $i < $len; $i++) {
5564  $charValue = ord($string[$i]);
5565  // 0-9 . , - + / :
5566  if ($charValue >= 43 && $charValue <= 58) {
5567  $out .= $this->encryptCharcode($charValue, 43, 58, $offset);
5568  } elseif ($charValue >= 64 && $charValue <= 90) {
5569  // A-Z @
5570  $out .= $this->encryptCharcode($charValue, 64, 90, $offset);
5571  } elseif ($charValue >= 97 && $charValue <= 122) {
5572  // a-z
5573  $out .= $this->encryptCharcode($charValue, 97, 122, $offset);
5574  } else {
5575  $out .= $string[$i];
5576  }
5577  }
5578  }
5579  return $out;
5580  }
5581 
5592  protected function encryptCharcode($n, $start, $end, $offset)
5593  {
5594  $n = $n + $offset;
5595  if ($offset > 0 && $n > $end) {
5596  $n = $start + ($n - $end - 1);
5597  } elseif ($offset < 0 && $n < $start) {
5598  $n = $end - ($start - $n - 1);
5599  }
5600  return chr($n);
5601  }
5602 
5612  public function getQueryArguments($conf, $overruleQueryArguments = [], $forceOverruleArguments = false)
5613  {
5614  $exclude = [];
5615  $method = (string)($conf['method'] ?? '');
5616  if ($method === 'POST') {
5617  trigger_error('Assigning typolink.addQueryString.method = POST is not supported anymore since TYPO3 v10.0.', E_USER_WARNING);
5618  return '';
5619  }
5620  if ($method === 'GET,POST' || $method === 'POST,GET') {
5621  trigger_error('Assigning typolink.addQueryString.method = GET,POST or POST,GET is not supported anymore since TYPO3 v10.0 - falling back to GET.', E_USER_WARNING);
5622  $method = 'GET';
5623  }
5624  if ($method === 'GET') {
5625  $currentQueryArray = GeneralUtility::_GET();
5626  } else {
5627  $currentQueryArray = [];
5628  parse_str($this->getEnvironmentVariable('QUERY_STRING'), $currentQueryArray);
5629  }
5630  if ($conf['exclude'] ?? false) {
5631  $excludeString = str_replace(',', '&', $conf['exclude']);
5632  $excludedQueryParts = [];
5633  parse_str($excludeString, $excludedQueryParts);
5634  // never repeat id
5635  $exclude['id'] = 0;
5636  $newQueryArray = ArrayUtility::arrayDiffKeyRecursive($currentQueryArray, $excludedQueryParts);
5637  } else {
5638  $newQueryArray = $currentQueryArray;
5639  }
5640  ArrayUtility::mergeRecursiveWithOverrule($newQueryArray, $overruleQueryArguments, $forceOverruleArguments);
5641  return HttpUtility::buildQueryString($newQueryArray, '&');
5642  }
5643 
5644  /***********************************************
5645  *
5646  * Miscellaneous functions, stand alone
5647  *
5648  ***********************************************/
5660  public function wrap($content, $wrap, $char = '|')
5661  {
5662  if ($wrap) {
5663  $wrapArr = explode($char, $wrap);
5664  $content = trim($wrapArr[0] ?? '') . $content . trim($wrapArr[1] ?? '');
5665  }
5666  return $content;
5667  }
5668 
5679  public function noTrimWrap($content, $wrap, $char = '|')
5680  {
5681  if ($wrap) {
5682  // expects to be wrapped with (at least) 3 characters (before, middle, after)
5683  // anything else is not taken into account
5684  $wrapArr = explode($char, $wrap, 4);
5685  $content = $wrapArr[1] . $content . $wrapArr[2];
5686  }
5687  return $content;
5688  }
5689 
5702  public function callUserFunction($funcName, $conf, $content)
5703  {
5704  // Split parts
5705  $parts = explode('->', $funcName);
5706  if (count($parts) === 2) {
5707  // Check whether PHP class is available
5708  if (class_exists($parts[0])) {
5709  if ($this->container && $this->container->has($parts[0])) {
5710  $classObj = $this->container->get($parts[0]);
5711  } else {
5712  $classObj = GeneralUtility::makeInstance($parts[0]);
5713  }
5714  $methodName = (string)$parts[1];
5715  $callable = [$classObj, $methodName];
5716  if (is_object($classObj) && method_exists($classObj, $parts[1]) && is_callable($callable)) {
5717  $classObj->cObj = $this;
5718  $content = call_user_func_array($callable, [
5719  $content,
5720  $conf
5721  ]);
5722  } else {
5723  $this->getTimeTracker()->setTSlogMessage('Method "' . $parts[1] . '" did not exist in class "' . $parts[0] . '"', 3);
5724  }
5725  } else {
5726  $this->getTimeTracker()->setTSlogMessage('Class "' . $parts[0] . '" did not exist', 3);
5727  }
5728  } elseif (function_exists($funcName)) {
5729  $content = $funcName($content, $conf);
5730  } else {
5731  $this->getTimeTracker()->setTSlogMessage('Function "' . $funcName . '" did not exist', 3);
5732  }
5733  return $content;
5734  }
5735 
5742  public function keywords($content)
5743  {
5744  $listArr = preg_split('/[,;' . LF . ']/', $content);
5745  if ($listArr === false) {
5746  return '';
5747  }
5748  foreach ($listArr as $k => $v) {
5749  $listArr[$k] = trim($v);
5750  }
5751  return implode(',', $listArr);
5752  }
5753 
5762  public function caseshift($theValue, $case)
5763  {
5764  switch (strtolower($case)) {
5765  case 'upper':
5766  $theValue = mb_strtoupper($theValue, 'utf-8');
5767  break;
5768  case 'lower':
5769  $theValue = mb_strtolower($theValue, 'utf-8');
5770  break;
5771  case 'capitalize':
5772  $theValue = mb_convert_case($theValue, MB_CASE_TITLE, 'utf-8');
5773  break;
5774  case 'ucfirst':
5775  $firstChar = mb_substr($theValue, 0, 1, 'utf-8');
5776  $firstChar = mb_strtoupper($firstChar, 'utf-8');
5777  $remainder = mb_substr($theValue, 1, null, 'utf-8');
5778  $theValue = $firstChar . $remainder;
5779  break;
5780  case 'lcfirst':
5781  $firstChar = mb_substr($theValue, 0, 1, 'utf-8');
5782  $firstChar = mb_strtolower($firstChar, 'utf-8');
5783  $remainder = mb_substr($theValue, 1, null, 'utf-8');
5784  $theValue = $firstChar . $remainder;
5785  break;
5786  case 'uppercamelcase':
5787  $theValue = GeneralUtility::underscoredToUpperCamelCase($theValue);
5788  break;
5789  case 'lowercamelcase':
5790  $theValue = GeneralUtility::underscoredToLowerCamelCase($theValue);
5791  break;
5792  }
5793  return $theValue;
5794  }
5795 
5804  public function HTMLcaseshift($theValue, $case)
5805  {
5806  $inside = 0;
5807  $newVal = '';
5808  $pointer = 0;
5809  $totalLen = strlen($theValue);
5810  do {
5811  if (!$inside) {
5812  $len = strcspn(substr($theValue, $pointer), '<');
5813  $newVal .= $this->caseshift(substr($theValue, $pointer, $len), $case);
5814  $inside = 1;
5815  } else {
5816  $len = strcspn(substr($theValue, $pointer), '>') + 1;
5817  $newVal .= substr($theValue, $pointer, $len);
5818  $inside = 0;
5819  }
5820  $pointer += $len;
5821  } while ($pointer < $totalLen);
5822  return $newVal;
5823  }
5824 
5832  public function calcAge($seconds, $labels)
5833  {
5834  if (MathUtility::canBeInterpretedAsInteger($labels)) {
5835  $labels = ' min| hrs| days| yrs| min| hour| day| year';
5836  } else {
5837  $labels = str_replace('"', '', $labels);
5838  }
5839  $labelArr = explode('|', $labels);
5840  if (count($labelArr) === 4) {
5841  $labelArr = array_merge($labelArr, $labelArr);
5842  }
5843  $absSeconds = abs($seconds);
5844  $sign = $seconds > 0 ? 1 : -1;
5845  if ($absSeconds < 3600) {
5846  $val = round($absSeconds / 60);
5847  $seconds = $sign * $val . ($val == 1 ? $labelArr[4] : $labelArr[0]);
5848  } elseif ($absSeconds < 24 * 3600) {
5849  $val = round($absSeconds / 3600);
5850  $seconds = $sign * $val . ($val == 1 ? $labelArr[5] : $labelArr[1]);
5851  } elseif ($absSeconds < 365 * 24 * 3600) {
5852  $val = round($absSeconds / (24 * 3600));
5853  $seconds = $sign * $val . ($val == 1 ? $labelArr[6] : $labelArr[2]);
5854  } else {
5855  $val = round($absSeconds / (365 * 24 * 3600));
5856  $seconds = $sign * $val . ($val == 1 ? ($labelArr[7] ?? null) : ($labelArr[3] ?? null));
5857  }
5858  return $seconds;
5859  }
5860 
5873  public function sendNotifyEmail($message, $recipients, $cc, $senderAddress, $senderName = '', $replyTo = '')
5874  {
5875  trigger_error('ContentObjectRenderer::sendNotifyEmail is deprecated and will be removed in TYPO3 v11. Consider using the mail API directly.', E_USER_DEPRECATED);
5877  $mail = GeneralUtility::makeInstance(MailMessage::class);
5878  $senderName = trim($senderName);
5879  $senderAddress = trim($senderAddress);
5880  if ($senderAddress !== '') {
5881  $mail->from(new Address($senderAddress, $senderName));
5882  }
5883  $parsedReplyTo = MailUtility::parseAddresses($replyTo);
5884  if (!empty($parsedReplyTo)) {
5885  $mail->replyTo($parsedReplyTo);
5886  }
5887  $message = trim($message);
5888  if ($message !== '') {
5889  // First line is subject
5890  $messageParts = explode(LF, $message, 2);
5891  $subject = trim($messageParts[0]);
5892  $plainMessage = trim($messageParts[1]);
5893  $parsedRecipients = MailUtility::parseAddresses($recipients);
5894  if (!empty($parsedRecipients)) {
5895  $mail->to(...$parsedRecipients)
5896  ->subject($subject)
5897  ->text($plainMessage);
5898  $mail->send();
5899  }
5900  $parsedCc = MailUtility::parseAddresses($cc);
5901  if (!empty($parsedCc)) {
5902  $from = $mail->getFrom();
5904  $mail = GeneralUtility::makeInstance(MailMessage::class);
5905  if (!empty($parsedReplyTo)) {
5906  $mail->replyTo($parsedReplyTo);
5907  }
5908  $mail->from($from)
5909  ->to(...$parsedCc)
5910  ->subject($subject)
5911  ->text($plainMessage);
5912  $mail->send();
5913  }
5914  return true;
5915  }
5916  return false;
5917  }
5918 
5927  public function mergeTSRef($confArr, $prop)
5928  {
5929  if ($confArr[$prop][0] === '<') {
5930  $key = trim(substr($confArr[$prop], 1));
5931  $cF = GeneralUtility::makeInstance(TypoScriptParser::class);
5932  // $name and $conf is loaded with the referenced values.
5933  $old_conf = $confArr[$prop . '.'];
5934  [, $conf] = $cF->getVal($key, $this->getTypoScriptFrontendController()->tmpl->setup);
5935  if (is_array($old_conf) && !empty($old_conf)) {
5936  $conf = is_array($conf) ? array_replace_recursive($conf, $old_conf) : $old_conf;
5937  }
5938  $confArr[$prop . '.'] = $conf;
5939  }
5940  return $confArr;
5941  }
5942 
5943  /***********************************************
5944  *
5945  * Database functions, making of queries
5946  *
5947  ***********************************************/
5975  public function getTreeList($id, $depth, $begin = 0, $dontCheckEnableFields = false, $addSelectFields = '', $moreWhereClauses = '', array $prevId_array = [], $recursionLevel = 0)
5976  {
5977  $id = (int)$id;
5978  if (!$id) {
5979  return '';
5980  }
5981 
5982  // Init vars:
5983  $allFields = 'uid,hidden,starttime,endtime,fe_group,extendToSubpages,doktype,php_tree_stop,mount_pid,mount_pid_ol,t3ver_state,l10n_parent' . $addSelectFields;
5984  $depth = (int)$depth;
5985  $begin = (int)$begin;
5986  $theList = [];
5987  $addId = 0;
5988  $requestHash = '';
5989 
5990  // First level, check id (second level, this is done BEFORE the recursive call)
5991  $tsfe = $this->getTypoScriptFrontendController();
5992  if (!$recursionLevel) {
5993  // Check tree list cache
5994  // First, create the hash for this request - not sure yet whether we need all these parameters though
5995  $parameters = [
5996  $id,
5997  $depth,
5998  $begin,
5999  $dontCheckEnableFields,
6000  $addSelectFields,
6001  $moreWhereClauses,
6002  $prevId_array,
6003  GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('frontend.user', 'groupIds', [0, -1])
6004  ];
6005  $requestHash = md5(serialize($parameters));
6006  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
6007  ->getQueryBuilderForTable('cache_treelist');
6008  $cacheEntry = $queryBuilder->select('treelist')
6009  ->from('cache_treelist')
6010  ->where(
6011  $queryBuilder->expr()->eq(
6012  'md5hash',
6013  $queryBuilder->createNamedParameter($requestHash, \PDO::PARAM_STR)
6014  ),
6015  $queryBuilder->expr()->orX(
6016  $queryBuilder->expr()->gt(
6017  'expires',
6018  $queryBuilder->createNamedParameter(‪$GLOBALS['EXEC_TIME'], \PDO::PARAM_INT)
6019  ),
6020  $queryBuilder->expr()->eq('expires', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
6021  )
6022  )
6023  ->setMaxResults(1)
6024  ->execute()
6025  ->fetch();
6026 
6027  if (is_array($cacheEntry)) {
6028  // Cache hit
6029  return $cacheEntry['treelist'];
6030  }
6031  // If Id less than zero it means we should add the real id to list:
6032  if ($id < 0) {
6033  $addId = $id = abs($id);
6034  }
6035  // Check start page:
6036  if ($tsfe->sys_page->getRawRecord('pages', $id, 'uid')) {
6037  // Find mount point if any:
6038  $mount_info = $tsfe->sys_page->getMountPointInfo($id);
6039  if (is_array($mount_info)) {
6040  $id = $mount_info['mount_pid'];
6041  // In Overlay mode, use the mounted page uid as added ID!:
6042  if ($addId && $mount_info['overlay']) {
6043  $addId = $id;
6044  }
6045  }
6046  } else {
6047  // Return blank if the start page was NOT found at all!
6048  return '';
6049  }
6050  }
6051  // Add this ID to the array of IDs
6052  if ($begin <= 0) {
6053  $prevId_array[] = $id;
6054  }
6055  // Select sublevel:
6056  if ($depth > 0) {
6057  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
6058  $queryBuilder->getRestrictions()
6059  ->removeAll()
6060  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
6061  $queryBuilder->select(...GeneralUtility::trimExplode(',', $allFields, true))
6062  ->from('pages')
6063  ->where(
6064  $queryBuilder->expr()->eq(
6065  'pid',
6066  $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
6067  ),
6068  // tree is only built by language=0 pages
6069  $queryBuilder->expr()->eq('sys_language_uid', 0)
6070  )
6071  ->orderBy('sorting');
6072 
6073  if (!empty($moreWhereClauses)) {
6074  $queryBuilder->andWhere(QueryHelper::stripLogicalOperatorPrefix($moreWhereClauses));
6075  }
6076 
6077  $result = $queryBuilder->execute();
6078  while ($row = $result->fetch()) {
6080  $versionState = VersionState::cast($row['t3ver_state']);
6081  $tsfe->sys_page->versionOL('pages', $row);
6082  if ($row === false
6083  || (int)$row['doktype'] === PageRepository::DOKTYPE_RECYCLER
6084  || (int)$row['doktype'] === PageRepository::DOKTYPE_BE_USER_SECTION
6085  || $versionState->indicatesPlaceholder()
6086  ) {
6087  // falsy row means Overlay prevents access to this page.
6088  // Doing this after the overlay to make sure changes
6089  // in the overlay are respected.
6090  // However, we do not process pages below of and
6091  // including of type recycler and BE user section
6092  continue;
6093  }
6094  // Find mount point if any:
6095  $next_id = $row['uid'];
6096  $mount_info = $tsfe->sys_page->getMountPointInfo($next_id, $row);
6097  // Overlay mode:
6098  if (is_array($mount_info) && $mount_info['overlay']) {
6099  $next_id = $mount_info['mount_pid'];
6100  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
6101  ->getQueryBuilderForTable('pages');
6102  $queryBuilder->getRestrictions()
6103  ->removeAll()
6104  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
6105  $queryBuilder->select(...GeneralUtility::trimExplode(',', $allFields, true))
6106  ->from('pages')
6107  ->where(
6108  $queryBuilder->expr()->eq(
6109  'uid',
6110  $queryBuilder->createNamedParameter($next_id, \PDO::PARAM_INT)
6111  )
6112  )
6113  ->orderBy('sorting')
6114  ->setMaxResults(1);
6115 
6116  if (!empty($moreWhereClauses)) {
6117  $queryBuilder->andWhere(QueryHelper::stripLogicalOperatorPrefix($moreWhereClauses));
6118  }
6119 
6120  $row = $queryBuilder->execute()->fetch();
6121  $tsfe->sys_page->versionOL('pages', $row);
6122  if ((int)$row['doktype'] === PageRepository::DOKTYPE_RECYCLER
6123  || (int)$row['doktype'] === PageRepository::DOKTYPE_BE_USER_SECTION
6124  || $versionState->indicatesPlaceholder()
6125  ) {
6126  // Doing this after the overlay to make sure
6127  // changes in the overlay are respected.
6128  // see above
6129  continue;
6130  }
6131  }
6132  // Add record:
6133  if ($dontCheckEnableFields || $tsfe->checkPagerecordForIncludeSection($row)) {
6134  // Add ID to list:
6135  if ($begin <= 0) {
6136  if ($dontCheckEnableFields || $tsfe->checkEnableFields($row)) {
6137  $theList[] = $next_id;
6138  }
6139  }
6140  // Next level:
6141  if ($depth > 1 && !$row['php_tree_stop']) {
6142  // Normal mode:
6143  if (is_array($mount_info) && !$mount_info['overlay']) {
6144  $next_id = $mount_info['mount_pid'];
6145  }
6146  // Call recursively, if the id is not in prevID_array:
6147  if (!in_array($next_id, $prevId_array)) {
6148  $theList = array_merge(
6149  GeneralUtility::intExplode(
6150  ',',
6151  $this->getTreeList(
6152  $next_id,
6153  $depth - 1,
6154  $begin - 1,
6155  $dontCheckEnableFields,
6156  $addSelectFields,
6157  $moreWhereClauses,
6158  $prevId_array,
6159  $recursionLevel + 1
6160  ),
6161  true
6162  ),
6163  $theList
6164  );
6165  }
6166  }
6167  }
6168  }
6169  }
6170  // If first run, check if the ID should be returned:
6171  if (!$recursionLevel) {
6172  if ($addId) {
6173  if ($begin > 0) {
6174  $theList[] = 0;
6175  } else {
6176  $theList[] = $addId;
6177  }
6178  }
6179 
6180  $cacheEntry = [
6181  'md5hash' => $requestHash,
6182  'pid' => $id,
6183  'treelist' => implode(',', $theList),
6184  'tstamp' => ‪$GLOBALS['EXEC_TIME'],
6185  ];
6186 
6187  // Only add to cache if not logged into TYPO3 Backend
6188  if (!$this->getFrontendBackendUser() instanceof ‪AbstractUserAuthentication) {
6189  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('cache_treelist');
6190  try {
6191  $connection->transactional(function ($connection) use ($cacheEntry) {
6192  $connection->insert('cache_treelist', $cacheEntry);
6193  });
6194  } catch (\Throwable $e) {
6195  }
6196  }
6197  }
6198 
6199  return implode(',', $theList);
6200  }
6201 
6211  public function searchWhere($searchWords, $searchFieldList, $searchTable)
6212  {
6213  if (!$searchWords) {
6214  return '';
6215  }
6216 
6217  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
6218  ->getQueryBuilderForTable($searchTable);
6219 
6220  $prefixTableName = $searchTable ? $searchTable . '.' : '';
6221 
6222  $where = $queryBuilder->expr()->andX();
6223  $searchFields = explode(',', $searchFieldList);
6224  $searchWords = preg_split('/[ ,]/', $searchWords);
6225  foreach ($searchWords as $searchWord) {
6226  $searchWord = trim($searchWord);
6227  if (strlen($searchWord) < 3) {
6228  continue;
6229  }
6230  $searchWordConstraint = $queryBuilder->expr()->orX();
6231  $searchWord = $queryBuilder->escapeLikeWildcards($searchWord);
6232  foreach ($searchFields as $field) {
6233  $searchWordConstraint->add(
6234  $queryBuilder->expr()->like($prefixTableName . $field, $queryBuilder->quote('%' . $searchWord . '%'))
6235  );
6236  }
6237 
6238  if ($searchWordConstraint->count()) {
6239  $where->add($searchWordConstraint);
6240  }
6241  }
6242 
6243  if ((string)$where === '') {
6244  return '';
6245  }
6247  return ' AND (' . (string)$where . ')';
6248  }
6249 
6259  public function exec_getQuery($table, $conf)
6260  {
6261  $statement = $this->getQuery($table, $conf);
6262  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
6263 
6264  return $connection->executeQuery($statement);
6265  }
6266 
6276  public function getRecords($tableName, array $queryConfiguration)
6277  {
6278  $records = [];
6279 
6280  $statement = $this->exec_getQuery($tableName, $queryConfiguration);
6281 
6282  $tsfe = $this->getTypoScriptFrontendController();
6283  while ($row = $statement->fetch()) {
6284  // Versioning preview:
6285  $tsfe->sys_page->versionOL($tableName, $row, true);
6286 
6287  // Language overlay:
6288  if (is_array($row)) {
6289  $row = $tsfe->sys_page->getLanguageOverlay($tableName, $row);
6290  }
6291 
6292  // Might be unset in the language overlay
6293  if (is_array($row)) {
6294  $records[] = $row;
6295  }
6296  }
6297 
6298  return $records;
6299  }
6300 
6314  public function getQuery($table, $conf, $returnQueryArray = false)
6315  {
6316  // Resolve stdWrap in these properties first
6317  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
6318  $properties = [
6319  'pidInList',
6320  'uidInList',
6321  'languageField',
6322  'selectFields',
6323  'max',
6324  'begin',
6325  'groupBy',
6326  'orderBy',
6327  'join',
6328  'leftjoin',
6329  'rightjoin',
6330  'recursive',
6331  'where'
6332  ];
6333  foreach ($properties as $property) {
6334  $conf[$property] = trim(
6335  isset($conf[$property . '.'])
6336  ? $this->stdWrap($conf[$property], $conf[$property . '.'])
6337  : $conf[$property]
6338  );
6339  if ($conf[$property] === '') {
6340  unset($conf[$property]);
6341  } elseif (in_array($property, ['languageField', 'selectFields', 'join', 'leftjoin', 'rightjoin', 'where'], true)) {
6342  $conf[$property] = QueryHelper::quoteDatabaseIdentifiers($connection, $conf[$property]);
6343  }
6344  if (isset($conf[$property . '.'])) {
6345  // stdWrapping already done, so remove the sub-array
6346  unset($conf[$property . '.']);
6347  }
6348  }
6349  // Handle PDO-style named parameter markers first
6350  $queryMarkers = $this->getQueryMarkers($table, $conf);
6351  // Replace the markers in the non-stdWrap properties
6352  foreach ($queryMarkers as $marker => $markerValue) {
6353  $properties = [
6354  'uidInList',
6355  'selectFields',
6356  'where',
6357  'max',
6358  'begin',
6359  'groupBy',
6360  'orderBy',
6361  'join',
6362  'leftjoin',
6363  'rightjoin'
6364  ];
6365  foreach ($properties as $property) {
6366  if ($conf[$property]) {
6367  $conf[$property] = str_replace('###' . $marker . '###', $markerValue, $conf[$property]);
6368  }
6369  }
6370  }
6371 
6372  // Construct WHERE clause:
6373  // Handle recursive function for the pidInList
6374  if (isset($conf['recursive'])) {
6375  $conf['recursive'] = (int)$conf['recursive'];
6376  if ($conf['recursive'] > 0) {
6377  $pidList = GeneralUtility::trimExplode(',', $conf['pidInList'], true);
6378  array_walk($pidList, function (&$storagePid) {
6379  if ($storagePid === 'this') {
6380  $storagePid = $this->getTypoScriptFrontendController()->id;
6381  }
6382  if ($storagePid > 0) {
6383  $storagePid = -$storagePid;
6384  }
6385  });
6386  $expandedPidList = [];
6387  foreach ($pidList as $value) {
6388  // Implementation of getTreeList allows to pass the id negative to include
6389  // it into the result otherwise only childpages are returned
6390  $expandedPidList = array_merge(
6391  GeneralUtility::intExplode(',', $this->getTreeList((int)$value, (int)($conf['recursive'] ?? 0))),
6392  $expandedPidList
6393  );
6394  }
6395  $conf['pidInList'] = implode(',', $expandedPidList);
6396  }
6397  }
6398  if ((string)$conf['pidInList'] === '') {
6399  $conf['pidInList'] = 'this';
6400  }
6401 
6402  $queryParts = $this->getQueryConstraints($table, $conf);
6403 
6404  $queryBuilder = $connection->createQueryBuilder();
6405  // @todo Check against getQueryConstraints, can probably use FrontendRestrictions
6406  // @todo here and remove enableFields there.
6407  $queryBuilder->getRestrictions()->removeAll();
6408  $queryBuilder->select('*')->from($table);
6409 
6410  if ($queryParts['where']) {
6411  $queryBuilder->where($queryParts['where']);
6412  }
6413 
6414  if ($queryParts['groupBy']) {
6415  $queryBuilder->groupBy(...$queryParts['groupBy']);
6416  }
6417 
6418  if (is_array($queryParts['orderBy'])) {
6419  foreach ($queryParts['orderBy'] as $orderBy) {
6420  $queryBuilder->addOrderBy(...$orderBy);
6421  }
6422  }
6423 
6424  // Fields:
6425  if ($conf['selectFields']) {
6426  $queryBuilder->selectLiteral($this->sanitizeSelectPart($conf['selectFields'], $table));
6427  }
6428 
6429  // Setting LIMIT:
6430  $error = false;
6431  if ($conf['max'] || $conf['begin']) {
6432  // Finding the total number of records, if used:
6433  if (strpos(strtolower($conf['begin'] . $conf['max']), 'total') !== false) {
6434  $countQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
6435  $countQueryBuilder->getRestrictions()->removeAll();
6436  $countQueryBuilder->count('*')
6437  ->from($table)
6438  ->where($queryParts['where']);
6439 
6440  if ($queryParts['groupBy']) {
6441  $countQueryBuilder->groupBy(...$queryParts['groupBy']);
6442  }
6443 
6444  try {
6445  $count = $countQueryBuilder->execute()->fetchColumn(0);
6446  $conf['max'] = str_ireplace('total', $count, $conf['max']);
6447  $conf['begin'] = str_ireplace('total', $count, $conf['begin']);
6448  } catch (DBALException $e) {
6449  $this->getTimeTracker()->setTSlogMessage($e->getPrevious()->getMessage());
6450  $error = true;
6451  }
6452  }
6453 
6454  if (!$error) {
6455  $conf['begin'] = MathUtility::forceIntegerInRange((int)ceil($this->calc($conf['begin'])), 0);
6456  $conf['max'] = MathUtility::forceIntegerInRange((int)ceil($this->calc($conf['max'])), 0);
6457  if ($conf['begin'] > 0) {
6458  $queryBuilder->setFirstResult($conf['begin']);
6459  }
6460  $queryBuilder->setMaxResults($conf['max'] ?: 100000);
6461  }
6462  }
6463 
6464  if (!$error) {
6465  // Setting up tablejoins:
6466  if ($conf['join']) {
6467  $joinParts = QueryHelper::parseJoin($conf['join']);
6468  $queryBuilder->join(
6469  $table,
6470  $joinParts['tableName'],
6471  $joinParts['tableAlias'],
6472  $joinParts['joinCondition']
6473  );
6474  } elseif ($conf['leftjoin']) {
6475  $joinParts = QueryHelper::parseJoin($conf['leftjoin']);
6476  $queryBuilder->leftJoin(
6477  $table,
6478  $joinParts['tableName'],
6479  $joinParts['tableAlias'],
6480  $joinParts['joinCondition']
6481  );
6482  } elseif ($conf['rightjoin']) {
6483  $joinParts = QueryHelper::parseJoin($conf['rightjoin']);
6484  $queryBuilder->rightJoin(
6485  $table,
6486  $joinParts['tableName'],
6487  $joinParts['tableAlias'],
6488  $joinParts['joinCondition']
6489  );
6490  }
6491 
6492  // Convert the QueryBuilder object into a SQL statement.
6493  $query = $queryBuilder->getSQL();
6494 
6495  // Replace the markers in the queryParts to handle stdWrap enabled properties
6496  foreach ($queryMarkers as $marker => $markerValue) {
6497  // @todo Ugly hack that needs to be cleaned up, with the current architecture
6498  // @todo for exec_Query / getQuery it's the best we can do.
6499  $query = str_replace('###' . $marker . '###', $markerValue, $query);
6500  foreach ($queryParts as $queryPartKey => &$queryPartValue) {
6501  $queryPartValue = str_replace('###' . $marker . '###', $markerValue, $queryPartValue);
6502  }
6503  unset($queryPartValue);
6504  }
6505 
6506  return $returnQueryArray ? $this->getQueryArray($queryBuilder) : $query;
6507  }
6508 
6509  return '';
6510  }
6511 
6520  protected function getQueryArray(QueryBuilder $queryBuilder)
6521  {
6522  $fromClauses = [];
6523  $knownAliases = [];
6524  $queryParts = [];
6525 
6526  // Loop through all FROM clauses
6527  foreach ($queryBuilder->getQueryPart('from') as $from) {
6528  if ($from['alias'] === null) {
6529  $tableSql = $from['table'];
6530  $tableReference = $from['table'];
6531  } else {
6532  $tableSql = $from['table'] . ' ' . $from['alias'];
6533  $tableReference = $from['alias'];
6534  }
6535 
6536  $knownAliases[$tableReference] = true;
6537 
6538  $fromClauses[$tableReference] = $tableSql . $this->‪getQueryArrayJoinHelper(
6539  $tableReference,
6540  $queryBuilder->getQueryPart('join'),
6541  $knownAliases
6542  );
6543  }
6544 
6545  $queryParts['SELECT'] = implode(', ', $queryBuilder->getQueryPart('select'));
6546  $queryParts['FROM'] = implode(', ', $fromClauses);
6547  $queryParts['WHERE'] = (string)$queryBuilder->getQueryPart('where') ?: '';
6548  $queryParts['GROUPBY'] = implode(', ', $queryBuilder->getQueryPart('groupBy'));
6549  $queryParts['ORDERBY'] = implode(', ', $queryBuilder->getQueryPart('orderBy'));
6550  if ($queryBuilder->getFirstResult() > 0) {
6551  $queryParts['LIMIT'] = $queryBuilder->getFirstResult() . ',' . $queryBuilder->getMaxResults();
6552  } elseif ($queryBuilder->getMaxResults() > 0) {
6553  $queryParts['LIMIT'] = $queryBuilder->getMaxResults();
6554  }
6555 
6556  return $queryParts;
6557  }
6558 
6568  protected function getQueryArrayJoinHelper(string $fromAlias, array $joinParts, array &$knownAliases): string
6569  {
6570  $sql = '';
6571 
6572  if (isset($joinParts['join'][$fromAlias])) {
6573  foreach ($joinParts['join'][$fromAlias] as $join) {
6574  if (array_key_exists($join['joinAlias'], $knownAliases)) {
6575  throw new \RuntimeException(
6576  'Non unique join alias: "' . $join['joinAlias'] . '" found.',
6577  1472748872
6578  );
6579  }
6580  $sql .= ' ' . strtoupper($join['joinType'])
6581  . ' JOIN ' . $join['joinTable'] . ' ' . $join['joinAlias']
6582  . ' ON ' . ((string)$join['joinCondition']);
6583  $knownAliases[$join['joinAlias']] = true;
6584  }
6585 
6586  foreach ($joinParts['join'][$fromAlias] as $join) {
6587  $sql .= $this->getQueryArrayJoinHelper($join['joinAlias'], $joinParts, $knownAliases);
6588  }
6589  }
6590 
6591  return $sql;
6592  }
6602  protected function getQueryConstraints(string $table, array $conf): array
6603  {
6604  // Init:
6605  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
6606  $expressionBuilder = $queryBuilder->expr();
6607  $tsfe = $this->getTypoScriptFrontendController();
6608  $constraints = [];
6609  $pid_uid_flag = 0;
6610  $enableFieldsIgnore = [];
6611  $queryParts = [
6612  'where' => null,
6613  'groupBy' => null,
6614  'orderBy' => null,
6615  ];
6616 
6617  $isInWorkspace = GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('workspace', 'isOffline');
6618  $considerMovePlaceholders = (
6619  $isInWorkspace && $table !== 'pages'
6620  && !empty(‪$GLOBALS['TCA'][$table]['ctrl']['versioningWS'])
6621  );
6622 
6623  if (trim($conf['uidInList'])) {
6624  $listArr = GeneralUtility::intExplode(',', str_replace('this', (string)$tsfe->contentPid, $conf['uidInList']));
6625 
6626  // If move placeholder shall be considered, select via t3ver_move_id
6627  if ($considerMovePlaceholders) {
6628  $constraints[] = (string)$expressionBuilder->orX(
6629  $expressionBuilder->in($table . '.uid', $listArr),
6630  $expressionBuilder->andX(
6631  $expressionBuilder->eq(
6632  $table . '.t3ver_state',
6633  (int)(string)VersionState::cast(VersionState::MOVE_PLACEHOLDER)
6634  ),
6635  $expressionBuilder->in($table . '.t3ver_move_id', $listArr)
6636  )
6637  );
6638  } else {
6639  $constraints[] = (string)$expressionBuilder->in($table . '.uid', $listArr);
6640  }
6641  $pid_uid_flag++;
6642  }
6643 
6644  // Static_* tables are allowed to be fetched from root page
6645  if (strpos($table, 'static_') === 0) {
6646  $pid_uid_flag++;
6647  }
6648 
6649  if (trim($conf['pidInList'])) {
6650  $listArr = GeneralUtility::intExplode(',', str_replace('this', (string)$tsfe->contentPid, $conf['pidInList']));
6651  // Removes all pages which are not visible for the user!
6652  $listArr = $this->checkPidArray($listArr);
6653  if (GeneralUtility::inList($conf['pidInList'], 'root')) {
6654  $listArr[] = 0;
6655  }
6656  if (GeneralUtility::inList($conf['pidInList'], '-1')) {
6657  $listArr[] = -1;
6658  $enableFieldsIgnore['pid'] = true;
6659  }
6660  if (!empty($listArr)) {
6661  $constraints[] = $expressionBuilder->in($table . '.pid', array_map('intval', $listArr));
6662  $pid_uid_flag++;
6663  } else {
6664  // If not uid and not pid then uid is set to 0 - which results in nothing!!
6665  $pid_uid_flag = 0;
6666  }
6667  }
6668 
6669  // If not uid and not pid then uid is set to 0 - which results in nothing!!
6670  if (!$pid_uid_flag) {
6671  $constraints[] = $expressionBuilder->eq($table . '.uid', 0);
6672  }
6673 
6674  $where = isset($conf['where.']) ? trim($this->stdWrap($conf['where'], $conf['where.'])) : trim($conf['where']);
6675  if ($where) {
6676  $constraints[] = QueryHelper::stripLogicalOperatorPrefix($where);
6677  }
6678 
6679  // Check if the default language should be fetched (= doing overlays), or if only the records of a language should be fetched
6680  // but only do this for TCA tables that have languages enabled
6681  $languageConstraint = $this->getLanguageRestriction($expressionBuilder, $table, $conf, GeneralUtility::makeInstance(Context::class));
6682  if ($languageConstraint !== null) {
6683  $constraints[] = $languageConstraint;
6684  }
6685 
6686  // Enablefields
6687  if ($table === 'pages') {
6688  $constraints[] = QueryHelper::stripLogicalOperatorPrefix($tsfe->sys_page->where_hid_del);
6689  $constraints[] = QueryHelper::stripLogicalOperatorPrefix($tsfe->sys_page->where_groupAccess);
6690  } else {
6691  $constraints[] = QueryHelper::stripLogicalOperatorPrefix($tsfe->sys_page->enableFields($table, -1, $enableFieldsIgnore));
6692  }
6693 
6694  // MAKE WHERE:
6695  if (count($constraints) !== 0) {
6696  $queryParts['where'] = $expressionBuilder->andX(...$constraints);
6697  }
6698  // GROUP BY
6699  if (trim($conf['groupBy'])) {
6700  $groupBy = isset($conf['groupBy.'])
6701  ? trim($this->stdWrap($conf['groupBy'], $conf['groupBy.']))
6702  : trim($conf['groupBy']);
6703  $queryParts['groupBy'] = QueryHelper::parseGroupBy($groupBy);
6704  }
6705 
6706  // ORDER BY
6707  if (trim($conf['orderBy'])) {
6708  $orderByString = isset($conf['orderBy.'])
6709  ? trim($this->stdWrap($conf['orderBy'], $conf['orderBy.']))
6710  : trim($conf['orderBy']);
6711 
6712  $queryParts['orderBy'] = QueryHelper::parseOrderBy($orderByString);
6713  }
6714 
6715  // Return result:
6716  return $queryParts;
6717  }
6718 
6745  protected function getLanguageRestriction(‪ExpressionBuilder $expressionBuilder, string $table, array $conf, ‪Context $context)
6746  {
6747  $languageField = '';
6748  $localizationParentField = ‪$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] ?? null;
6749  // Check if the table is translatable, and set the language field by default from the TCA information
6750  if (!empty($conf['languageField']) || !isset($conf['languageField'])) {
6751  if (isset($conf['languageField']) && !empty(‪$GLOBALS['TCA'][$table]['columns'][$conf['languageField']])) {
6752  $languageField = $conf['languageField'];
6753  } elseif (!empty(‪$GLOBALS['TCA'][$table]['ctrl']['languageField']) && !empty($localizationParentField)) {
6754  $languageField = $table . '.' . ‪$GLOBALS['TCA'][$table]['ctrl']['languageField'];
6755  }
6756  }
6757 
6758  // No language restriction enabled explicitly or available via TCA
6759  if (empty($languageField)) {
6760  return null;
6761  }
6762 
6764  $languageAspect = $context->‪getAspect('language');
6765  if ($languageAspect->doOverlays() && !empty($localizationParentField)) {
6766  // Sys language content is set to zero/-1 - and it is expected that whatever routine processes the output will
6767  // OVERLAY the records with localized versions!
6768  $languageQuery = $expressionBuilder->‪in($languageField, [0, -1]);
6769  // Use this option to include records that don't have a default language counterpart ("free mode")
6770  // (originalpointerfield is 0 and the language field contains the requested language)
6771  if (isset($conf['includeRecordsWithoutDefaultTranslation']) || $conf['includeRecordsWithoutDefaultTranslation.']) {
6772  $includeRecordsWithoutDefaultTranslation = isset($conf['includeRecordsWithoutDefaultTranslation.']) ?
6773  $this->stdWrap($conf['includeRecordsWithoutDefaultTranslation'], $conf['includeRecordsWithoutDefaultTranslation.']) : $conf['includeRecordsWithoutDefaultTranslation'];
6774  $includeRecordsWithoutDefaultTranslation = trim($includeRecordsWithoutDefaultTranslation) !== '';
6775  } else {
6776  // Option was not explicitly set, check what's in for the language overlay type.
6777  $includeRecordsWithoutDefaultTranslation = $languageAspect->getOverlayType() === $languageAspect::OVERLAYS_ON_WITH_FLOATING;
6778  }
6779  if ($includeRecordsWithoutDefaultTranslation) {
6780  $languageQuery = $expressionBuilder->‪orX(
6781  $languageQuery,
6782  $expressionBuilder->‪andX(
6783  $expressionBuilder->‪eq($table . '.' . $localizationParentField, 0),
6784  $expressionBuilder->‪eq($languageField, $languageAspect->getContentId())
6785  )
6786  );
6787  }
6788  return $languageQuery;
6789  }
6790  // No overlays = only fetch records given for the requested language and "all languages"
6791  return $expressionBuilder->‪in($languageField, [$languageAspect->getContentId(), -1]);
6792  }
6793 
6806  protected function sanitizeSelectPart($selectPart, $table)
6807  {
6808  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
6809 
6810  // Pattern matching parts
6811  $matchStart = '/(^\\s*|,\\s*|' . $table . '\\.)';
6812  $matchEnd = '(\\s*,|\\s*$)/';
6813  $necessaryFields = ['uid', 'pid'];
6814  $wsFields = ['t3ver_state'];
6815  if (isset(‪$GLOBALS['TCA'][$table]) && !preg_match($matchStart . '\\*' . $matchEnd, $selectPart) && !preg_match('/(count|max|min|avg|sum)\\([^\\)]+\\)|distinct/i', $selectPart)) {
6816  foreach ($necessaryFields as $field) {
6817  $match = $matchStart . $field . $matchEnd;
6818  if (!preg_match($match, $selectPart)) {
6819  $selectPart .= ', ' . $connection->quoteIdentifier($table . '.' . $field) . ' AS ' . $connection->quoteIdentifier($field);
6820  }
6821  }
6822  if (‪$GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
6823  foreach ($wsFields as $field) {
6824  $match = $matchStart . $field . $matchEnd;
6825  if (!preg_match($match, $selectPart)) {
6826  $selectPart .= ', ' . $connection->quoteIdentifier($table . '.' . $field) . ' AS ' . $connection->quoteIdentifier($field);
6827  }
6828  }
6829  }
6830  }
6831  return $selectPart;
6832  }
6833 
6841  public function checkPidArray($pageIds)
6842  {
6843  if (!is_array($pageIds) || empty($pageIds)) {
6844  return [];
6845  }
6846  $restrictionContainer = GeneralUtility::makeInstance(FrontendRestrictionContainer::class);
6847  $restrictionContainer->add(GeneralUtility::makeInstance(
6848  DocumentTypeExclusionRestriction::class,
6849  GeneralUtility::intExplode(',', (string)$this->checkPid_badDoktypeList, true)
6850  ));
6851  return $this->getTypoScriptFrontendController()->sys_page->filterAccessiblePageIds($pageIds, $restrictionContainer);
6852  }
6853 
6864  public function getQueryMarkers($table, $conf)
6865  {
6866  if (!is_array($conf['markers.'])) {
6867  return [];
6868  }
6869  // Parse markers and prepare their values
6870  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
6871  $markerValues = [];
6872  foreach ($conf['markers.'] as $dottedMarker => $dummy) {
6873  $marker = rtrim($dottedMarker, '.');
6874  if ($dottedMarker != $marker . '.') {
6875  continue;
6876  }
6877  // Parse definition
6878  $tempValue = isset($conf['markers.'][$dottedMarker])
6879  ? $this->stdWrap($conf['markers.'][$dottedMarker]['value'], $conf['markers.'][$dottedMarker])
6880  : $conf['markers.'][$dottedMarker]['value'];
6881  // Quote/escape if needed
6882  if (is_numeric($tempValue)) {
6883  if ((int)$tempValue == $tempValue) {
6884  // Handle integer
6885  $markerValues[$marker] = (int)$tempValue;
6886  } else {
6887  // Handle float
6888  $markerValues[$marker] = (float)$tempValue;
6889  }
6890  } elseif ($tempValue === null) {
6891  // It represents NULL
6892  $markerValues[$marker] = 'NULL';
6893  } elseif (!empty($conf['markers.'][$dottedMarker]['commaSeparatedList'])) {
6894  // See if it is really a comma separated list of values
6895  $explodeValues = GeneralUtility::trimExplode(',', $tempValue);
6896  if (count($explodeValues) > 1) {
6897  // Handle each element of list separately
6898  $tempArray = [];
6899  foreach ($explodeValues as $listValue) {
6900  if (is_numeric($listValue)) {
6901  if ((int)$listValue == $listValue) {
6902  $tempArray[] = (int)$listValue;
6903  } else {
6904  $tempArray[] = (float)$listValue;
6905  }
6906  } else {
6907  // If quoted, remove quotes before
6908  // escaping.
6909  if (preg_match('/^\'([^\']*)\'$/', $listValue, $matches)) {
6910  $listValue = $matches[1];
6911  } elseif (preg_match('/^\\"([^\\"]*)\\"$/', $listValue, $matches)) {
6912  $listValue = $matches[1];
6913  }
6914  $tempArray[] = $connection->quote($listValue);
6915  }
6916  }
6917  $markerValues[$marker] = implode(',', $tempArray);
6918  } else {
6919  // Handle remaining values as string
6920  $markerValues[$marker] = $connection->quote($tempValue);
6921  }
6922  } else {
6923  // Handle remaining values as string
6924  $markerValues[$marker] = $connection->quote($tempValue);
6925  }
6926  }
6927  return $markerValues;
6928  }
6929 
6930  /***********************************************
6931  *
6932  * Frontend editing functions
6933  *
6934  ***********************************************/
6946  public function editPanel($content, $conf, $currentRecord = '', $dataArray = [])
6947  {
6948  if (!$this->getTypoScriptFrontendController()->isBackendUserLoggedIn()) {
6949  return $content;
6950  }
6951  if (!$this->getTypoScriptFrontendController()->displayEditIcons) {
6952  return $content;
6953  }
6954 
6955  if (!$currentRecord) {
6956  $currentRecord = $this->currentRecord;
6957  }
6958  if (empty($dataArray)) {
6959  $dataArray = $this->data;
6960  }
6961 
6962  if ($conf['newRecordFromTable']) {
6963  $currentRecord = $conf['newRecordFromTable'] . ':NEW';
6964  $conf['allow'] = 'new';
6965  $checkEditAccessInternals = false;
6966  } else {
6967  $checkEditAccessInternals = true;
6968  }
6969  [$table, $uid] = explode(':', $currentRecord);
6970  // Page ID for new records, 0 if not specified
6971  $newRecordPid = (int)$conf['newRecordInPid'];
6972  $newUid = null;
6973  if (!$conf['onlyCurrentPid'] || $dataArray['pid'] == $this->getTypoScriptFrontendController()->id) {
6974  if ($table === 'pages') {
6975  $newUid = $uid;
6976  } else {
6977  if ($conf['newRecordFromTable']) {
6978  $newUid = $this->getTypoScriptFrontendController()->id;
6979  if ($newRecordPid) {
6980  $newUid = $newRecordPid;
6981  }
6982  } else {
6983  $newUid = -1 * $uid;
6984  }
6985  }
6986  }
6987  if ($table && $this->getFrontendBackendUser()->allowedToEdit($table, $dataArray, $conf, $checkEditAccessInternals) && $this->getFrontendBackendUser()->allowedToEditLanguage($table, $dataArray)) {
6988  $editClass = ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/classes/class.frontendedit.php']['edit'];
6989  if ($editClass) {
6990  $edit = GeneralUtility::makeInstance($editClass);
6991  $allowedActions = $this->getFrontendBackendUser()->getAllowedEditActions($table, $conf, $dataArray['pid']);
6992  $content = $edit->editPanel($content, $conf, $currentRecord, $dataArray, $table, $allowedActions, $newUid, []);
6993  }
6994  }
6995  return $content;
6996  }
6997 
7010  public function editIcons($content, $params, array $conf = [], $currentRecord = '', $dataArray = [], $addUrlParamStr = '')
7011  {
7012  if (!$this->getTypoScriptFrontendController()->isBackendUserLoggedIn()) {
7013  return $content;
7014  }
7015  if (!$this->getTypoScriptFrontendController()->displayFieldEditIcons) {
7016  return $content;
7017  }
7018  if (!$currentRecord) {
7019  $currentRecord = $this->currentRecord;
7020  }
7021  if (empty($dataArray)) {
7022  $dataArray = $this->data;
7023  }
7024  // Check incoming params:
7025  [$currentRecordTable, $currentRecordUID] = explode(':', $currentRecord);
7026  [$fieldList, $table] = array_reverse(GeneralUtility::trimExplode(':', $params, true));
7027  // Reverse the array because table is optional
7028  if (!$table) {
7029  $table = $currentRecordTable;
7030  } elseif ($table != $currentRecordTable) {
7031  // If the table is set as the first parameter, and does not match the table of the current record, then just return.
7032  return $content;
7033  }
7034 
7035  $editUid = $dataArray['_LOCALIZED_UID'] ?: $currentRecordUID;
7036  // Edit icons imply that the editing action is generally allowed, assuming page and content element permissions permit it.
7037  if (!array_key_exists('allow', $conf)) {
7038  $conf['allow'] = 'edit';
7039  }
7040  if ($table && $this->getFrontendBackendUser()->allowedToEdit($table, $dataArray, $conf, true) && $fieldList && $this->getFrontendBackendUser()->allowedToEditLanguage($table, $dataArray)) {
7041  $editClass = ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/classes/class.frontendedit.php']['edit'];
7042  if ($editClass) {
7043  $edit = GeneralUtility::makeInstance($editClass);
7044  $content = $edit->editIcons($content, $params, $conf, $currentRecord, $dataArray, $addUrlParamStr, $table, $editUid, $fieldList);
7045  }
7046  }
7047  return $content;
7048  }
7049 
7059  public function isDisabled($table, $row)
7060  {
7061  $tsfe = $this->getTypoScriptFrontendController();
7062  $enablecolumns = ‪$GLOBALS['TCA'][$table]['ctrl']['enablecolumns'];
7063  return $enablecolumns['disabled'] && $row[$enablecolumns['disabled']]
7064  || $enablecolumns['fe_group'] && $tsfe->simUserGroup && (int)$row[$enablecolumns['fe_group']] === (int)$tsfe->simUserGroup
7065  || $enablecolumns['starttime'] && $row[$enablecolumns['starttime']] > ‪$GLOBALS['EXEC_TIME']
7066  || $enablecolumns['endtime'] && $row[$enablecolumns['endtime']] && $row[$enablecolumns['endtime']] < ‪$GLOBALS['EXEC_TIME'];
7067  }
7074  protected function getResourceFactory()
7075  {
7076  return GeneralUtility::makeInstance(ResourceFactory::class);
7077  }
7078 
7086  protected function getEnvironmentVariable($key)
7087  {
7088  return GeneralUtility::getIndpEnv($key);
7089  }
7090 
7098  protected function getFromCache(array $configuration)
7099  {
7100  $content = false;
7101 
7102  if ($this->getTypoScriptFrontendController()->no_cache) {
7103  return $content;
7104  }
7105  $cacheKey = $this->calculateCacheKey($configuration);
7106  if (!empty($cacheKey)) {
7108  $cacheFrontend = GeneralUtility::makeInstance(CacheManager::class)
7109  ->getCache('hash');
7110  $content = $cacheFrontend->get($cacheKey);
7111  }
7112  return $content;
7113  }
7114 
7121  protected function calculateCacheLifetime(array $configuration)
7122  {
7123  $lifetimeConfiguration = $configuration['lifetime'] ?? '';
7124  $lifetimeConfiguration = isset($configuration['lifetime.'])
7125  ? $this->stdWrap($lifetimeConfiguration, $configuration['lifetime.'])
7126  : $lifetimeConfiguration;
7127 
7128  $lifetime = null; // default lifetime
7129  if (strtolower($lifetimeConfiguration) === 'unlimited') {
7130  $lifetime = 0; // unlimited
7131  } elseif ($lifetimeConfiguration > 0) {
7132  $lifetime = (int)$lifetimeConfiguration; // lifetime in seconds
7133  }
7134  return $lifetime;
7135  }
7136 
7143  protected function calculateCacheTags(array $configuration)
7144  {
7145  $tags = $configuration['tags'] ?? '';
7146  $tags = isset($configuration['tags.'])
7147  ? $this->stdWrap($tags, $configuration['tags.'])
7148  : $tags;
7149  return empty($tags) ? [] : GeneralUtility::trimExplode(',', $tags);
7150  }
7151 
7158  protected function calculateCacheKey(array $configuration)
7159  {
7160  $key = $configuration['key'] ?? '';
7161  return isset($configuration['key.'])
7162  ? $this->stdWrap($key, $configuration['key.'])
7163  : $key;
7164  }
7165 
7171  protected function getFrontendBackendUser()
7172  {
7173  return ‪$GLOBALS['BE_USER'];
7174  }
7175 
7179  protected function getTimeTracker()
7180  {
7181  return GeneralUtility::makeInstance(TimeTracker::class);
7182  }
7183 
7187  protected function getTypoScriptFrontendController()
7188  {
7189  return $this->typoScriptFrontendController ?: ‪$GLOBALS['TSFE'];
7190  }
7201  protected function resolveAnchorLink(string $linkText, array $conf): string
7202  {
7203  $anchorTag = '<a ' . $this->getATagParams($conf) . '>';
7204  $aTagParams = GeneralUtility::get_tag_attributes($anchorTag);
7205  // If it looks like a anchor tag, render it anyway
7206  if (isset($aTagParams['id']) || isset($aTagParams['name'])) {
7207  return $anchorTag . $linkText . '</a>';
7208  }
7209  // Otherwise just return the link text
7210  return $linkText;
7211  }
7212 
7221  protected function getContentLengthOfCurrentTag(string $theValue, int $pointer, string $currentTag): int
7222  {
7223  $tempContent = strtolower(substr($theValue, $pointer));
7224  $startTag = '<' . $currentTag;
7225  $endTag = '</' . $currentTag . '>';
7226  $offsetCount = 0;
7227 
7228  // Take care for nested tags
7229  do {
7230  $nextMatchingEndTagPosition = strpos($tempContent, $endTag);
7231  // only match tag `a` in `<a href"...">` but not in `<abbr>`
7232  $nextSameTypeTagPosition = preg_match(
7233  '#' . $startTag . '[\s/>]#',
7234  $tempContent,
7235  $nextSameStartTagMatches,
7236  PREG_OFFSET_CAPTURE
7237  ) ? $nextSameStartTagMatches[0][1] : false;
7238 
7239  // filter out nested tag contents to help getting the correct closing tag
7240  if ($nextMatchingEndTagPosition !== false && $nextSameTypeTagPosition !== false && $nextSameTypeTagPosition < $nextMatchingEndTagPosition) {
7241  $lastOpeningTagStartPosition = (int)strrpos(substr($tempContent, 0, $nextMatchingEndTagPosition), $startTag);
7242  $closingTagEndPosition = $nextMatchingEndTagPosition + strlen($endTag);
7243  $offsetCount += $closingTagEndPosition - $lastOpeningTagStartPosition;
7244 
7245  // replace content from latest tag start to latest tag end
7246  $tempContent = substr($tempContent, 0, $lastOpeningTagStartPosition) . substr($tempContent, $closingTagEndPosition);
7247  }
7248  } while (
7249  ($nextMatchingEndTagPosition !== false && $nextSameTypeTagPosition !== false) &&
7250  $nextSameTypeTagPosition < $nextMatchingEndTagPosition
7251  );
7252 
7253  // if no closing tag is found we use length of the whole content
7254  $endingOffset = strlen($tempContent);
7255  if ($nextMatchingEndTagPosition !== false) {
7256  $endingOffset = $nextMatchingEndTagPosition + $offsetCount;
7257  }
7258 
7259  return $endingOffset;
7260  }
7261 
7262  protected function shallDebug(): bool
7263  {
7264  $tsfe = $this->getTypoScriptFrontendController();
7265  if ($tsfe !== null && isset($tsfe->config['config']['debug'])) {
7266  return (bool)($tsfe->config['config']['debug']);
7267  }
7268  return !empty(‪$GLOBALS['TYPO3_CONF_VARS']['FE']['debug']);
7269  }
7270 }
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\getQueryPart
‪mixed getQueryPart(string $queryPartName)
Definition: QueryBuilder.php:870
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_noTrimWrap
‪string stdWrap_noTrimWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:2687
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$parentRecordNumber
‪int $parentRecordNumber
Definition: ContentObjectRenderer.php:339
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\http_makelinks
‪string http_makelinks($data, $conf)
Definition: ContentObjectRenderer.php:4245
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_case
‪string stdWrap_case($content='', $conf=[])
Definition: ContentObjectRenderer.php:2393
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_htmlSpecialChars
‪string stdWrap_htmlSpecialChars($content='', $conf=[])
Definition: ContentObjectRenderer.php:2483
‪TYPO3\CMS\Core\Utility\GeneralUtility\xml2array
‪static mixed xml2array($string, $NSprefix='', $reportDocTag=false)
Definition: GeneralUtility.php:1531
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectStdWrapHookInterface
Definition: ContentObjectStdWrapHookInterface.php:22
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_editIcons
‪string stdWrap_editIcons($content='', $conf=[])
Definition: ContentObjectRenderer.php:2884
‪TYPO3\CMS\Core\Database\Query\Restriction\DocumentTypeExclusionRestriction
Definition: DocumentTypeExclusionRestriction.php:27
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\shallDebug
‪shallDebug()
Definition: ContentObjectRenderer.php:7232
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\setCurrentFile
‪setCurrentFile($fileObject)
Definition: ContentObjectRenderer.php:1559
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_expandList
‪string stdWrap_expandList($content='')
Definition: ContentObjectRenderer.php:2310
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getFileDataKey
‪string int getFileDataKey($key)
Definition: ContentObjectRenderer.php:4874
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\OBJECTTYPE_USER
‪const OBJECTTYPE_USER
Definition: ContentObjectRenderer.php:436
‪TYPO3\CMS\Core\Page\AssetCollector
Definition: AssetCollector.php:44
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_cacheRead
‪string stdWrap_cacheRead($content='', $conf=[])
Definition: ContentObjectRenderer.php:1725
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getCurrentTable
‪string getCurrentTable()
Definition: ContentObjectRenderer.php:567
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getImageSourceCollection
‪string getImageSourceCollection($layoutKey, $conf, $file)
Definition: ContentObjectRenderer.php:1147
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getTypoScriptFrontendController
‪TYPO3 CMS Frontend Controller TypoScriptFrontendController getTypoScriptFrontendController()
Definition: ContentObjectRenderer.php:7157
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\mailto_makelinks
‪string mailto_makelinks($data, $conf)
Definition: ContentObjectRenderer.php:4322
‪TYPO3\CMS\Frontend\Http\UrlProcessorInterface\CONTEXT_COMMON
‪const CONTEXT_COMMON
Definition: UrlProcessorInterface.php:28
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_ifNull
‪string stdWrap_ifNull($content='', $conf=[])
Definition: ContentObjectRenderer.php:1949
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$contentObjectClassMap
‪array $contentObjectClassMap
Definition: ContentObjectRenderer.php:278
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
Definition: ExpressionBuilder.php:35
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_editPanel
‪string stdWrap_editPanel($content='', $conf=[])
Definition: ContentObjectRenderer.php:2903
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger($var)
Definition: MathUtility.php:74
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getContentLengthOfCurrentTag
‪int getContentLengthOfCurrentTag(string $theValue, int $pointer, string $currentTag)
Definition: ContentObjectRenderer.php:7191
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getQueryArrayJoinHelper
‪string getQueryArrayJoinHelper(string $fromAlias, array $joinParts, array &$knownAliases)
Definition: ContentObjectRenderer.php:6538
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_insertData
‪string stdWrap_insertData($content='')
Definition: ContentObjectRenderer.php:2816
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:180
‪TYPO3\CMS\Core\Utility\StringUtility\endsWith
‪static bool endsWith($haystack, $needle)
Definition: StringUtility.php:61
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getUserObjectType
‪mixed getUserObjectType()
Definition: ContentObjectRenderer.php:907
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$recordRegister
‪array $recordRegister
Definition: ContentObjectRenderer.php:371
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_orderedStdWrap
‪string stdWrap_orderedStdWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:2787
‪TYPO3\CMS\Core\Resource\FileInterface
Definition: FileInterface.php:22
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_csConv
‪string stdWrap_csConv($content='', $conf=[])
Definition: ContentObjectRenderer.php:2146
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\mergeTSRef
‪array mergeTSRef($confArr, $prop)
Definition: ContentObjectRenderer.php:5897
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\round
‪string round($content, array $conf=[])
Definition: ContentObjectRenderer.php:3682
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getResourceFactory
‪ResourceFactory getResourceFactory()
Definition: ContentObjectRenderer.php:7044
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\encaps_lineSplit
‪string encaps_lineSplit($theValue, $conf)
Definition: ContentObjectRenderer.php:4126
‪TYPO3\CMS\Core\Html\HtmlParser
Definition: HtmlParser.php:27
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\start
‪start($data, $table='')
Definition: ContentObjectRenderer.php:533
‪TYPO3\CMS\Frontend\ContentObject\ImageContentObject
Definition: ImageContentObject.php:29
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\imageLinkWrap
‪string imageLinkWrap($string, $imageFile, $conf)
Definition: ContentObjectRenderer.php:1279
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap
‪string stdWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:1590
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\substring
‪string substring($content, $options)
Definition: ContentObjectRenderer.php:3258
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\eq
‪string eq(string $fieldName, $value)
Definition: ExpressionBuilder.php:109
‪TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser
Definition: TypoScriptParser.php:37
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$cObjHookObjectsRegistry
‪array $cObjHookObjectsRegistry
Definition: ContentObjectRenderer.php:378
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_listNum
‪string stdWrap_listNum($content='', $conf=[])
Definition: ContentObjectRenderer.php:1998
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_prefixComment
‪string stdWrap_prefixComment($content='', $conf=[])
Definition: ContentObjectRenderer.php:2865
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\setUserObjectType
‪setUserObjectType($userObjectType)
Definition: ContentObjectRenderer.php:917
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_wrap
‪string stdWrap_wrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:2669
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\determineExceptionHandlerClassName
‪string null determineExceptionHandlerClassName($configuration)
Definition: ContentObjectRenderer.php:855
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$currentFile
‪File FileReference Folder null $currentFile
Definition: ContentObjectRenderer.php:399
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_replacement
‪string stdWrap_replacement($content='', $conf=[])
Definition: ContentObjectRenderer.php:2208
‪TYPO3\CMS\Core\Imaging\ImageManipulation\Area
Definition: Area.php:23
‪TYPO3\CMS\Core\Resource\ProcessedFile\CONTEXT_IMAGECROPSCALEMASK
‪const CONTEXT_IMAGECROPSCALEMASK
Definition: ProcessedFile.php:58
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getSite
‪getSite()
Definition: TypoScriptFrontendController.php:3971
‪TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException
Definition: MissingArrayPathException.php:28
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$currentRecord
‪string $currentRecord
Definition: ContentObjectRenderer.php:321
‪TYPO3
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\cropHTML
‪string cropHTML($content, $options)
Definition: ContentObjectRenderer.php:3316
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$doConvertToUserIntObject
‪bool $doConvertToUserIntObject
Definition: ContentObjectRenderer.php:404
‪TYPO3\CMS\Core\Resource\FileReference\getProperty
‪mixed getProperty($key)
Definition: FileReference.php:118
‪TYPO3\CMS\Frontend\ContentObject
Definition: AbstractContentObject.php:16
‪TYPO3\CMS\Frontend\Http\UrlProcessorInterface
Definition: UrlProcessorInterface.php:27
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\uniqueHash
‪string uniqueHash($str='')
Definition: TypoScriptFrontendController.php:3492
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\sendNotifyEmail
‪bool sendNotifyEmail($message, $recipients, $cc, $senderAddress, $senderName='', $replyTo='')
Definition: ContentObjectRenderer.php:5843
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getTypoLink_URL
‪string getTypoLink_URL($params, $urlParameters=[], $target='')
Definition: ContentObjectRenderer.php:5422
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\setParent
‪setParent($data, $currentRecord)
Definition: ContentObjectRenderer.php:601
‪TYPO3\CMS\Frontend\Resource\FilePathSanitizer
Definition: FilePathSanitizer.php:39
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_prepend
‪string stdWrap_prepend($content='', $conf=[])
Definition: ContentObjectRenderer.php:2743
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$alternativeData
‪string $alternativeData
Definition: ContentObjectRenderer.php:304
‪TYPO3\CMS\Core\Mail\MailMessage
Definition: MailMessage.php:28
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_stdWrap
‪string stdWrap_stdWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:2060
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$stdWrapHookObjects
‪array $stdWrapHookObjects
Definition: ContentObjectRenderer.php:389
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getCurrentFile
‪File getCurrentFile()
Definition: ContentObjectRenderer.php:1569
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\setCurrentVal
‪setCurrentVal($value)
Definition: ContentObjectRenderer.php:633
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\setContentObjectClassMap
‪setContentObjectClassMap(array $contentObjectClassMap)
Definition: ContentObjectRenderer.php:505
‪TYPO3\CMS\Core\Resource\FileReference
Definition: FileReference.php:33
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\HTMLcaseshift
‪string HTMLcaseshift($theValue, $case)
Definition: ContentObjectRenderer.php:5774
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectGetImageResourceHookInterface
Definition: ContentObjectGetImageResourceHookInterface.php:22
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\getMaxResults
‪int getMaxResults()
Definition: QueryBuilder.php:368
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$checkPid_badDoktypeList
‪string int $checkPid_badDoktypeList
Definition: ContentObjectRenderer.php:349
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\typoLink
‪string typoLink($linkText, $conf)
Definition: ContentObjectRenderer.php:5088
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\extLinkATagParams
‪string extLinkATagParams($URL, $TYPE)
Definition: ContentObjectRenderer.php:1535
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$stdWrapOrder
‪string[] $stdWrapOrder
Definition: ContentObjectRenderer.php:117
‪TYPO3\CMS\Frontend\ContentObject\Exception\ExceptionHandlerInterface
Definition: ExceptionHandlerInterface.php:24
‪TYPO3\CMS\Core\Localization\Locales
Definition: Locales.php:30
‪TYPO3\CMS\Core\Utility\ArrayUtility\mergeRecursiveWithOverrule
‪static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
Definition: ArrayUtility.php:654
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_round
‪string stdWrap_round($content='', $conf=[])
Definition: ContentObjectRenderer.php:2285
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$currentRecordNumber
‪int $currentRecordNumber
Definition: ContentObjectRenderer.php:333
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_stripHtml
‪string stdWrap_stripHtml($content='')
Definition: ContentObjectRenderer.php:2444
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_HTMLparser
‪string stdWrap_HTMLparser($content='', $conf=[])
Definition: ContentObjectRenderer.php:2178
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_lang
‪string stdWrap_lang($content='', $conf=[])
Definition: ContentObjectRenderer.php:1788
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\registerContentObjectClass
‪registerContentObjectClass($className, $contentObjectName)
Definition: ContentObjectRenderer.php:520
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_br
‪string stdWrap_br($content='')
Definition: ContentObjectRenderer.php:2526
‪TYPO3\CMS\Frontend\ContentObject\Exception\ContentRenderingException
Definition: ContentRenderingException.php:25
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_wrapAlign
‪string stdWrap_wrapAlign($content='', $conf=[])
Definition: ContentObjectRenderer.php:2633
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getEnvironmentVariable
‪string getEnvironmentVariable($key)
Definition: ContentObjectRenderer.php:7056
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getCropAreaFromFileReference
‪Area null getCropAreaFromFileReference(FileReference $fileReference, array $fileArray)
Definition: ContentObjectRenderer.php:4536
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_split
‪string stdWrap_split($content='', $conf=[])
Definition: ContentObjectRenderer.php:2195
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getImageTagTemplate
‪string getImageTagTemplate($layoutKey, $conf)
Definition: ContentObjectRenderer.php:1123
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:53
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\_parseFunc
‪string _parseFunc($theValue, $conf)
Definition: ContentObjectRenderer.php:3875
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_numRows
‪string stdWrap_numRows($content='', $conf=[])
Definition: ContentObjectRenderer.php:1875
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_cacheStore
‪string stdWrap_cacheStore($content='', $conf=[])
Definition: ContentObjectRenderer.php:2934
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getTypoLink
‪string getTypoLink($label, $params, $urlParameters=[], $target='')
Definition: ContentObjectRenderer.php:5370
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$getImgResourceHookObjects
‪array $getImgResourceHookObjects
Definition: ContentObjectRenderer.php:395
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_stdWrapProcess
‪string stdWrap_stdWrapProcess($content='', $conf=[])
Definition: ContentObjectRenderer.php:2074
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_if
‪string stdWrap_if($content='', $conf=[])
Definition: ContentObjectRenderer.php:2109
‪TYPO3\CMS\Core\Core\Environment\getContext
‪static ApplicationContext getContext()
Definition: Environment.php:133
‪TYPO3\CMS\Core\Database\Query\QueryBuilder
Definition: QueryBuilder.php:52
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$container
‪ContainerInterface $container
Definition: ContentObjectRenderer.php:102
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getUrlToCurrentLocation
‪string getUrlToCurrentLocation($addQueryString=true)
Definition: ContentObjectRenderer.php:5397
‪TYPO3\CMS\Core\Service\FlexFormService
Definition: FlexFormService.php:25
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_stdWrapPreProcess
‪string stdWrap_stdWrapPreProcess($content='', $conf=[])
Definition: ContentObjectRenderer.php:1709
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\wrap
‪string wrap($content, $wrap, $char='|')
Definition: ContentObjectRenderer.php:5630
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getLanguageRestriction
‪string TYPO3 CMS Core Database Query Expression CompositeExpression null getLanguageRestriction(ExpressionBuilder $expressionBuilder, string $table, array $conf, Context $context)
Definition: ContentObjectRenderer.php:6715
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_brTag
‪string stdWrap_brTag($content='', $conf=[])
Definition: ContentObjectRenderer.php:2539
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\cImage
‪string cImage($file, $conf)
Definition: ContentObjectRenderer.php:1030
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_rawUrlEncode
‪string stdWrap_rawUrlEncode($content='')
Definition: ContentObjectRenderer.php:2469
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getContentObject
‪AbstractContentObject null getContentObject($name)
Definition: ContentObjectRenderer.php:754
‪TYPO3\CMS\Core\Type\BitSet
Definition: BitSet.php:62
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getGetImgResourceHookObjects
‪array getGetImgResourceHookObjects()
Definition: ContentObjectRenderer.php:578
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_wrap3
‪string stdWrap_wrap3($content='', $conf=[])
Definition: ContentObjectRenderer.php:2770
‪TYPO3\CMS\Core\TimeTracker\TimeTracker\setTSlogMessage
‪setTSlogMessage($content, $num=0)
Definition: TimeTracker.php:215
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getLanguage
‪getLanguage()
Definition: TypoScriptFrontendController.php:3966
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression
Definition: CompositeExpression.php:25
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getATagParams
‪string getATagParams($conf, $addGlobal=1)
Definition: ContentObjectRenderer.php:1497
‪TYPO3\CMS\Core\Utility\ArrayUtility\getValueByPath
‪static mixed getValueByPath(array $array, $path, $delimiter='/')
Definition: ArrayUtility.php:180
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_preIfEmptyListNum
‪string stdWrap_preIfEmptyListNum($content='', $conf=[])
Definition: ContentObjectRenderer.php:1936
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\caseshift
‪string caseshift($theValue, $case)
Definition: ContentObjectRenderer.php:5732
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$parentRecord
‪array $parentRecord
Definition: ContentObjectRenderer.php:345
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\in
‪string in(string $fieldName, $value)
Definition: ExpressionBuilder.php:244
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_date
‪string stdWrap_date($content='', $conf=[])
Definition: ContentObjectRenderer.php:2324
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\createExceptionHandler
‪ExceptionHandlerInterface null createExceptionHandler($configuration=[])
Definition: ContentObjectRenderer.php:835
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_htmlSanitize
‪stdWrap_htmlSanitize(string $content='', array $conf=[])
Definition: ContentObjectRenderer.php:2911
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_keywords
‪string stdWrap_keywords($content='')
Definition: ContentObjectRenderer.php:2565
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_preCObject
‪string stdWrap_preCObject($content='', $conf=[])
Definition: ContentObjectRenderer.php:2606
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\resolveMixedLinkParameter
‪array string resolveMixedLinkParameter($linkText, $mixedLinkParameter, &$configuration=[])
Definition: ContentObjectRenderer.php:5031
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_required
‪string stdWrap_required($content='')
Definition: ContentObjectRenderer.php:2091
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_current
‪string stdWrap_current($content='', $conf=[])
Definition: ContentObjectRenderer.php:1847
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\__sleep
‪array __sleep()
Definition: ContentObjectRenderer.php:456
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_setContentToCurrent
‪string stdWrap_setContentToCurrent($content='')
Definition: ContentObjectRenderer.php:1760
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\andX
‪CompositeExpression andX(... $expressions)
Definition: ExpressionBuilder.php:70
‪TYPO3\CMS\Core\Utility\DebugUtility\debugTrail
‪static string debugTrail($prependFileNames=false)
Definition: DebugUtility.php:140
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\cObjGet
‪string cObjGet($setup, $addKey='')
Definition: ContentObjectRenderer.php:647
‪TYPO3\CMS\Core\Database\Query\QueryHelper
Definition: QueryHelper.php:32
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\encryptEmail
‪string encryptEmail(string $string, $type)
Definition: ContentObjectRenderer.php:5521
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_numberFormat
‪string stdWrap_numberFormat($content='', $conf=[])
Definition: ContentObjectRenderer.php:2298
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_setCurrent
‪string stdWrap_setCurrent($content='', $conf=[])
Definition: ContentObjectRenderer.php:1774
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$userObjectType
‪bool $userObjectType
Definition: ContentObjectRenderer.php:411
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\convertToUserIntObject
‪convertToUserIntObject()
Definition: ContentObjectRenderer.php:925
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_intval
‪string stdWrap_intval($content='')
Definition: ContentObjectRenderer.php:2254
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\insertData
‪string insertData($str)
Definition: ContentObjectRenderer.php:3196
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\__construct
‪__construct(TypoScriptFrontendController $typoScriptFrontendController=null, ContainerInterface $container=null)
Definition: ContentObjectRenderer.php:442
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_ifEmpty
‪string stdWrap_ifEmpty($content='', $conf=[])
Definition: ContentObjectRenderer.php:1963
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getQueryArguments
‪string getQueryArguments($conf, $overruleQueryArguments=[], $forceOverruleArguments=false)
Definition: ContentObjectRenderer.php:5582
‪TYPO3\CMS\Core\Resource\FileReference\getOriginalFile
‪File getOriginalFile()
Definition: FileReference.php:490
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\encryptCharcode
‪string encryptCharcode($n, $start, $end, $offset)
Definition: ContentObjectRenderer.php:5562
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_parseFunc
‪string stdWrap_parseFunc($content='', $conf=[])
Definition: ContentObjectRenderer.php:2164
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectGetSingleHookInterface
Definition: ContentObjectGetSingleHookInterface.php:24
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_hash
‪string stdWrap_hash($content='', array $conf=[])
Definition: ContentObjectRenderer.php:2267
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\isDisabled
‪bool isDisabled($table, $row)
Definition: ContentObjectRenderer.php:7029
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$data
‪array $data
Definition: ContentObjectRenderer.php:288
‪TYPO3\CMS\Core\Resource\ResourceFactory
Definition: ResourceFactory.php:41
‪$locales
‪$locales
Definition: be_users.php:7
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\__wakeup
‪__wakeup()
Definition: ContentObjectRenderer.php:475
‪TYPO3\CMS\Frontend\Page\PageLayoutResolver
Definition: PageLayoutResolver.php:32
‪TYPO3\CMS\Core\Utility\DebugUtility\viewArray
‪static string viewArray($array_in)
Definition: DebugUtility.php:196
‪TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException
Definition: ResourceDoesNotExistException.php:24
‪TYPO3\CMS\Core\Resource\File
Definition: File.php:24
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_outerWrap
‪string stdWrap_outerWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:2804
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\numberFormat
‪string numberFormat($content, $conf)
Definition: ContentObjectRenderer.php:3714
‪TYPO3\CMS\Core\Configuration\Features
Definition: Features.php:56
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\keywords
‪string keywords($content)
Definition: ContentObjectRenderer.php:5712
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectGetDataHookInterface
Definition: ContentObjectGetDataHookInterface.php:22
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getFrontendBackendUser
‪TYPO3 CMS Backend FrontendBackendUserAuthentication getFrontendBackendUser()
Definition: ContentObjectRenderer.php:7141
‪TYPO3\CMS\Core\Html\SanitizerInitiator
Definition: SanitizerInitiator.php:25
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\orX
‪CompositeExpression orX(... $expressions)
Definition: ExpressionBuilder.php:82
‪TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection\getCropArea
‪Area getCropArea(string $id='default')
Definition: CropVariantCollection.php:129
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\noTrimWrap
‪string noTrimWrap($content, $wrap, $char='|')
Definition: ContentObjectRenderer.php:5649
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$lastTypoLinkLD
‪array $lastTypoLinkLD
Definition: ContentObjectRenderer.php:365
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:35
‪TYPO3\CMS\Core\Service\DependencyOrderingService
Definition: DependencyOrderingService.php:32
‪TYPO3\CMS\Frontend\ContentObject\ImageContentObject\getAltParam
‪string getAltParam($conf, $longDesc=true)
Definition: ImageContentObject.php:318
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\editIcons
‪string editIcons($content, $params, array $conf=[], $currentRecord='', $dataArray=[], $addUrlParamStr='')
Definition: ContentObjectRenderer.php:6980
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getFieldVal
‪string null getFieldVal($field)
Definition: ContentObjectRenderer.php:4614
‪TYPO3\CMS\Core\Resource\ResourceFactory\getFileReferenceObject
‪FileReference getFileReferenceObject($uid, array $fileReferenceData=[], $raw=false)
Definition: ResourceFactory.php:620
‪TYPO3\CMS\Core\Utility\MailUtility
Definition: MailUtility.php:24
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\HTMLparser_TSbridge
‪string HTMLparser_TSbridge($theValue, $conf)
Definition: ContentObjectRenderer.php:3160
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\isInternalUrl
‪bool isInternalUrl(string $url)
Definition: ContentObjectRenderer.php:5314
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$currentValKey
‪string $currentValKey
Definition: ContentObjectRenderer.php:314
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_postCObject
‪string stdWrap_postCObject($content='', $conf=[])
Definition: ContentObjectRenderer.php:2619
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$currentRecordTotal
‪int $currentRecordTotal
Definition: ContentObjectRenderer.php:327
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\dataWrap
‪string dataWrap($content, $wrap)
Definition: ContentObjectRenderer.php:3176
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getRecords
‪array getRecords($tableName, array $queryConfiguration)
Definition: ContentObjectRenderer.php:6246
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_strftime
‪string stdWrap_strftime($content='', $conf=[])
Definition: ContentObjectRenderer.php:2341
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\calculateCacheTags
‪array calculateCacheTags(array $configuration)
Definition: ContentObjectRenderer.php:7113
‪TYPO3\CMS\Frontend\ContentObject\AbstractContentObject
Definition: AbstractContentObject.php:25
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$align
‪array $align
Definition: ContentObjectRenderer.php:106
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_substring
‪string stdWrap_substring($content='', $conf=[])
Definition: ContentObjectRenderer.php:2419
‪TYPO3\CMS\Core\Context\LanguageAspect
Definition: LanguageAspect.php:57
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_innerWrap2
‪string stdWrap_innerWrap2($content='', $conf=[])
Definition: ContentObjectRenderer.php:2593
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_field
‪string stdWrap_field($content='', $conf=[])
Definition: ContentObjectRenderer.php:1833
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_ifBlank
‪string stdWrap_ifBlank($content='', $conf=[])
Definition: ContentObjectRenderer.php:1980
‪TYPO3\CMS\Core\Context\Context\getAspect
‪AspectInterface getAspect(string $name)
Definition: Context.php:102
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\linkWrap
‪string linkWrap($content, $wrap)
Definition: ContentObjectRenderer.php:1437
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_stdWrapOverride
‪string stdWrap_stdWrapOverride($content='', $conf=[])
Definition: ContentObjectRenderer.php:1902
‪TYPO3\CMS\Core\Utility\DebugUtility
Definition: DebugUtility.php:25
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getQueryArray
‪array getQueryArray(QueryBuilder $queryBuilder)
Definition: ContentObjectRenderer.php:6490
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$parameters
‪array $parameters
Definition: ContentObjectRenderer.php:310
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_debug
‪string stdWrap_debug($content='')
Definition: ContentObjectRenderer.php:2986
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getBorderAttr
‪string getBorderAttr($borderAttr)
Definition: ContentObjectRenderer.php:1099
‪TYPO3\CMS\Frontend\Imaging\GifBuilder
Definition: GifBuilder.php:56
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$lastTypoLinkUrl
‪string $lastTypoLinkUrl
Definition: ContentObjectRenderer.php:355
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\getFirstResult
‪int getFirstResult()
Definition: QueryBuilder.php:343
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_typolink
‪string stdWrap_typolink($content='', $conf=[])
Definition: ContentObjectRenderer.php:2652
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_dataWrap
‪string stdWrap_dataWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:2730
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\parseFunc
‪string parseFunc($theValue, $conf, $ref='')
Definition: ContentObjectRenderer.php:3747
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$stdWrapRecursionLevel
‪int $stdWrapRecursionLevel
Definition: ContentObjectRenderer.php:419
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$stopRendering
‪array $stopRendering
Definition: ContentObjectRenderer.php:415
‪TYPO3\CMS\Core\Versioning\VersionState
Definition: VersionState.php:24
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static string[] trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:1059
‪TYPO3\CMS\Core\Resource\ProcessedFile
Definition: ProcessedFile.php:44
‪TYPO3\CMS\Core\TypoScript\TypoScriptService
Definition: TypoScriptService.php:25
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\createCropAreaFromJsonString
‪Area createCropAreaFromJsonString(string $cropSettings, string $cropVariant)
Definition: ContentObjectRenderer.php:4598
‪TYPO3\CMS\Core\Utility\MathUtility\calculateWithParentheses
‪static int calculateWithParentheses($string)
Definition: MathUtility.php:172
‪$output
‪$output
Definition: annotationChecker.php:119
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\calculateCacheLifetime
‪int null calculateCacheLifetime(array $configuration)
Definition: ContentObjectRenderer.php:7091
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\listNum
‪string listNum($content, $listNum, $char)
Definition: ContentObjectRenderer.php:3046
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\exec_getQuery
‪Statement exec_getQuery($table, $conf)
Definition: ContentObjectRenderer.php:6229
‪debug
‪debug($variable='', $title=null, $group=null)
Definition: GlobalDebugFunctions.php:19
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_encapsLines
‪string stdWrap_encapsLines($content='', $conf=[])
Definition: ContentObjectRenderer.php:2553
‪TYPO3\CMS\Core\Resource\Exception
Definition: Exception.php:22
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\editPanel
‪string editPanel($content, $conf, $currentRecord='', $dataArray=[])
Definition: ContentObjectRenderer.php:6916
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\calc
‪int calc($val)
Definition: ContentObjectRenderer.php:3476
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_append
‪string stdWrap_append($content='', $conf=[])
Definition: ContentObjectRenderer.php:2756
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\render
‪string render(AbstractContentObject $contentObject, $configuration=[])
Definition: ContentObjectRenderer.php:783
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\resolveAnchorLink
‪string resolveAnchorLink(string $linkText, array $conf)
Definition: ContentObjectRenderer.php:7171
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_bytes
‪string stdWrap_bytes($content='', $conf=[])
Definition: ContentObjectRenderer.php:2406
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_crop
‪string stdWrap_crop($content='', $conf=[])
Definition: ContentObjectRenderer.php:2457
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getData
‪string getData($string, $fieldArray=null)
Definition: ContentObjectRenderer.php:4637
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\addSecurityRelValues
‪addSecurityRelValues(array $tagAttributes, ?string $target, string $url)
Definition: ContentObjectRenderer.php:5284
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\addCacheTags
‪addCacheTags(array $tags)
Definition: TypoScriptFrontendController.php:2646
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:98
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrapValue
‪string stdWrapValue($key, array $config, $defaultValue='')
Definition: ContentObjectRenderer.php:1685
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\setJS
‪setJS($key, $content='')
Definition: TypoScriptFrontendController.php:3473
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:24
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getQueryConstraints
‪array getQueryConstraints(string $table, array $conf)
Definition: ContentObjectRenderer.php:6572
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_debugData
‪string stdWrap_debugData($content='')
Definition: ContentObjectRenderer.php:3012
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Utility\GeneralUtility\revExplode
‪static string[] revExplode($delimiter, $string, $count=0)
Definition: GeneralUtility.php:1025
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:28
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectOneSourceCollectionHookInterface
Definition: ContentObjectOneSourceCollectionHookInterface.php:22
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_wrap2
‪string stdWrap_wrap2($content='', $conf=[])
Definition: ContentObjectRenderer.php:2712
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getCropAreaFromFromTypoScriptSettings
‪Area null getCropAreaFromFromTypoScriptSettings(FileInterface $file, array $fileArray)
Definition: ContentObjectRenderer.php:4557
‪TYPO3\CMS\Core\Log\LogManager
Definition: LogManager.php:30
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:40
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\crop
‪string crop($content, $options)
Definition: ContentObjectRenderer.php:3276
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_cObject
‪string stdWrap_cObject($content='', $conf=[])
Definition: ContentObjectRenderer.php:1861
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_prioriCalc
‪string stdWrap_prioriCalc($content='', $conf=[])
Definition: ContentObjectRenderer.php:2222
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static int[] intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:988
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\replacementSingle
‪string replacementSingle($content, array $configuration)
Definition: ContentObjectRenderer.php:3605
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\lastChanged
‪lastChanged($tstamp)
Definition: ContentObjectRenderer.php:1417
‪TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection
Definition: CropVariantCollection.php:23
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_char
‪string stdWrap_char($content='', $conf=[])
Definition: ContentObjectRenderer.php:2242
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_stdWrapPostProcess
‪string stdWrap_stdWrapPostProcess($content='', $conf=[])
Definition: ContentObjectRenderer.php:2970
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
Definition: ContentObjectRenderer.php:97
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\processUrl
‪string null processUrl($context, $url, $typolinkConfiguration=[])
Definition: ContentObjectRenderer.php:5437
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\numRows
‪int numRows($conf)
Definition: ContentObjectRenderer.php:3030
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$typoScriptFrontendController
‪TypoScriptFrontendController null $typoScriptFrontendController
Definition: ContentObjectRenderer.php:423
‪TYPO3\CMS\Core\Resource\ResourceFactory\getFileObject
‪File getFileObject($uid, array $fileData=[])
Definition: ResourceFactory.php:390
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_debugFunc
‪string stdWrap_debugFunc($content='', $conf=[])
Definition: ContentObjectRenderer.php:2999
‪TYPO3\CMS\Core\Utility\HttpUtility
Definition: HttpUtility.php:24
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getImgResource
‪array null getImgResource($file, $fileArray)
Definition: ContentObjectRenderer.php:4384
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getTimeTracker
‪TimeTracker getTimeTracker()
Definition: ContentObjectRenderer.php:7149
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$cObjHookObjectsArr
‪array $cObjHookObjectsArr
Definition: ContentObjectRenderer.php:383
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\rootLineValue
‪string rootLineValue($key, $field, $slideBack=false, $altRootLine='')
Definition: ContentObjectRenderer.php:4940
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$oldData
‪array $oldData
Definition: ContentObjectRenderer.php:298
‪TYPO3\CMS\Core\Domain\Repository\PageRepository
Definition: PageRepository.php:52
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\prefixComment
‪string prefixComment($str, $conf, $content)
Definition: ContentObjectRenderer.php:3233
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\mergeExceptionHandlerConfiguration
‪array mergeExceptionHandlerConfiguration($configuration)
Definition: ContentObjectRenderer.php:885
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\searchWhere
‪string searchWhere($searchWords, $searchFieldList, $searchTable)
Definition: ContentObjectRenderer.php:6181
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\cObjGetSingle
‪string cObjGetSingle($name, $conf, $TSkey='__')
Definition: ContentObjectRenderer.php:673
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\callUserFunction
‪mixed callUserFunction($funcName, $conf, $content)
Definition: ContentObjectRenderer.php:5672
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_override
‪string stdWrap_override($content='', $conf=[])
Definition: ContentObjectRenderer.php:1919
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getAltParam
‪string getAltParam($conf, $longDesc=true)
Definition: ContentObjectRenderer.php:1459
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService
Definition: MarkerBasedTemplateService.php:27
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\readFlexformIntoConf
‪readFlexformIntoConf($flexData, &$conf, $recursive=false)
Definition: ContentObjectRenderer.php:946
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_innerWrap
‪string stdWrap_innerWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:2579
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getSlidePids
‪string getSlidePids($pidList, $pidConf)
Definition: ContentObjectRenderer.php:992
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_age
‪string stdWrap_age($content='', $conf=[])
Definition: ContentObjectRenderer.php:2379
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:22
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\calcAge
‪string calcAge($seconds, $labels)
Definition: ContentObjectRenderer.php:5802
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$table
‪string $table
Definition: ContentObjectRenderer.php:292
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_cropHTML
‪string stdWrap_cropHTML($content='', $conf=[])
Definition: ContentObjectRenderer.php:2432
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getTreeList
‪string getTreeList($id, $depth, $begin=0, $dontCheckEnableFields=false, $addSelectFields='', $moreWhereClauses='', array $prevId_array=[], $recursionLevel=0)
Definition: ContentObjectRenderer.php:5945
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getCurrentVal
‪mixed getCurrentVal()
Definition: ContentObjectRenderer.php:622
‪TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection\create
‪static CropVariantCollection create(string $jsonString, array $tcaConfig=[])
Definition: CropVariantCollection.php:42
‪TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer
Definition: FrontendRestrictionContainer.php:31
‪TYPO3\CMS\Core\TimeTracker\TimeTracker
Definition: TimeTracker.php:30
‪TYPO3\CMS\Core\Resource\Exception\InvalidPathException
Definition: InvalidPathException.php:24
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\checkPidArray
‪array checkPidArray($pageIds)
Definition: ContentObjectRenderer.php:6811
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_data
‪string stdWrap_data($content='', $conf=[])
Definition: ContentObjectRenderer.php:1817
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getFromCache
‪string bool getFromCache(array $configuration)
Definition: ContentObjectRenderer.php:7068
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_addPageCacheTags
‪string stdWrap_addPageCacheTags($content='', $conf=[])
Definition: ContentObjectRenderer.php:1741
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\sanitizeSelectPart
‪string sanitizeSelectPart($selectPart, $table)
Definition: ContentObjectRenderer.php:6776
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getQuery
‪mixed getQuery($table, $conf, $returnQueryArray=false)
Definition: ContentObjectRenderer.php:6284
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_strtotime
‪string stdWrap_strtotime($content='', $conf=[])
Definition: ContentObjectRenderer.php:2363
‪TYPO3\CMS\Core\Utility\ArrayUtility\filterAndSortByNumericKeys
‪static array filterAndSortByNumericKeys($setupArr, $acceptAnyKeys=false)
Definition: ArrayUtility.php:844
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\OBJECTTYPE_USER_INT
‪const OBJECTTYPE_USER_INT
Definition: ContentObjectRenderer.php:430
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_trim
‪string stdWrap_trim($content='')
Definition: ContentObjectRenderer.php:2010
‪TYPO3\CMS\Core\Resource\Exception
Definition: AbstractFileOperationException.php:16
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_RECYCLER
‪const DOKTYPE_RECYCLER
Definition: PageRepository.php:110
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_preUserFunc
‪string stdWrap_preUserFunc($content='', $conf=[])
Definition: ContentObjectRenderer.php:1888
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\calculateCacheKey
‪string calculateCacheKey(array $configuration)
Definition: ContentObjectRenderer.php:7128
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getKey
‪int getKey($key, $arr)
Definition: ContentObjectRenderer.php:4998
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_postUserFuncInt
‪string stdWrap_postUserFuncInt($content='', $conf=[])
Definition: ContentObjectRenderer.php:2843
‪TYPO3\CMS\Core\Html\SanitizerBuilderFactory
Definition: SanitizerBuilderFactory.php:35
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_doubleBrTag
‪string stdWrap_doubleBrTag($content='', $conf=[])
Definition: ContentObjectRenderer.php:2513
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\typoLink_URL
‪string typoLink_URL($conf)
Definition: ContentObjectRenderer.php:5351
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\splitObj
‪string splitObj($value, $conf)
Definition: ContentObjectRenderer.php:3518
‪TYPO3\CMS\Frontend\ContentObject\Exception\ProductionExceptionHandler
Definition: ProductionExceptionHandler.php:30
‪TYPO3\CMS\Core\Resource\ResourceFactory\retrieveFileOrFolderObject
‪File Folder null retrieveFileOrFolderObject($input)
Definition: ResourceFactory.php:482
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_strPad
‪string stdWrap_strPad($content='', $conf=[])
Definition: ContentObjectRenderer.php:2023
‪TYPO3\CMS\Frontend\ContentObject\AbstractContentObject\render
‪string render($conf=[])
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectPostInitHookInterface
Definition: ContentObjectPostInitHookInterface.php:23
‪TYPO3\CMS\Core\Utility\StringUtility\multibyteStringPad
‪static string multibyteStringPad(string $string, int $length, string $pad_string=' ', int $pad_type=STR_PAD_RIGHT, string $encoding='UTF-8')
Definition: StringUtility.php:165
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\$lastTypoLinkTarget
‪string $lastTypoLinkTarget
Definition: ContentObjectRenderer.php:361
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_encodeForJavaScriptValue
‪string stdWrap_encodeForJavaScriptValue($content='')
Definition: ContentObjectRenderer.php:2500
‪TYPO3\CMS\Core\Authentication\AbstractUserAuthentication
Definition: AbstractUserAuthentication.php:51
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\checkIf
‪bool checkIf($conf)
Definition: ContentObjectRenderer.php:3074
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\replacement
‪string replacement($content, array $configuration)
Definition: ContentObjectRenderer.php:3585
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_fieldRequired
‪string stdWrap_fieldRequired($content='', $conf=[])
Definition: ContentObjectRenderer.php:2127
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getMailTo
‪array getMailTo($mailAddress, $linktxt)
Definition: ContentObjectRenderer.php:5477
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap_postUserFunc
‪string stdWrap_postUserFunc($content='', $conf=[])
Definition: ContentObjectRenderer.php:2829
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getQueryMarkers
‪array getQueryMarkers($table, $conf)
Definition: ContentObjectRenderer.php:6834
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getGlobal
‪mixed getGlobal($keyString, $source=null)
Definition: ContentObjectRenderer.php:4965