[BUGFIX] Invalid file identifier with GIFBUILDER
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / ContentObject / ContentObjectRenderer.php
1 <?php
2 namespace TYPO3\CMS\Frontend\ContentObject;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Cache\CacheManager;
18 use TYPO3\CMS\Core\FrontendEditing\FrontendEditingController;
19 use TYPO3\CMS\Core\Html\HtmlParser;
20 use TYPO3\CMS\Core\Imaging\GraphicalFunctions;
21 use TYPO3\CMS\Core\Log\LogManager;
22 use TYPO3\CMS\Core\Mail\MailMessage;
23 use TYPO3\CMS\Core\Resource\Exception;
24 use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
25 use TYPO3\CMS\Core\Resource\File;
26 use TYPO3\CMS\Core\Resource\FileInterface;
27 use TYPO3\CMS\Core\Resource\FileReference;
28 use TYPO3\CMS\Core\Resource\Folder;
29 use TYPO3\CMS\Core\Resource\ProcessedFile;
30 use TYPO3\CMS\Core\Resource\ResourceFactory;
31 use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
32 use TYPO3\CMS\Core\TypoScript\TemplateService;
33 use TYPO3\CMS\Core\Utility\ArrayUtility;
34 use TYPO3\CMS\Core\Utility\DebugUtility;
35 use TYPO3\CMS\Core\Utility\GeneralUtility;
36 use TYPO3\CMS\Core\Utility\HttpUtility;
37 use TYPO3\CMS\Core\Utility\MailUtility;
38 use TYPO3\CMS\Core\Utility\MathUtility;
39 use TYPO3\CMS\Core\Utility\StringUtility;
40 use TYPO3\CMS\Core\Versioning\VersionState;
41 use TYPO3\CMS\Frontend\ContentObject\Exception\ContentRenderingException;
42 use TYPO3\CMS\Frontend\ContentObject\Exception\ProductionExceptionHandler;
43 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
44 use TYPO3\CMS\Frontend\Imaging\GifBuilder;
45 use TYPO3\CMS\Frontend\ContentObject\Exception\ExceptionHandlerInterface;
46 use TYPO3\CMS\Frontend\Page\CacheHashCalculator;
47 use TYPO3\CMS\Frontend\Page\PageRepository;
48
49 /**
50 * This class contains all main TypoScript features.
51 * This includes the rendering of TypoScript content objects (cObjects).
52 * Is the backbone of TypoScript Template rendering.
53 *
54 * There are lots of functions you can use from your include-scripts.
55 * The class is normally instantiated and referred to as "cObj".
56 * When you call your own PHP-code typically through a USER or USER_INT cObject then it is this class that instantiates the object and calls the main method. Before it does so it will set (if you are using classes) a reference to itself in the internal variable "cObj" of the object. Thus you can access all functions and data from this class by $this->cObj->... from within you classes written to be USER or USER_INT content objects.
57 *
58 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
59 */
60 class ContentObjectRenderer {
61
62 /**
63 * @var array
64 */
65 public $align = array(
66 'center',
67 'right',
68 'left'
69 );
70
71 /**
72 * stdWrap functions in their correct order
73 *
74 * @see stdWrap()
75 */
76 public $stdWrapOrder = array(
77 'stdWrapPreProcess' => 'hook',
78 // this is a placeholder for the first Hook
79 'cacheRead' => 'hook',
80 // this is a placeholder for checking if the content is available in cache
81 'setContentToCurrent' => 'boolean',
82 'setContentToCurrent.' => 'array',
83 'addPageCacheTags' => 'string',
84 'addPageCacheTags.' => 'array',
85 'setCurrent' => 'string',
86 'setCurrent.' => 'array',
87 'lang.' => 'array',
88 'data' => 'getText',
89 'data.' => 'array',
90 'field' => 'fieldName',
91 'field.' => 'array',
92 'current' => 'boolean',
93 'current.' => 'array',
94 'cObject' => 'cObject',
95 'cObject.' => 'array',
96 'numRows.' => 'array',
97 'filelist' => 'dir',
98 'filelist.' => 'array',
99 'preUserFunc' => 'functionName',
100 'stdWrapOverride' => 'hook',
101 // this is a placeholder for the second Hook
102 'override' => 'string',
103 'override.' => 'array',
104 'preIfEmptyListNum' => 'listNum',
105 'preIfEmptyListNum.' => 'array',
106 'ifNull' => 'string',
107 'ifNull.' => 'array',
108 'ifEmpty' => 'string',
109 'ifEmpty.' => 'array',
110 'ifBlank' => 'string',
111 'ifBlank.' => 'array',
112 'listNum' => 'listNum',
113 'listNum.' => 'array',
114 'trim' => 'boolean',
115 'trim.' => 'array',
116 'strPad.' => 'array',
117 'stdWrap' => 'stdWrap',
118 'stdWrap.' => 'array',
119 'stdWrapProcess' => 'hook',
120 // this is a placeholder for the third Hook
121 'required' => 'boolean',
122 'required.' => 'array',
123 'if.' => 'array',
124 'fieldRequired' => 'fieldName',
125 'fieldRequired.' => 'array',
126 'csConv' => 'string',
127 'csConv.' => 'array',
128 'parseFunc' => 'objectpath',
129 'parseFunc.' => 'array',
130 'HTMLparser' => 'boolean',
131 'HTMLparser.' => 'array',
132 'split.' => 'array',
133 'replacement.' => 'array',
134 'prioriCalc' => 'boolean',
135 'prioriCalc.' => 'array',
136 'char' => 'integer',
137 'char.' => 'array',
138 'intval' => 'boolean',
139 'intval.' => 'array',
140 'hash' => 'string',
141 'hash.' => 'array',
142 'round' => 'boolean',
143 'round.' => 'array',
144 'numberFormat.' => 'array',
145 'expandList' => 'boolean',
146 'expandList.' => 'array',
147 'date' => 'dateconf',
148 'date.' => 'array',
149 'strftime' => 'strftimeconf',
150 'strftime.' => 'array',
151 'age' => 'boolean',
152 'age.' => 'array',
153 'case' => 'case',
154 'case.' => 'array',
155 'bytes' => 'boolean',
156 'bytes.' => 'array',
157 'substring' => 'parameters',
158 'substring.' => 'array',
159 'removeBadHTML' => 'boolean',
160 'removeBadHTML.' => 'array',
161 'cropHTML' => 'crop',
162 'cropHTML.' => 'array',
163 'stripHtml' => 'boolean',
164 'stripHtml.' => 'array',
165 'crop' => 'crop',
166 'crop.' => 'array',
167 'rawUrlEncode' => 'boolean',
168 'rawUrlEncode.' => 'array',
169 'htmlSpecialChars' => 'boolean',
170 'htmlSpecialChars.' => 'array',
171 'encodeForJavaScriptValue' => 'boolean',
172 'encodeForJavaScriptValue.' => 'array',
173 'doubleBrTag' => 'string',
174 'doubleBrTag.' => 'array',
175 'br' => 'boolean',
176 'br.' => 'array',
177 'brTag' => 'string',
178 'brTag.' => 'array',
179 'encapsLines.' => 'array',
180 'keywords' => 'boolean',
181 'keywords.' => 'array',
182 'innerWrap' => 'wrap',
183 'innerWrap.' => 'array',
184 'innerWrap2' => 'wrap',
185 'innerWrap2.' => 'array',
186 'fontTag' => 'wrap',
187 'fontTag.' => 'array',
188 'addParams.' => 'array',
189 'textStyle.' => 'array',
190 'tableStyle.' => 'array',
191 'filelink.' => 'array',
192 'preCObject' => 'cObject',
193 'preCObject.' => 'array',
194 'postCObject' => 'cObject',
195 'postCObject.' => 'array',
196 'wrapAlign' => 'align',
197 'wrapAlign.' => 'array',
198 'typolink.' => 'array',
199 'TCAselectItem.' => 'array',
200 'space' => 'space',
201 'space.' => 'array',
202 'spaceBefore' => 'int',
203 'spaceBefore.' => 'array',
204 'spaceAfter' => 'int',
205 'spaceAfter.' => 'array',
206 'wrap' => 'wrap',
207 'wrap.' => 'array',
208 'noTrimWrap' => 'wrap',
209 'noTrimWrap.' => 'array',
210 'wrap2' => 'wrap',
211 'wrap2.' => 'array',
212 'dataWrap' => 'dataWrap',
213 'dataWrap.' => 'array',
214 'prepend' => 'cObject',
215 'prepend.' => 'array',
216 'append' => 'cObject',
217 'append.' => 'array',
218 'wrap3' => 'wrap',
219 'wrap3.' => 'array',
220 'orderedStdWrap' => 'stdWrap',
221 'orderedStdWrap.' => 'array',
222 'outerWrap' => 'wrap',
223 'outerWrap.' => 'array',
224 'insertData' => 'boolean',
225 'insertData.' => 'array',
226 'offsetWrap' => 'space',
227 'offsetWrap.' => 'array',
228 'postUserFunc' => 'functionName',
229 'postUserFuncInt' => 'functionName',
230 'prefixComment' => 'string',
231 'prefixComment.' => 'array',
232 'editIcons' => 'string',
233 'editIcons.' => 'array',
234 'editPanel' => 'boolean',
235 'editPanel.' => 'array',
236 'cacheStore' => 'hook',
237 // this is a placeholder for storing the content in cache
238 'stdWrapPostProcess' => 'hook',
239 // this is a placeholder for the last Hook
240 'debug' => 'boolean',
241 'debug.' => 'array',
242 'debugFunc' => 'boolean',
243 'debugFunc.' => 'array',
244 'debugData' => 'boolean',
245 'debugData.' => 'array'
246 );
247
248 /**
249 * Class names for accordant content object names
250 *
251 * @var array
252 */
253 protected $contentObjectClassMap = array();
254
255 /**
256 * Holds ImageMagick parameters and extensions used for compression
257 *
258 * @var array
259 * @see IMGTEXT()
260 */
261 public $image_compression = array(
262 10 => array(
263 'params' => '',
264 'ext' => 'gif'
265 ),
266 11 => array(
267 'params' => '-colors 128',
268 'ext' => 'gif'
269 ),
270 12 => array(
271 'params' => '-colors 64',
272 'ext' => 'gif'
273 ),
274 13 => array(
275 'params' => '-colors 32',
276 'ext' => 'gif'
277 ),
278 14 => array(
279 'params' => '-colors 16',
280 'ext' => 'gif'
281 ),
282 15 => array(
283 'params' => '-colors 8',
284 'ext' => 'gif'
285 ),
286 20 => array(
287 'params' => '-quality 100',
288 'ext' => 'jpg'
289 ),
290 21 => array(
291 'params' => '-quality 90',
292 'ext' => 'jpg'
293 ),
294 22 => array(
295 'params' => '-quality 80',
296 'ext' => 'jpg'
297 ),
298 23 => array(
299 'params' => '-quality 70',
300 'ext' => 'jpg'
301 ),
302 24 => array(
303 'params' => '-quality 60',
304 'ext' => 'jpg'
305 ),
306 25 => array(
307 'params' => '-quality 50',
308 'ext' => 'jpg'
309 ),
310 26 => array(
311 'params' => '-quality 40',
312 'ext' => 'jpg'
313 ),
314 27 => array(
315 'params' => '-quality 30',
316 'ext' => 'jpg'
317 ),
318 28 => array(
319 'params' => '-quality 20',
320 'ext' => 'jpg'
321 ),
322 30 => array(
323 'params' => '-colors 256',
324 'ext' => 'png'
325 ),
326 31 => array(
327 'params' => '-colors 128',
328 'ext' => 'png'
329 ),
330 32 => array(
331 'params' => '-colors 64',
332 'ext' => 'png'
333 ),
334 33 => array(
335 'params' => '-colors 32',
336 'ext' => 'png'
337 ),
338 34 => array(
339 'params' => '-colors 16',
340 'ext' => 'png'
341 ),
342 35 => array(
343 'params' => '-colors 8',
344 'ext' => 'png'
345 ),
346 39 => array(
347 'params' => '',
348 'ext' => 'png'
349 )
350 );
351
352 /**
353 * ImageMagick parameters for image effects
354 *
355 * @var array
356 * @see IMGTEXT()
357 */
358 public $image_effects = array(
359 1 => '-rotate 90',
360 2 => '-rotate 270',
361 3 => '-rotate 180',
362 10 => '-colorspace GRAY',
363 11 => '-sharpen 70',
364 20 => '-normalize',
365 23 => '-contrast',
366 25 => '-gamma 1.3',
367 26 => '-gamma 0.8'
368 );
369
370 /**
371 * Loaded with the current data-record.
372 *
373 * If the instance of this class is used to render records from the database those records are found in this array.
374 * The function stdWrap has TypoScript properties that fetch field-data from this array.
375 *
376 * @var array
377 * @see init()
378 */
379 public $data = array();
380
381 /**
382 * @var string
383 */
384 protected $table = '';
385
386 /**
387 * Used for backup...
388 *
389 * @var array
390 */
391 public $oldData = array();
392
393 /**
394 * If this is set with an array before stdWrap, it's used instead of $this->data in the data-property in stdWrap
395 *
396 * @var string
397 */
398 public $alternativeData = '';
399
400 /**
401 * Used by the parseFunc function and is loaded with tag-parameters when parsing tags.
402 *
403 * @var array
404 */
405 public $parameters = array();
406
407 /**
408 * @var string
409 */
410 public $currentValKey = 'currentValue_kidjls9dksoje';
411
412 /**
413 * This is set to the [table]:[uid] of the record delivered in the $data-array, if the cObjects CONTENT or RECORD is in operation.
414 * Note that $GLOBALS['TSFE']->currentRecord is set to an equal value but always indicating the latest record rendered.
415 *
416 * @var string
417 */
418 public $currentRecord = '';
419
420 /**
421 * Set in RecordsContentObject and ContentContentObject to the current number of records selected in a query.
422 *
423 * @var int
424 */
425 public $currentRecordTotal = 0;
426
427 /**
428 * Incremented in RecordsContentObject and ContentContentObject before each record rendering.
429 *
430 * @var int
431 */
432 public $currentRecordNumber = 0;
433
434 /**
435 * Incremented in RecordsContentObject and ContentContentObject before each record rendering.
436 *
437 * @var int
438 */
439 public $parentRecordNumber = 0;
440
441 /**
442 * If the ContentObjectRender was started from ContentContentObject, RecordsContentObject or SearchResultContentObject this array has two keys, 'data' and 'currentRecord' which indicates the record and data for the parent cObj.
443 *
444 * @var array
445 */
446 public $parentRecord = array();
447
448 /**
449 * Is set to 1 if the instance of this cObj is executed from a *_INT plugin (see pagegen, bottom of document)
450 *
451 * @var bool
452 */
453 public $INT_include = 0;
454
455 /**
456 * This is used by checkPid, that checks if pages are accessible. The $checkPid_cache['page_uid'] is set TRUE or FALSE upon this check featuring a caching function for the next request.
457 *
458 * @var array
459 */
460 public $checkPid_cache = array();
461
462 /**
463 * @var string
464 */
465 public $checkPid_badDoktypeList = '255';
466
467 /**
468 * This will be set by typoLink() to the url of the most recent link created.
469 *
470 * @var string
471 */
472 public $lastTypoLinkUrl = '';
473
474 /**
475 * DO. link target.
476 *
477 * @var string
478 */
479 public $lastTypoLinkTarget = '';
480
481 /**
482 * @var array
483 */
484 public $lastTypoLinkLD = array();
485
486 /**
487 * Caching substituteMarkerArrayCached function
488 *
489 * @var array
490 */
491 public $substMarkerCache = array();
492
493 /**
494 * array that registers rendered content elements (or any table) to make sure they are not rendered recursively!
495 *
496 * @var array
497 */
498 public $recordRegister = array();
499
500 /**
501 * Additionally registered content object types and class names
502 *
503 * @var array
504 */
505 protected $cObjHookObjectsRegistry = array();
506
507 /**
508 * @var array
509 */
510 public $cObjHookObjectsArr = array();
511
512 /**
513 * Containing hook objects for stdWrap
514 *
515 * @var array
516 */
517 protected $stdWrapHookObjects = array();
518
519 /**
520 * Containing hook objects for getImgResource
521 *
522 * @var array
523 */
524 protected $getImgResourceHookObjects;
525
526 /**
527 * @var File Current file objects (during iterations over files)
528 */
529 protected $currentFile = NULL;
530
531 /**
532 * Set to TRUE by doConvertToUserIntObject() if USER object wants to become USER_INT
533 */
534 public $doConvertToUserIntObject = FALSE;
535
536 /**
537 * Indicates current object type. Can hold one of OBJECTTYPE_ constants or FALSE.
538 * The value is set and reset inside USER() function. Any time outside of
539 * USER() it is FALSE.
540 */
541 protected $userObjectType = FALSE;
542
543 /**
544 * @var array
545 */
546 protected $stopRendering = array();
547
548 /**
549 * @var int
550 */
551 protected $stdWrapRecursionLevel = 0;
552
553 /**
554 * @var TypoScriptFrontendController
555 */
556 protected $typoScriptFrontendController;
557
558 /**
559 * Indicates that object type is USER.
560 *
561 * @see ContentObjectRender::$userObjectType
562 */
563 const OBJECTTYPE_USER_INT = 1;
564 /**
565 * Indicates that object type is USER.
566 *
567 * @see ContentObjectRender::$userObjectType
568 */
569 const OBJECTTYPE_USER = 2;
570
571 /**
572 * @param TypoScriptFrontendController $typoScriptFrontendController
573 */
574 public function __construct(TypoScriptFrontendController $typoScriptFrontendController = NULL) {
575 $this->typoScriptFrontendController = $typoScriptFrontendController ?: $GLOBALS['TSFE'];
576 $this->contentObjectClassMap = $GLOBALS['TYPO3_CONF_VARS']['FE']['ContentObjects'];
577 }
578
579 /**
580 * Prevent several objects from being serialized.
581 * If currentFile is set, it is either a File or a FileReference object. As the object itself can't be serialized,
582 * we have store a hash and restore the object in __wakeup()
583 *
584 * @return array
585 */
586 public function __sleep() {
587 $vars = get_object_vars($this);
588 unset($vars['typoScriptFrontendController']);
589 if ($this->currentFile instanceof FileReference) {
590 $this->currentFile = 'FileReference:' . $this->currentFile->getUid();
591 } elseif ($this->currentFile instanceof File) {
592 $this->currentFile = 'File:' . $this->currentFile->getIdentifier();
593 } else {
594 unset($vars['currentFile']);
595 }
596 return array_keys($vars);
597 }
598
599 /**
600 * Restore currentFile from hash.
601 * If currentFile references a File, the identifier equals file identifier.
602 * If it references a FileReference the identifier equals the uid of the reference.
603 */
604 public function __wakeup() {
605 if (isset($GLOBALS['TSFE'])) {
606 $this->typoScriptFrontendController = $GLOBALS['TSFE'];
607 }
608 if ($this->currentFile !== NULL && is_string($this->currentFile)) {
609 list($objectType, $identifier) = explode(':', $this->currentFile, 2);
610 try {
611 if ($objectType === 'File') {
612 $this->currentFile = ResourceFactory::getInstance()->retrieveFileOrFolderObject($identifier);
613 } elseif ($objectType === 'FileReference') {
614 $this->currentFile = ResourceFactory::getInstance()->getFileReferenceObject($identifier);
615 }
616 } catch (ResourceDoesNotExistException $e) {
617 $this->currentFile = NULL;
618 }
619 }
620 }
621
622 /**
623 * Allow injecting content object class map.
624 *
625 * This method is private API, please use configuration
626 * $GLOBALS['TYPO3_CONF_VARS']['FE']['ContentObjects'] to add new content objects
627 *
628 * @internal
629 * @param array $contentObjectClassMap
630 */
631 public function setContentObjectClassMap(array $contentObjectClassMap) {
632 $this->contentObjectClassMap = $contentObjectClassMap;
633 }
634
635 /**
636 * Register a single content object name to class name
637 *
638 * This method is private API, please use configuration
639 * $GLOBALS['TYPO3_CONF_VARS']['FE']['ContentObjects'] to add new content objects
640 *
641 * @internal
642 * @param string $className
643 * @param string $contentObjectName
644 */
645 public function registerContentObjectClass($className, $contentObjectName) {
646 $this->contentObjectClassMap[$contentObjectName] = $className;
647 }
648
649 /**
650 * Class constructor.
651 * Well, it has to be called manually since it is not a real constructor function.
652 * So after making an instance of the class, call this function and pass to it a database record and the tablename from where the record is from. That will then become the "current" record loaded into memory and accessed by the .fields property found in eg. stdWrap.
653 *
654 * @param array $data The record data that is rendered.
655 * @param string $table The table that the data record is from.
656 * @return void
657 */
658 public function start($data, $table = '') {
659 $this->data = $data;
660 $this->table = $table;
661 $this->currentRecord = $table ? $table . ':' . $this->data['uid'] : '';
662 $this->parameters = array();
663 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['cObjTypeAndClass'])) {
664 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['cObjTypeAndClass'] as $classArr) {
665 $this->cObjHookObjectsRegistry[$classArr[0]] = $classArr[1];
666 }
667 }
668 $this->stdWrapHookObjects = array();
669 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['stdWrap'])) {
670 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['stdWrap'] as $classData) {
671 $hookObject = GeneralUtility::getUserObj($classData);
672 if (!$hookObject instanceof ContentObjectStdWrapHookInterface) {
673 throw new \UnexpectedValueException($classData . ' must implement interface ' . ContentObjectStdWrapHookInterface::class, 1195043965);
674 }
675 $this->stdWrapHookObjects[] = $hookObject;
676 }
677 }
678 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['postInit'])) {
679 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['postInit'] as $classData) {
680 $postInitializationProcessor = GeneralUtility::getUserObj($classData);
681 if (!$postInitializationProcessor instanceof ContentObjectPostInitHookInterface) {
682 throw new \UnexpectedValueException($classData . ' must implement interface ' . ContentObjectPostInitHookInterface::class, 1274563549);
683 }
684 $postInitializationProcessor->postProcessContentObjectInitialization($this);
685 }
686 }
687 }
688
689 /**
690 * Returns the current table
691 *
692 * @return string
693 */
694 public function getCurrentTable() {
695 return $this->table;
696 }
697
698 /**
699 * Gets the 'getImgResource' hook objects.
700 * The first call initializes the accordant objects.
701 *
702 * @return array The 'getImgResource' hook objects (if any)
703 */
704 protected function getGetImgResourceHookObjects() {
705 if (!isset($this->getImgResourceHookObjects)) {
706 $this->getImgResourceHookObjects = array();
707 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImgResource'])) {
708 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImgResource'] as $classData) {
709 $hookObject = GeneralUtility::getUserObj($classData);
710 if (!$hookObject instanceof ContentObjectGetImageResourceHookInterface) {
711 throw new \UnexpectedValueException('$hookObject must implement interface ' . ContentObjectGetImageResourceHookInterface::class, 1218636383);
712 }
713 $this->getImgResourceHookObjects[] = $hookObject;
714 }
715 }
716 }
717 return $this->getImgResourceHookObjects;
718 }
719
720 /**
721 * Sets the internal variable parentRecord with information about current record.
722 * If the ContentObjectRender was started from CONTENT, RECORD or SEARCHRESULT cObject's this array has two keys, 'data' and 'currentRecord' which indicates the record and data for the parent cObj.
723 *
724 * @param array $data The record array
725 * @param string $currentRecord This is set to the [table]:[uid] of the record delivered in the $data-array, if the cObjects CONTENT or RECORD is in operation. Note that $GLOBALS['TSFE']->currentRecord is set to an equal value but always indicating the latest record rendered.
726 * @return void
727 * @access private
728 */
729 public function setParent($data, $currentRecord) {
730 $this->parentRecord = array(
731 'data' => $data,
732 'currentRecord' => $currentRecord
733 );
734 }
735
736 /***********************************************
737 *
738 * CONTENT_OBJ:
739 *
740 ***********************************************/
741 /**
742 * Returns the "current" value.
743 * The "current" value is just an internal variable that can be used by functions to pass a single value on to another function later in the TypoScript processing.
744 * It's like "load accumulator" in the good old C64 days... basically a "register" you can use as you like.
745 * The TSref will tell if functions are setting this value before calling some other object so that you know if it holds any special information.
746 *
747 * @return mixed The "current" value
748 */
749 public function getCurrentVal() {
750 return $this->data[$this->currentValKey];
751 }
752
753 /**
754 * Sets the "current" value.
755 *
756 * @param mixed $value The variable that you want to set as "current
757 * @return void
758 * @see getCurrentVal()
759 */
760 public function setCurrentVal($value) {
761 $this->data[$this->currentValKey] = $value;
762 }
763
764 /**
765 * Rendering of a "numerical array" of cObjects from TypoScript
766 * Will call ->cObjGetSingle() for each cObject found and accumulate the output.
767 *
768 * @param array $setup array with cObjects as values.
769 * @param string $addKey A prefix for the debugging information
770 * @return string Rendered output from the cObjects in the array.
771 * @see cObjGetSingle()
772 */
773 public function cObjGet($setup, $addKey = '') {
774 if (is_array($setup)) {
775 $sKeyArray = TemplateService::sortedKeyList($setup);
776 $content = '';
777 foreach ($sKeyArray as $theKey) {
778 $theValue = $setup[$theKey];
779 if ((int)$theKey && strpos($theKey, '.') === FALSE) {
780 $conf = $setup[$theKey . '.'];
781 $content .= $this->cObjGetSingle($theValue, $conf, $addKey . $theKey);
782 }
783 }
784 return $content;
785 }
786 }
787
788 /**
789 * Renders a content object
790 *
791 * @param string $name The content object name, eg. "TEXT" or "USER" or "IMAGE
792 * @param array $conf The array with TypoScript properties for the content object
793 * @param string $TSkey A string label used for the internal debugging tracking.
794 * @return string cObject output
795 * @throws \UnexpectedValueException
796 */
797 public function cObjGetSingle($name, $conf, $TSkey = '__') {
798 $content = '';
799 // Checking that the function is not called eternally. This is done by interrupting at a depth of 100
800 $GLOBALS['TSFE']->cObjectDepthCounter--;
801 if ($GLOBALS['TSFE']->cObjectDepthCounter > 0) {
802 $name = trim($name);
803 if ($GLOBALS['TT']->LR) {
804 $GLOBALS['TT']->push($TSkey, $name);
805 }
806 // Checking if the COBJ is a reference to another object. (eg. name of 'blabla.blabla = < styles.something')
807 if ($name[0] === '<') {
808 $key = trim(substr($name, 1));
809 $cF = GeneralUtility::makeInstance(TypoScriptParser::class);
810 // $name and $conf is loaded with the referenced values.
811 $confOverride = is_array($conf) ? $conf : array();
812 list($name, $conf) = $cF->getVal($key, $GLOBALS['TSFE']->tmpl->setup);
813 $conf = array_replace_recursive(is_array($conf) ? $conf : array(), $confOverride);
814 // Getting the cObject
815 $GLOBALS['TT']->incStackPointer();
816 $content .= $this->cObjGetSingle($name, $conf, $key);
817 $GLOBALS['TT']->decStackPointer();
818 } else {
819 $hooked = FALSE;
820 // Application defined cObjects
821 if (!empty($this->cObjHookObjectsRegistry[$name])) {
822 if (empty($this->cObjHookObjectsArr[$name])) {
823 $this->cObjHookObjectsArr[$name] = GeneralUtility::getUserObj($this->cObjHookObjectsRegistry[$name]);
824 }
825 $hookObj = $this->cObjHookObjectsArr[$name];
826 if (method_exists($hookObj, 'cObjGetSingleExt')) {
827 $content .= $hookObj->cObjGetSingleExt($name, $conf, $TSkey, $this);
828 $hooked = TRUE;
829 }
830 }
831 if (!$hooked) {
832 $contentObject = $this->getContentObject($name);
833 if ($contentObject) {
834 $content .= $this->render($contentObject, $conf);
835 } else {
836 // Call hook functions for extra processing
837 if ($name && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['cObjTypeAndClassDefault'])) {
838 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['cObjTypeAndClassDefault'] as $classData) {
839 $hookObject = GeneralUtility::getUserObj($classData);
840 if (!$hookObject instanceof ContentObjectGetSingleHookInterface) {
841 throw new \UnexpectedValueException('$hookObject must implement interface ' . ContentObjectGetSingleHookInterface::class, 1195043731);
842 }
843 /** @var $hookObject ContentObjectGetSingleHookInterface */
844 $content .= $hookObject->getSingleContentObject($name, (array)$conf, $TSkey, $this);
845 }
846 } else {
847 // Log error in AdminPanel
848 $warning = sprintf('Content Object "%s" does not exist', $name);
849 $GLOBALS['TT']->setTSlogMessage($warning, 2);
850 }
851 }
852 }
853 }
854 if ($GLOBALS['TT']->LR) {
855 $GLOBALS['TT']->pull($content);
856 }
857 }
858 // Increasing on exit...
859 $GLOBALS['TSFE']->cObjectDepthCounter++;
860 return $content;
861 }
862
863 /**
864 * Returns a new content object of type $name.
865 * This content object needs to be registered as content object
866 * in $this->contentObjectClassMap
867 *
868 * @param string $name
869 * @return NULL|AbstractContentObject
870 * @throws ContentRenderingException
871 */
872 public function getContentObject($name) {
873 if (!isset($this->contentObjectClassMap[$name])) {
874 return NULL;
875 }
876 $fullyQualifiedClassName = $this->contentObjectClassMap[$name];
877 $contentObject = GeneralUtility::makeInstance($fullyQualifiedClassName, $this);
878 if (!($contentObject instanceof AbstractContentObject)) {
879 throw new ContentRenderingException(sprintf('Registered content object class name "%" must be an instance of AbstractContentObject, but is not!', $fullyQualifiedClassName), 1422564295);
880 }
881 return $contentObject;
882 }
883
884 /********************************************
885 *
886 * Functions rendering content objects (cObjects)
887 *
888 ********************************************/
889
890 /**
891 * Renders a content object by taking exception handling into consideration
892 *
893 * @param AbstractContentObject $contentObject Content object instance
894 * @param array $configuration Array of TypoScript properties
895 *
896 * @throws ContentRenderingException
897 * @throws \Exception
898 * @return string
899 */
900 public function render(AbstractContentObject $contentObject, $configuration = array()) {
901 $content = '';
902 try {
903 $content .= $contentObject->render($configuration);
904 } catch (ContentRenderingException $exception) {
905 // Content rendering Exceptions indicate a critical problem which should not be
906 // caught e.g. when something went wrong with Exception handling itself
907 throw $exception;
908 } catch (\Exception $exception) {
909 $exceptionHandler = $this->createExceptionHandler($configuration);
910 if ($exceptionHandler === NULL) {
911 throw $exception;
912 } else {
913 $content = $exceptionHandler->handle($exception, $contentObject, $configuration);
914 }
915 }
916 return $content;
917 }
918
919 /**
920 * Creates the content object exception handler from local content object configuration
921 * or, from global configuration if not explicitly disabled in local configuration
922 *
923 * @param array $configuration
924 * @return NULL|ExceptionHandlerInterface
925 * @throws ContentRenderingException
926 */
927 protected function createExceptionHandler($configuration = array()) {
928 $exceptionHandler = NULL;
929 $exceptionHandlerClassName = $this->determineExceptionHandlerClassName($configuration);
930 if (!empty($exceptionHandlerClassName)) {
931 $exceptionHandler = GeneralUtility::makeInstance($exceptionHandlerClassName, $this->mergeExceptionHandlerConfiguration($configuration));
932 if (!$exceptionHandler instanceof ExceptionHandlerInterface) {
933 throw new ContentRenderingException('An exception handler was configured but the class does not exist or does not implement the ExceptionHandlerInterface', 1403653369);
934 }
935 }
936
937 return $exceptionHandler;
938 }
939
940 /**
941 * Determine exception handler class name from global and content object configuration
942 *
943 * @param array $configuration
944 * @return string|NULL
945 */
946 protected function determineExceptionHandlerClassName($configuration) {
947 $exceptionHandlerClassName = NULL;
948 if (!isset($this->typoScriptFrontendController->config['config']['contentObjectExceptionHandler'])) {
949 if (GeneralUtility::getApplicationContext()->isProduction()) {
950 $exceptionHandlerClassName = '1';
951 }
952 } else {
953 $exceptionHandlerClassName = $this->typoScriptFrontendController->config['config']['contentObjectExceptionHandler'];
954 }
955
956 if (isset($configuration['exceptionHandler'])) {
957 $exceptionHandlerClassName = $configuration['exceptionHandler'];
958 }
959
960 if ($exceptionHandlerClassName === '1') {
961 $exceptionHandlerClassName = ProductionExceptionHandler::class;
962 }
963
964 return $exceptionHandlerClassName;
965 }
966
967 /**
968 * Merges global exception handler configuration with the one from the content object
969 * and returns the merged exception handler configuration
970 *
971 * @param array $configuration
972 * @return array
973 */
974 protected function mergeExceptionHandlerConfiguration($configuration) {
975 $exceptionHandlerConfiguration = array();
976 if (!empty($this->typoScriptFrontendController->config['config']['contentObjectExceptionHandler.'])) {
977 $exceptionHandlerConfiguration = $this->typoScriptFrontendController->config['config']['contentObjectExceptionHandler.'];
978 }
979 if (!empty($configuration['exceptionHandler.'])) {
980 $exceptionHandlerConfiguration = array_replace_recursive($exceptionHandlerConfiguration, $configuration['exceptionHandler.']);
981 }
982
983 return $exceptionHandlerConfiguration;
984 }
985 /**
986 * Rendering the cObject, FLOWPLAYER
987 *
988 * @param array $conf Array of TypoScript properties
989 * @return string Output
990 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('FLOWPLAYER', $conf) instead
991 */
992 public function FLOWPLAYER($conf) {
993 GeneralUtility::logDeprecatedFunction();
994 return $this->render($this->getContentObject('FLOWPLAYER'), $conf);
995 }
996
997 /**
998 * Rendering the cObject, TEXT
999 *
1000 * @param array $conf Array of TypoScript properties
1001 * @return string Output
1002 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('TEXT', $conf) instead
1003 */
1004 public function TEXT($conf) {
1005 GeneralUtility::logDeprecatedFunction();
1006 return $this->render($this->getContentObject('TEXT'), $conf);
1007 }
1008
1009 /**
1010 * Rendering the cObject, CLEARGIF
1011 *
1012 * @param array $conf Array of TypoScript properties
1013 * @return string Output
1014 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('CLEARGIF', $conf) instead
1015 */
1016 public function CLEARGIF($conf) {
1017 GeneralUtility::logDeprecatedFunction();
1018 return $this->render($this->getContentObject('CLEARGIF'), $conf);
1019 }
1020
1021 /**
1022 * Rendering the cObject, COBJ_ARRAY / COA and COBJ_ARRAY_INT
1023 *
1024 * @param array $conf Array of TypoScript properties
1025 * @param string $ext If "INT" then the cObject is a "COBJ_ARRAY_INT" (non-cached), otherwise just "COBJ_ARRAY" (cached)
1026 * @return string Output
1027 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('COA', $conf) or $cObj->cObjGetSingle('COA_INT', $conf) instead
1028 */
1029 public function COBJ_ARRAY($conf, $ext = '') {
1030 GeneralUtility::logDeprecatedFunction();
1031 if ($ext === 'INT') {
1032 return $this->render($this->getContentObject('COA_INT'), $conf);
1033 } else {
1034 return $this->render($this->getContentObject('COA'), $conf);
1035 }
1036 }
1037
1038 /**
1039 * Rendering the cObject, USER and USER_INT
1040 *
1041 * @param array $conf Array of TypoScript properties
1042 * @param string $ext If "INT" then the cObject is a "USER_INT" (non-cached), otherwise just "USER" (cached)
1043 * @return string Output
1044 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('USER', $conf) or $cObj->cObjGetSingle('USER_INT', $conf) instead
1045 */
1046 public function USER($conf, $ext = '') {
1047 GeneralUtility::logDeprecatedFunction();
1048 if ($ext === 'INT') {
1049 return $this->render($this->getContentObject('USER_INT'), $conf);
1050 } else {
1051 return $this->render($this->getContentObject('USER'), $conf);
1052 }
1053 }
1054
1055 /**
1056 * Retrieves a type of object called as USER or USER_INT. Object can detect their
1057 * type by using this call. It returns OBJECTTYPE_USER_INT or OBJECTTYPE_USER depending on the
1058 * current object execution. In all other cases it will return FALSE to indicate
1059 * a call out of context.
1060 *
1061 * @return mixed One of OBJECTTYPE_ class constants or FALSE
1062 */
1063 public function getUserObjectType() {
1064 return $this->userObjectType;
1065 }
1066
1067 /**
1068 * Sets the user object type
1069 *
1070 * @param mixed $userObjectType
1071 * @return void
1072 */
1073 public function setUserObjectType($userObjectType) {
1074 $this->userObjectType = $userObjectType;
1075 }
1076
1077 /**
1078 * Requests the current USER object to be converted to USER_INT.
1079 *
1080 * @return void
1081 */
1082 public function convertToUserIntObject() {
1083 if ($this->userObjectType !== self::OBJECTTYPE_USER) {
1084 $GLOBALS['TT']->setTSlogMessage(ContentObjectRenderer::class . '::convertToUserIntObject() is called in the wrong context or for the wrong object type', 2);
1085 } else {
1086 $this->doConvertToUserIntObject = TRUE;
1087 }
1088 }
1089
1090 /**
1091 * Rendering the cObject, FILE
1092 *
1093 * @param array $conf Array of TypoScript properties
1094 * @return string Output
1095 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('FILE', $conf) instead
1096 */
1097 public function FILE($conf) {
1098 GeneralUtility::logDeprecatedFunction();
1099 return $this->render($this->getContentObject('FILE'), $conf);
1100 }
1101
1102 /**
1103 * Rendering the cObject, FILES
1104 *
1105 * @param array $conf Array of TypoScript properties
1106 * @return string Output
1107 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('FILES', $conf) instead
1108 */
1109 public function FILES($conf) {
1110 GeneralUtility::logDeprecatedFunction();
1111 return $this->render($this->getContentObject('FILES'), $conf);
1112 }
1113
1114 /**
1115 * Rendering the cObject, IMAGE
1116 *
1117 * @param array $conf Array of TypoScript properties
1118 * @return string Output
1119 * @see cImage()
1120 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('IMAGE', $conf) instead
1121 */
1122 public function IMAGE($conf) {
1123 GeneralUtility::logDeprecatedFunction();
1124 return $this->render($this->getContentObject('IMAGE'), $conf);
1125 }
1126
1127 /**
1128 * Rendering the cObject, IMG_RESOURCE
1129 *
1130 * @param array $conf Array of TypoScript properties
1131 * @return string Output
1132 * @see getImgResource()
1133 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('IMG_RESOURCE', $conf) instead
1134 */
1135 public function IMG_RESOURCE($conf) {
1136 GeneralUtility::logDeprecatedFunction();
1137 return $this->render($this->getContentObject('IMG_RESOURCE'), $conf);
1138 }
1139
1140 /**
1141 * Rendering the cObject, IMGTEXT
1142 *
1143 * @param array $conf Array of TypoScript properties
1144 * @return string Output
1145 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('IMGTEXT', $conf) instead
1146 */
1147 public function IMGTEXT($conf) {
1148 GeneralUtility::logDeprecatedFunction();
1149 return $this->render($this->getContentObject('IMGTEXT'), $conf);
1150 }
1151
1152 /**
1153 * Rendering the cObject, CONTENT
1154 *
1155 * @param array $conf Array of TypoScript properties
1156 * @return string Output
1157 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('CONTENT', $conf) instead
1158 */
1159 public function CONTENT($conf) {
1160 GeneralUtility::logDeprecatedFunction();
1161 return $this->render($this->getContentObject('CONTENT'), $conf);
1162 }
1163
1164 /**
1165 * Rendering the cObject, RECORDS
1166 *
1167 * @param array $conf Array of TypoScript properties
1168 * @return string Output
1169 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('RECORDS', $conf) instead
1170 */
1171 public function RECORDS($conf) {
1172 GeneralUtility::logDeprecatedFunction();
1173 return $this->render($this->getContentObject('RECORDS'), $conf);
1174 }
1175
1176 /**
1177 * Rendering the cObject, HMENU
1178 *
1179 * @param array $conf Array of TypoScript properties
1180 * @return string Output
1181 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('HMENU', $conf) instead
1182 */
1183 public function HMENU($conf) {
1184 GeneralUtility::logDeprecatedFunction();
1185 return $this->render($this->getContentObject('HMENU'), $conf);
1186 }
1187
1188 /**
1189 * Rendering the cObject, CTABLE
1190 *
1191 * @param array $conf Array of TypoScript properties
1192 * @return string Output
1193 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('CTABLE', $conf) instead
1194 */
1195 public function CTABLE($conf) {
1196 GeneralUtility::logDeprecatedFunction();
1197 return $this->render($this->getContentObject('CTABLE'), $conf);
1198 }
1199
1200 /**
1201 * Rendering the cObject, OTABLE
1202 *
1203 * @param array $conf Array of TypoScript properties
1204 * @return string Output
1205 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('OTABLE', $conf) instead
1206 */
1207 public function OTABLE($conf) {
1208 GeneralUtility::logDeprecatedFunction();
1209 return $this->render($this->getContentObject('OTABLE'), $conf);
1210 }
1211
1212 /**
1213 * Rendering the cObject, COLUMNS
1214 *
1215 * @param array $conf Array of TypoScript properties
1216 * @return string Output
1217 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('COLUMNS', $conf) instead
1218 */
1219 public function COLUMNS($conf) {
1220 GeneralUtility::logDeprecatedFunction();
1221 return $this->render($this->getContentObject('COLUMNS'), $conf);
1222 }
1223
1224 /**
1225 * Rendering the cObject, HRULER
1226 *
1227 * @param array $conf Array of TypoScript properties
1228 * @return string Output
1229 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('HRULER', $conf) instead
1230 */
1231 public function HRULER($conf) {
1232 GeneralUtility::logDeprecatedFunction();
1233 return $this->render($this->getContentObject('HRULER'), $conf);
1234 }
1235
1236 /**
1237 * Rendering the cObject, CASE
1238 *
1239 * @param array $conf Array of TypoScript properties
1240 * @return string Output
1241 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('CASE', $conf) instead
1242 */
1243 public function CASEFUNC($conf) {
1244 GeneralUtility::logDeprecatedFunction();
1245 return $this->render($this->getContentObject('CASE'), $conf);
1246 }
1247
1248 /**
1249 * Rendering the cObject, LOAD_REGISTER and RESTORE_REGISTER
1250 * NOTICE: This cObject does NOT return any content since it just sets internal data based on the TypoScript properties.
1251 *
1252 * @param array $conf Array of TypoScript properties
1253 * @param string $name If "RESTORE_REGISTER" then the cObject rendered is "RESTORE_REGISTER", otherwise "LOAD_REGISTER"
1254 * @return string Empty string (the cObject only sets internal data!)
1255 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('LOAD_REGISTER', $conf) and $cObj->cObjGetSingle('RESTORE_REGISTER', $conf) instead
1256 */
1257 public function LOAD_REGISTER($conf, $name) {
1258 GeneralUtility::logDeprecatedFunction();
1259 if ($name === 'RESTORE_REGISTER') {
1260 return $this->render($this->getContentObject('RESTORE_REGISTER'), $conf);
1261 } else {
1262 return $this->render($this->getContentObject('LOAD_REGISTER'), $conf);
1263 }
1264 }
1265
1266 /**
1267 * Rendering the cObject, FORM
1268 *
1269 * @param array $conf Array of TypoScript properties
1270 * @param array $formData Alternative formdata overriding whatever comes from TypoScript
1271 * @return string Output
1272 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('FORM', $conf) instead
1273 */
1274 public function FORM($conf, $formData = '') {
1275 GeneralUtility::logDeprecatedFunction();
1276 return $this->render($this->getContentObject('FORM'), $conf);
1277 }
1278
1279 /**
1280 * Rendering the cObject, SEARCHRESULT
1281 *
1282 * @param array $conf Array of TypoScript properties
1283 * @return string Output
1284 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('SEARCHRESULT', $conf) instead
1285 */
1286 public function SEARCHRESULT($conf) {
1287 GeneralUtility::logDeprecatedFunction();
1288 return $this->render($this->getContentObject('SEARCHRESULT'), $conf);
1289 }
1290
1291 /**
1292 * Rendering the cObject, TEMPLATE
1293 *
1294 * @param array $conf Array of TypoScript properties
1295 * @return string Output
1296 * @see substituteMarkerArrayCached()
1297 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('TEMPLATE', $conf) instead
1298 */
1299 public function TEMPLATE($conf) {
1300 GeneralUtility::logDeprecatedFunction();
1301 return $this->render($this->getContentObject('TEMPLATE'), $conf);
1302 }
1303
1304 /**
1305 * Rendering the cObject, FLUIDTEMPLATE
1306 *
1307 * @param array $conf Array of TypoScript properties
1308 * @return string the HTML output
1309 * @author Steffen Ritter <info@steffen-ritter.net>
1310 * @author Benjamin Mack <benni@typo3.org>
1311 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('FLUIDTEMPLATE', $conf) instead
1312 */
1313 protected function FLUIDTEMPLATE(array $conf) {
1314 GeneralUtility::logDeprecatedFunction();
1315 return $this->render($this->getContentObject('FLUIDTEMPLATE'), $conf);
1316 }
1317
1318 /**
1319 * Rendering the cObject, MULTIMEDIA
1320 *
1321 * @param array $conf Array of TypoScript properties
1322 * @return string Output
1323 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('MULTIMEDIA', $conf) instead
1324 */
1325 public function MULTIMEDIA($conf) {
1326 GeneralUtility::logDeprecatedFunction();
1327 return $this->render($this->getContentObject('MULTIMEDIA'), $conf);
1328 }
1329
1330 /**
1331 * Rendering the cObject, MEDIA
1332 *
1333 * @param array $conf Array of TypoScript properties
1334 * @return string Output
1335 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('MEDIA', $conf) instead
1336 */
1337 public function MEDIA($conf) {
1338 GeneralUtility::logDeprecatedFunction();
1339 return $this->render($this->getContentObject('MEDIA'), $conf);
1340 }
1341
1342 /**
1343 * Rendering the cObject, SWFOBJECT
1344 *
1345 * @param array $conf Array of TypoScript properties
1346 * @return string Output
1347 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('SWFOBJECT', $conf) instead
1348 */
1349 public function SWFOBJECT($conf) {
1350 GeneralUtility::logDeprecatedFunction();
1351 return $this->render($this->getContentObject('SWFOBJECT'), $conf);
1352 }
1353
1354 /**
1355 * Rendering the cObject, QTOBJECT
1356 *
1357 * @param array $conf Array of TypoScript properties
1358 * @return string Output
1359 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('QTOBJECT', $conf) instead
1360 */
1361 public function QTOBJECT($conf) {
1362 GeneralUtility::logDeprecatedFunction();
1363 return $this->render($this->getContentObject('QTOBJECT'), $conf);
1364 }
1365
1366 /**
1367 * Rendering the cObject, SVG
1368 *
1369 * @param array $conf Array of TypoScript properties
1370 * @return string Output
1371 * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use $cObj->cObjGetSingle('SVG', $conf) instead
1372 */
1373 public function SVG($conf) {
1374 GeneralUtility::logDeprecatedFunction();
1375 return $this->render($this->getContentObject('SVG'), $conf);
1376 }
1377
1378 /************************************
1379 *
1380 * Various helper functions for content objects:
1381 *
1382 ************************************/
1383 /**
1384 * Converts a given config in Flexform to a conf-array
1385 *
1386 * @param string|array $flexData Flexform data
1387 * @param array $conf Array to write the data into, by reference
1388 * @param bool $recursive Is set if called recursive. Don't call function with this parameter, it's used inside the function only
1389 * @return void
1390 */
1391 public function readFlexformIntoConf($flexData, &$conf, $recursive = FALSE) {
1392 if ($recursive === FALSE && is_string($flexData)) {
1393 $flexData = GeneralUtility::xml2array($flexData, 'T3');
1394 }
1395 if (is_array($flexData) && isset($flexData['data']['sDEF']['lDEF'])) {
1396 $flexData = $flexData['data']['sDEF']['lDEF'];
1397 }
1398 if (!is_array($flexData)) {
1399 return;
1400 }
1401 foreach ($flexData as $key => $value) {
1402 if (!is_array($value)) {
1403 continue;
1404 }
1405 if (isset($value['el'])) {
1406 if (is_array($value['el']) && count($value['el']) > 0) {
1407 foreach ($value['el'] as $ekey => $element) {
1408 if (isset($element['vDEF'])) {
1409 $conf[$ekey] = $element['vDEF'];
1410 } else {
1411 if (is_array($element)) {
1412 $this->readFlexformIntoConf($element, $conf[$key][key($element)][$ekey], TRUE);
1413 } else {
1414 $this->readFlexformIntoConf($element, $conf[$key][$ekey], TRUE);
1415 }
1416 }
1417 }
1418 } else {
1419 $this->readFlexformIntoConf($value['el'], $conf[$key], TRUE);
1420 }
1421 }
1422 if (isset($value['vDEF'])) {
1423 $conf[$key] = $value['vDEF'];
1424 }
1425 }
1426 }
1427
1428 /**
1429 * Returns all parents of the given PID (Page UID) list
1430 *
1431 * @param string $pidList A list of page Content-Element PIDs (Page UIDs) / stdWrap
1432 * @param array $pidConf stdWrap array for the list
1433 * @return string A list of PIDs
1434 * @access private
1435 */
1436 public function getSlidePids($pidList, $pidConf) {
1437 $pidList = isset($pidConf) ? trim($this->stdWrap($pidList, $pidConf)) : trim($pidList);
1438 if ($pidList === '') {
1439 $pidList = 'this';
1440 }
1441 if (trim($pidList)) {
1442 $listArr = GeneralUtility::intExplode(',', str_replace('this', $GLOBALS['TSFE']->contentPid, $pidList));
1443 $listArr = $this->checkPidArray($listArr);
1444 }
1445 $pidList = array();
1446 if (is_array($listArr) && count($listArr)) {
1447 foreach ($listArr as $uid) {
1448 $page = $GLOBALS['TSFE']->sys_page->getPage($uid);
1449 if (!$page['is_siteroot']) {
1450 $pidList[] = $page['pid'];
1451 }
1452 }
1453 }
1454 return implode(',', $pidList);
1455 }
1456
1457 /**
1458 * Returns a <img> tag with the image file defined by $file and processed according to the properties in the TypoScript array.
1459 * Mostly this function is a sub-function to the IMAGE function which renders the IMAGE cObject in TypoScript.
1460 * This function is called by "$this->cImage($conf['file'], $conf);" from IMAGE().
1461 *
1462 * @param string $file File TypoScript resource
1463 * @param array $conf TypoScript configuration properties
1464 * @return string <img> tag, (possibly wrapped in links and other HTML) if any image found.
1465 * @access private
1466 * @see IMAGE()
1467 */
1468 public function cImage($file, $conf) {
1469 $info = $this->getImgResource($file, $conf['file.']);
1470 $GLOBALS['TSFE']->lastImageInfo = $info;
1471 if (!is_array($info)) {
1472 return '';
1473 }
1474 if (is_file(PATH_site . $info['3'])) {
1475 $source = GeneralUtility::rawUrlEncodeFP(GraphicalFunctions::pngToGifByImagemagick($info[3]));
1476 $source = $GLOBALS['TSFE']->absRefPrefix . $source;
1477 } else {
1478 $source = $info[3];
1479 }
1480
1481 $layoutKey = $this->stdWrap($conf['layoutKey'], $conf['layoutKey.']);
1482 $imageTagTemplate = $this->getImageTagTemplate($layoutKey, $conf);
1483 $sourceCollection = $this->getImageSourceCollection($layoutKey, $conf, $file);
1484
1485 // This array is used to collect the image-refs on the page...
1486 $GLOBALS['TSFE']->imagesOnPage[] = $source;
1487 $altParam = $this->getAltParam($conf);
1488 $params = $this->stdWrapValue('params', $conf);
1489 if ($params !== '' && $params{0} !== ' ') {
1490 $params = ' ' . $params;
1491 }
1492
1493 $imageTagValues = array(
1494 'width' => $info[0],
1495 'height' => $info[1],
1496 'src' => htmlspecialchars($source),
1497 'params' => $params,
1498 'altParams' => $altParam,
1499 'border' => $this->getBorderAttr(' border="' . (int)$conf['border'] . '"'),
1500 'sourceCollection' => $sourceCollection,
1501 'selfClosingTagSlash' => (!empty($GLOBALS['TSFE']->xhtmlDoctype) ? ' /' : ''),
1502 );
1503
1504 $theValue = $this->substituteMarkerArray($imageTagTemplate, $imageTagValues, '###|###', TRUE, TRUE);
1505
1506 $linkWrap = isset($conf['linkWrap.']) ? $this->stdWrap($conf['linkWrap'], $conf['linkWrap.']) : $conf['linkWrap'];
1507 if ($linkWrap) {
1508 $theValue = $this->linkWrap($theValue, $linkWrap);
1509 } elseif ($conf['imageLinkWrap']) {
1510 $originalFile = !empty($info['originalFile']) ? $info['originalFile'] : $info['origFile'];
1511 $theValue = $this->imageLinkWrap($theValue, $originalFile, $conf['imageLinkWrap.']);
1512 }
1513 $wrap = isset($conf['wrap.']) ? $this->stdWrap($conf['wrap'], $conf['wrap.']) : $conf['wrap'];
1514 if ($wrap) {
1515 $theValue = $this->wrap($theValue, $conf['wrap']);
1516 }
1517 return $theValue;
1518 }
1519
1520 /**
1521 * Returns the 'border' attribute for an <img> tag only if the doctype is not xhtml_strict, xhtml_11, xhtml_2 or html5
1522 * or if the config parameter 'disableImgBorderAttr' is not set.
1523 *
1524 * @param string $borderAttr The border attribute
1525 * @return string The border attribute
1526 */
1527 public function getBorderAttr($borderAttr) {
1528 if (!GeneralUtility::inList('xhtml_strict,xhtml_11,xhtml_2', $GLOBALS['TSFE']->xhtmlDoctype) && $GLOBALS['TSFE']->config['config']['doctype'] != 'html5' && !$GLOBALS['TSFE']->config['config']['disableImgBorderAttr']) {
1529 return $borderAttr;
1530 }
1531 }
1532
1533 /**
1534 * Returns the html-template for rendering the image-Tag if no template is defined via typoscript the
1535 * default <img> tag template is returned
1536 *
1537 * @param string $layoutKey rendering key
1538 * @param array $conf TypoScript configuration properties
1539 * @return string
1540 */
1541 public function getImageTagTemplate($layoutKey, $conf) {
1542 if ($layoutKey && isset($conf['layout.']) && isset($conf['layout.'][$layoutKey . '.'])) {
1543 $imageTagLayout = $this->stdWrap($conf['layout.'][$layoutKey . '.']['element'], $conf['layout.'][$layoutKey . '.']['element.']);
1544 } else {
1545 $imageTagLayout = '<img src="###SRC###" width="###WIDTH###" height="###HEIGHT###" ###PARAMS### ###ALTPARAMS### ###BORDER######SELFCLOSINGTAGSLASH###>';
1546 }
1547 return $imageTagLayout;
1548 }
1549
1550 /**
1551 * Render alternate sources for the image tag. If no source collection is given an empty string is returned.
1552 *
1553 * @param string $layoutKey rendering key
1554 * @param array $conf TypoScript configuration properties
1555 * @param string $file
1556 * @throws \UnexpectedValueException
1557 * @return string
1558 */
1559 public function getImageSourceCollection($layoutKey, $conf, $file) {
1560 $sourceCollection = '';
1561 if ($layoutKey && $conf['sourceCollection.'] && ($conf['layout.'][$layoutKey . '.']['source'] || $conf['layout.'][$layoutKey . '.']['source.'])) {
1562
1563 // find active sourceCollection
1564 $activeSourceCollections = array();
1565 foreach ($conf['sourceCollection.'] as $sourceCollectionKey => $sourceCollectionConfiguration) {
1566 if (substr($sourceCollectionKey, -1) == '.') {
1567 if (empty($sourceCollectionConfiguration['if.']) || $this->checkIf($sourceCollectionConfiguration['if.'])) {
1568 $activeSourceCollections[] = $sourceCollectionConfiguration;
1569 }
1570 }
1571 }
1572
1573 // apply option split to configurations
1574 $srcLayoutOptionSplitted = $GLOBALS['TSFE']->tmpl->splitConfArray($conf['layout.'][$layoutKey . '.'], count($activeSourceCollections));
1575
1576 // render sources
1577 foreach ($activeSourceCollections as $key => $sourceConfiguration) {
1578 $sourceLayout = $this->stdWrap($srcLayoutOptionSplitted[$key]['source'], $srcLayoutOptionSplitted[$key]['source.']);
1579
1580 $sourceRenderConfiguration = array (
1581 'file' => $file,
1582 'file.' => $conf['file.']
1583 );
1584
1585 if (isset($sourceConfiguration['pixelDensity'])) {
1586 $pixelDensity = (int)$this->stdWrap($sourceConfiguration['pixelDensity'], $sourceConfiguration['pixelDensity.']);
1587 } else {
1588 $pixelDensity = 1;
1589 }
1590 $dimensionKeys = array('width', 'height', 'maxW', 'minW', 'maxH', 'minH');
1591 foreach ($dimensionKeys as $dimensionKey) {
1592 $dimension = $this->stdWrap($sourceConfiguration[$dimensionKey], $sourceConfiguration[$dimensionKey . '.']);
1593 if (!$dimension) {
1594 $dimension = $this->stdWrap($conf['file.'][$dimensionKey], $conf['file.'][$dimensionKey . '.']);
1595 }
1596 if ($dimension) {
1597 if (strstr($dimension, 'c') !== FALSE && ($dimensionKey === 'width' || $dimensionKey === 'height')) {
1598 $dimensionParts = explode('c', $dimension, 2);
1599 $dimension = (int)($dimensionParts[0] * $pixelDensity) . 'c';
1600 if ($dimensionParts[1]) {
1601 $dimension .= $dimensionParts[1];
1602 }
1603 } else {
1604 $dimension = (int)($dimension * $pixelDensity);
1605 }
1606 $sourceRenderConfiguration['file.'][$dimensionKey] = $dimension;
1607 // Remove the stdWrap properties for dimension as they have been processed already above.
1608 unset($sourceRenderConfiguration['file.'][$dimensionKey . '.']);
1609 }
1610 }
1611 $sourceInfo = $this->getImgResource($sourceRenderConfiguration['file'], $sourceRenderConfiguration['file.']);
1612 if ($sourceInfo) {
1613 $sourceConfiguration['width'] = $sourceInfo[0];
1614 $sourceConfiguration['height'] = $sourceInfo[1];
1615 $sourceConfiguration['src'] = htmlspecialchars($GLOBALS['TSFE']->absRefPrefix . $sourceInfo[3]);
1616 $sourceConfiguration['selfClosingTagSlash'] = (!empty($GLOBALS['TSFE']->xhtmlDoctype) ? ' /' : '');
1617
1618 $oneSourceCollection = $this->substituteMarkerArray($sourceLayout, $sourceConfiguration, '###|###', TRUE, TRUE);
1619
1620 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImageSourceCollection'])) {
1621 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImageSourceCollection'] as $classData) {
1622 $hookObject = GeneralUtility::getUserObj($classData);
1623 if (!$hookObject instanceof ContentObjectOneSourceCollectionHookInterface) {
1624 throw new \UnexpectedValueException(
1625 '$hookObject must implement interface ' . ContentObjectOneSourceCollectionHookInterface::class,
1626 1380007853
1627 );
1628 }
1629 $oneSourceCollection = $hookObject->getOneSourceCollection((array)$sourceRenderConfiguration, (array)$sourceConfiguration, $oneSourceCollection, $this);
1630 }
1631 }
1632
1633 $sourceCollection .= $oneSourceCollection;
1634 }
1635 }
1636 }
1637 return $sourceCollection;
1638 }
1639
1640 /**
1641 * Wraps the input string in link-tags that opens the image in a new window.
1642 *
1643 * @param string $string String to wrap, probably an <img> tag
1644 * @param string|File|FileReference $imageFile The original image file
1645 * @param array $conf TypoScript properties for the "imageLinkWrap" function
1646 * @return string The input string, $string, wrapped as configured.
1647 * @see cImage()
1648 */
1649 public function imageLinkWrap($string, $imageFile, $conf) {
1650 $a1 = '';
1651 $a2 = '';
1652 $content = $string;
1653 $enable = isset($conf['enable.']) ? $this->stdWrap($conf['enable'], $conf['enable.']) : $conf['enable'];
1654 if ($enable) {
1655 $content = $this->typolink($string, $conf['typolink.']);
1656 if (isset($conf['file.'])) {
1657 $imageFile = $this->stdWrap($imageFile, $conf['file.']);
1658 }
1659
1660 if ($imageFile instanceof File) {
1661 $file = $imageFile;
1662 } elseif ($imageFile instanceof FileReference) {
1663 $file = $imageFile->getOriginalFile();
1664 } else {
1665 if (MathUtility::canBeInterpretedAsInteger($imageFile)) {
1666 $file = ResourceFactory::getInstance()->getFileObject((int)$imageFile);
1667 } else {
1668 $file = ResourceFactory::getInstance()->getFileObjectFromCombinedIdentifier($imageFile);
1669 }
1670 }
1671
1672 // Create imageFileLink if not created with typolink
1673 if ($content == $string) {
1674 $parameterNames = array('width', 'height', 'effects', 'bodyTag', 'title', 'wrap');
1675 $parameters = array();
1676 $sample = isset($conf['sample.']) ? $this->stdWrap($conf['sample'], $conf['sample.']) : $conf['sample'];
1677 if ($sample) {
1678 $parameters['sample'] = 1;
1679 }
1680 foreach ($parameterNames as $parameterName) {
1681 if (isset($conf[$parameterName . '.'])) {
1682 $conf[$parameterName] = $this->stdWrap($conf[$parameterName], $conf[$parameterName . '.']);
1683 }
1684 if (isset($conf[$parameterName]) && $conf[$parameterName]) {
1685 $parameters[$parameterName] = $conf[$parameterName];
1686 }
1687 }
1688 $parametersEncoded = base64_encode(serialize($parameters));
1689 $hmac = GeneralUtility::hmac(implode('|', array($file->getUid(), $parametersEncoded)));
1690 $params = '&md5=' . $hmac;
1691 foreach (str_split($parametersEncoded, 64) as $index => $chunk) {
1692 $params .= '&parameters' . rawurlencode('[') . $index . rawurlencode(']') . '=' . rawurlencode($chunk);
1693 }
1694 $url = $GLOBALS['TSFE']->absRefPrefix . 'index.php?eID=tx_cms_showpic&file=' . $file->getUid() . $params;
1695 $directImageLink = isset($conf['directImageLink.']) ? $this->stdWrap($conf['directImageLink'], $conf['directImageLink.']) : $conf['directImageLink'];
1696 if ($directImageLink) {
1697 $imgResourceConf = array(
1698 'file' => $imageFile,
1699 'file.' => $conf
1700 );
1701 $url = $this->cObjGetSingle('IMG_RESOURCE', $imgResourceConf);
1702 if (!$url) {
1703 // If no imagemagick / gm is available
1704 $url = $imageFile;
1705 }
1706 }
1707 // Create TARGET-attribute only if the right doctype is used
1708 if (!GeneralUtility::inList('xhtml_strict,xhtml_11,xhtml_2', $GLOBALS['TSFE']->xhtmlDoctype)) {
1709 $target = isset($conf['target.']) ? $this->stdWrap($conf['target'], $conf['target.']) : $conf['target'];
1710 if ($target) {
1711 $target = sprintf(' target="%s"', $target);
1712 } else {
1713 $target = ' target="thePicture"';
1714 }
1715 } else {
1716 $target = '';
1717 }
1718 $conf['JSwindow'] = isset($conf['JSwindow.']) ? $this->stdWrap($conf['JSwindow'], $conf['JSwindow.']) : $conf['JSwindow'];
1719 if ($conf['JSwindow']) {
1720 if ($conf['JSwindow.']['altUrl'] || $conf['JSwindow.']['altUrl.']) {
1721 $altUrl = isset($conf['JSwindow.']['altUrl.']) ? $this->stdWrap($conf['JSwindow.']['altUrl'], $conf['JSwindow.']['altUrl.']) : $conf['JSwindow.']['altUrl'];
1722 if ($altUrl) {
1723 $url = $altUrl . ($conf['JSwindow.']['altUrl_noDefaultParams'] ? '' : '?file=' . rawurlencode($imageFile) . $params);
1724 }
1725 }
1726
1727 $processedFile = $file->process('Image.CropScaleMask', $conf);
1728 $JSwindowExpand = isset($conf['JSwindow.']['expand.']) ? $this->stdWrap($conf['JSwindow.']['expand'], $conf['JSwindow.']['expand.']) : $conf['JSwindow.']['expand'];
1729 $offset = GeneralUtility::intExplode(',', $JSwindowExpand . ',');
1730 $newWindow = isset($conf['JSwindow.']['newWindow.']) ? $this->stdWrap($conf['JSwindow.']['newWindow'], $conf['JSwindow.']['newWindow.']) : $conf['JSwindow.']['newWindow'];
1731 $a1 = '<a href="' . htmlspecialchars($url) . '" onclick="' . htmlspecialchars(('openPic(\'' . $GLOBALS['TSFE']->baseUrlWrap($url) . '\',\'' . ($newWindow ? md5($url) : 'thePicture') . '\',\'width=' . ($processedFile->getProperty('width') + $offset[0]) . ',height=' . ($processedFile->getProperty('height') + $offset[1]) . ',status=0,menubar=0\'); return false;')) . '"' . $target . $GLOBALS['TSFE']->ATagParams . '>';
1732 $a2 = '</a>';
1733 $GLOBALS['TSFE']->setJS('openPic');
1734 } else {
1735 $conf['linkParams.']['parameter'] = $url;
1736 $string = $this->typoLink($string, $conf['linkParams.']);
1737 }
1738 if (isset($conf['stdWrap.'])) {
1739 $string = $this->stdWrap($string, $conf['stdWrap.']);
1740 }
1741 $content = $a1 . $string . $a2;
1742 }
1743 }
1744 return $content;
1745 }
1746
1747 /**
1748 * Returns content of a file. If it's an image the content of the file is not returned but rather an image tag is.
1749 *
1750 * @param string $fName The filename, being a TypoScript resource data type
1751 * @param string $addParams Additional parameters (attributes). Default is empty alt and title tags.
1752 * @return string If jpg,gif,jpeg,png: returns image_tag with picture in. If html,txt: returns content string
1753 * @see FILE()
1754 */
1755 public function fileResource($fName, $addParams = 'alt="" title=""') {
1756 $incFile = $GLOBALS['TSFE']->tmpl->getFileName($fName);
1757 if ($incFile && file_exists($incFile)) {
1758 $fileinfo = GeneralUtility::split_fileref($incFile);
1759 if (GeneralUtility::inList('jpg,gif,jpeg,png', $fileinfo['fileext'])) {
1760 $imgFile = $incFile;
1761 $imgInfo = @getImageSize($imgFile);
1762 return '<img src="' . $GLOBALS['TSFE']->absRefPrefix . $imgFile . '" width="' . $imgInfo[0] . '" height="' . $imgInfo[1] . '"' . $this->getBorderAttr(' border="0"') . ' ' . $addParams . ' />';
1763 } elseif (filesize($incFile) < 1024 * 1024) {
1764 return $GLOBALS['TSFE']->tmpl->fileContent($incFile);
1765 }
1766 }
1767 }
1768
1769 /**
1770 * Sets the SYS_LASTCHANGED timestamp if input timestamp is larger than current value.
1771 * The SYS_LASTCHANGED timestamp can be used by various caching/indexing applications to determine if the page has new content.
1772 * Therefore you should call this function with the last-changed timestamp of any element you display.
1773 *
1774 * @param int $tstamp Unix timestamp (number of seconds since 1970)
1775 * @return void
1776 * @see TypoScriptFrontendController::setSysLastChanged()
1777 */
1778 public function lastChanged($tstamp) {
1779 $tstamp = (int)$tstamp;
1780 if ($tstamp > (int)$GLOBALS['TSFE']->register['SYS_LASTCHANGED']) {
1781 $GLOBALS['TSFE']->register['SYS_LASTCHANGED'] = $tstamp;
1782 }
1783 }
1784
1785 /**
1786 * Wraps the input string by the $wrap value and implements the "linkWrap" data type as well.
1787 * The "linkWrap" data type means that this function will find any integer encapsulated in {} (curly braces) in the first wrap part and substitute it with the corresponding page uid from the rootline where the found integer is pointing to the key in the rootline. See link below.
1788 *
1789 * @param string $content Input string
1790 * @param string $wrap A string where the first two parts separated by "|" (vertical line) will be wrapped around the input string
1791 * @return string Wrapped output string
1792 * @see wrap(), cImage(), FILE()
1793 */
1794 public function linkWrap($content, $wrap) {
1795 $wrapArr = explode('|', $wrap);
1796 if (preg_match('/\\{([0-9]*)\\}/', $wrapArr[0], $reg)) {
1797 if ($uid = $GLOBALS['TSFE']->tmpl->rootLine[$reg[1]]['uid']) {
1798 $wrapArr[0] = str_replace($reg[0], $uid, $wrapArr[0]);
1799 }
1800 }
1801 return trim($wrapArr[0]) . $content . trim($wrapArr[1]);
1802 }
1803
1804 /**
1805 * An abstraction method which creates an alt or title parameter for an HTML img, applet, area or input element and the FILE content element.
1806 * From the $conf array it implements the properties "altText", "titleText" and "longdescURL"
1807 *
1808 * @param array $conf TypoScript configuration properties
1809 * @param bool $longDesc If set, the longdesc attribute will be generated - must only be used for img elements!
1810 * @return string Parameter string containing alt and title parameters (if any)
1811 * @see IMGTEXT(), FILE(), FORM(), cImage(), filelink()
1812 */
1813 public function getAltParam($conf, $longDesc = TRUE) {
1814 $altText = isset($conf['altText.']) ? trim($this->stdWrap($conf['altText'], $conf['altText.'])) : trim($conf['altText']);
1815 $titleText = isset($conf['titleText.']) ? trim($this->stdWrap($conf['titleText'], $conf['titleText.'])) : trim($conf['titleText']);
1816 if (isset($conf['longdescURL.']) && $GLOBALS['TSFE']->config['config']['doctype'] != 'html5') {
1817 $longDesc = $this->typoLink_URL($conf['longdescURL.']);
1818 } else {
1819 $longDesc = trim($conf['longdescURL']);
1820 }
1821 // "alt":
1822 $altParam = ' alt="' . htmlspecialchars($altText) . '"';
1823 // "title":
1824 $emptyTitleHandling = 'useAlt';
1825 $emptyTitleHandling = isset($conf['emptyTitleHandling.']) ? $this->stdWrap($conf['emptyTitleHandling'], $conf['emptyTitleHandling.']) : $conf['emptyTitleHandling'];
1826 // Choices: 'keepEmpty' | 'useAlt' | 'removeAttr'
1827 if ($titleText || $emptyTitleHandling == 'keepEmpty') {
1828 $altParam .= ' title="' . htmlspecialchars($titleText) . '"';
1829 } elseif (!$titleText && $emptyTitleHandling == 'useAlt') {
1830 $altParam .= ' title="' . htmlspecialchars($altText) . '"';
1831 }
1832 // "longDesc" URL
1833 if ($longDesc) {
1834 $altParam .= ' longdesc="' . htmlspecialchars(strip_tags($longDesc)) . '"';
1835 }
1836 return $altParam;
1837 }
1838
1839 /**
1840 * Removes forbidden characters and spaces from name/id attributes in the form tag and formfields
1841 *
1842 * @param string $name Input string
1843 * @return string the cleaned string
1844 * @see FORM()
1845 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, the method is moved to FormContentObject
1846 */
1847 public function cleanFormName($name) {
1848 GeneralUtility::logDeprecatedFunction();
1849 // Turn data[x][y] into data:x:y:
1850 $name = preg_replace('/\\[|\\]\\[?/', ':', trim($name));
1851 // Remove illegal chars like _
1852 return preg_replace('#[^:a-zA-Z0-9]#', '', $name);
1853 }
1854
1855 /**
1856 * An abstraction method to add parameters to an A tag.
1857 * Uses the ATagParams property.
1858 *
1859 * @param array $conf TypoScript configuration properties
1860 * @param bool $addGlobal If set, will add the global config.ATagParams to the link
1861 * @return string String containing the parameters to the A tag (if non empty, with a leading space)
1862 * @see IMGTEXT(), filelink(), makelinks(), typolink()
1863 */
1864 public function getATagParams($conf, $addGlobal = 1) {
1865 $aTagParams = '';
1866 if ($conf['ATagParams.']) {
1867 $aTagParams = ' ' . $this->stdWrap($conf['ATagParams'], $conf['ATagParams.']);
1868 } elseif ($conf['ATagParams']) {
1869 $aTagParams = ' ' . $conf['ATagParams'];
1870 }
1871 if ($addGlobal) {
1872 $aTagParams = ' ' . trim(($GLOBALS['TSFE']->ATagParams . $aTagParams));
1873 }
1874 // Extend params
1875 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getATagParamsPostProc']) && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getATagParamsPostProc'])) {
1876 $_params = array(
1877 'conf' => &$conf,
1878 'aTagParams' => &$aTagParams
1879 );
1880 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getATagParamsPostProc'] as $objRef) {
1881 $processor =& GeneralUtility::getUserObj($objRef);
1882 $aTagParams = $processor->process($_params, $this);
1883 }
1884 }
1885
1886 $aTagParams = trim($aTagParams);
1887 if (!empty($aTagParams)) {
1888 $aTagParams = ' ' . $aTagParams;
1889 }
1890
1891 return $aTagParams;
1892 }
1893
1894 /**
1895 * All extension links should ask this function for additional properties to their tags.
1896 * Designed to add for instance an "onclick" property for site tracking systems.
1897 *
1898 * @param string $URL URL of the website
1899 * @param string $TYPE
1900 * @return string The additional tag properties
1901 */
1902 public function extLinkATagParams($URL, $TYPE) {
1903 $out = '';
1904 if ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['extLinkATagParamsHandler']) {
1905 $extLinkATagParamsHandler = GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['extLinkATagParamsHandler']);
1906 if (method_exists($extLinkATagParamsHandler, 'main')) {
1907 $out .= trim($extLinkATagParamsHandler->main($URL, $TYPE, $this));
1908 }
1909 }
1910 return trim($out) ? ' ' . trim($out) : '';
1911 }
1912
1913 /***********************************************
1914 *
1915 * HTML template processing functions
1916 *
1917 ***********************************************/
1918 /**
1919 * Returns a subpart from the input content stream.
1920 * A subpart is a part of the input stream which is encapsulated in a
1921 * string matching the input string, $marker. If this string is found
1922 * inside of HTML comment tags the start/end points of the content block
1923 * returned will be that right outside that comment block.
1924 * Example: The contennt string is
1925 * "Hello <!--###sub1### begin--> World. How are <!--###sub1### end--> you?"
1926 * If $marker is "###sub1###" then the content returned is
1927 * " World. How are ". The input content string could just as well have
1928 * been "Hello ###sub1### World. How are ###sub1### you?" and the result
1929 * would be the same
1930 * Wrapper for \TYPO3\CMS\Core\Html\HtmlParser::getSubpart which behaves identical
1931 *
1932 * @param string $content The content stream, typically HTML template content.
1933 * @param string $marker The marker string, typically on the form "###[the marker string]###
1934 * @return string The subpart found, if found.
1935 */
1936 public function getSubpart($content, $marker) {
1937 return HtmlParser::getSubpart($content, $marker);
1938 }
1939
1940 /**
1941 * Substitute subpart in input template stream.
1942 * This function substitutes a subpart in $content with the content of
1943 * $subpartContent.
1944 * Wrapper for \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart which behaves identical
1945 *
1946 * @param string $content The content stream, typically HTML template content.
1947 * @param string $marker The marker string, typically on the form "###[the marker string]###
1948 * @param mixed $subpartContent The content to insert instead of the subpart found. If a string, then just plain substitution happens (includes removing the HTML comments of the subpart if found). If $subpartContent happens to be an array, it's [0] and [1] elements are wrapped around the EXISTING content of the subpart (fetched by getSubpart()) thereby not removing the original content.
1949 * @param bool $recursive If $recursive is set, the function calls itself with the content set to the remaining part of the content after the second marker. This means that proceding subparts are ALSO substituted!
1950 * @return string The processed HTML content string.
1951 */
1952 public function substituteSubpart($content, $marker, $subpartContent, $recursive = 1) {
1953 return HtmlParser::substituteSubpart($content, $marker, $subpartContent, $recursive);
1954 }
1955
1956 /**
1957 * Substitues multiple subparts at once
1958 *
1959 * @param string $content The content stream, typically HTML template content.
1960 * @param array $subpartsContent The array of key/value pairs being subpart/content values used in the substitution. For each element in this array the function will substitute a subpart in the content stream with the content.
1961 * @return string The processed HTML content string.
1962 */
1963 public function substituteSubpartArray($content, array $subpartsContent) {
1964 return HtmlParser::substituteSubpartArray($content, $subpartsContent);
1965 }
1966
1967 /**
1968 * Substitutes a marker string in the input content
1969 * (by a simple str_replace())
1970 *
1971 * @param string $content The content stream, typically HTML template content.
1972 * @param string $marker The marker string, typically on the form "###[the marker string]###
1973 * @param mixed $markContent The content to insert instead of the marker string found.
1974 * @return string The processed HTML content string.
1975 * @see substituteSubpart()
1976 */
1977 public function substituteMarker($content, $marker, $markContent) {
1978 return HtmlParser::substituteMarker($content, $marker, $markContent);
1979 }
1980
1981 /**
1982 * Multi substitution function with caching.
1983 *
1984 * This function should be a one-stop substitution function for working
1985 * with HTML-template. It does not substitute by str_replace but by
1986 * splitting. This secures that the value inserted does not themselves
1987 * contain markers or subparts.
1988 *
1989 * Note that the "caching" won't cache the content of the substition,
1990 * but only the splitting of the template in various parts. So if you
1991 * want only one cache-entry per template, make sure you always pass the
1992 * exact same set of marker/subpart keys. Else you will be flooding the
1993 * users cache table.
1994 *
1995 * This function takes three kinds of substitutions in one:
1996 * $markContentArray is a regular marker-array where the 'keys' are
1997 * substituted in $content with their values
1998 *
1999 * $subpartContentArray works exactly like markContentArray only is whole
2000 * subparts substituted and not only a single marker.
2001 *
2002 * $wrappedSubpartContentArray is an array of arrays with 0/1 keys where
2003 * the subparts pointed to by the main key is wrapped with the 0/1 value
2004 * alternating.
2005 *
2006 * @param string $content The content stream, typically HTML template content.
2007 * @param array $markContentArray Regular marker-array where the 'keys' are substituted in $content with their values
2008 * @param array $subpartContentArray Exactly like markContentArray only is whole subparts substituted and not only a single marker.
2009 * @param array $wrappedSubpartContentArray An array of arrays with 0/1 keys where the subparts pointed to by the main key is wrapped with the 0/1 value alternating.
2010 * @return string The output content stream
2011 * @see substituteSubpart(), substituteMarker(), substituteMarkerInObject(), TEMPLATE()
2012 */
2013 public function substituteMarkerArrayCached($content, array $markContentArray = NULL, array $subpartContentArray = NULL, array $wrappedSubpartContentArray = NULL) {
2014 $GLOBALS['TT']->push('substituteMarkerArrayCached');
2015 // If not arrays then set them
2016 if (is_null($markContentArray)) {
2017 // Plain markers
2018 $markContentArray = array();
2019 }
2020 if (is_null($subpartContentArray)) {
2021 // Subparts being directly substituted
2022 $subpartContentArray = array();
2023 }
2024 if (is_null($wrappedSubpartContentArray)) {
2025 // Subparts being wrapped
2026 $wrappedSubpartContentArray = array();
2027 }
2028 // Finding keys and check hash:
2029 $sPkeys = array_keys($subpartContentArray);
2030 $wPkeys = array_keys($wrappedSubpartContentArray);
2031 $aKeys = array_merge(array_keys($markContentArray), $sPkeys, $wPkeys);
2032 if (!count($aKeys)) {
2033 $GLOBALS['TT']->pull();
2034 return $content;
2035 }
2036 asort($aKeys);
2037 $storeKey = md5('substituteMarkerArrayCached_storeKey:' . serialize(array(
2038 $content,
2039 $aKeys
2040 )));
2041 if ($this->substMarkerCache[$storeKey]) {
2042 $storeArr = $this->substMarkerCache[$storeKey];
2043 $GLOBALS['TT']->setTSlogMessage('Cached', 0);
2044 } else {
2045 $storeArrDat = $GLOBALS['TSFE']->sys_page->getHash($storeKey);
2046 if (is_array($storeArrDat)) {
2047 $storeArr = $storeArrDat;
2048 // Setting cache:
2049 $this->substMarkerCache[$storeKey] = $storeArr;
2050 $GLOBALS['TT']->setTSlogMessage('Cached from DB', 0);
2051 } else {
2052 // Initialize storeArr
2053 $storeArr = array();
2054 // Finding subparts and substituting them with the subpart as a marker
2055 foreach ($sPkeys as $sPK) {
2056 $content = $this->substituteSubpart($content, $sPK, $sPK);
2057 }
2058 // Finding subparts and wrapping them with markers
2059 foreach ($wPkeys as $wPK) {
2060 $content = $this->substituteSubpart($content, $wPK, array(
2061 $wPK,
2062 $wPK
2063 ));
2064 }
2065 // Traverse keys and quote them for reg ex.
2066 foreach ($aKeys as $tK => $tV) {
2067 $aKeys[$tK] = preg_quote($tV, '/');
2068 }
2069 $regex = '/' . implode('|', $aKeys) . '/';
2070 // Doing regex's
2071 $storeArr['c'] = preg_split($regex, $content);
2072 preg_match_all($regex, $content, $keyList);
2073 $storeArr['k'] = $keyList[0];
2074 // Setting cache:
2075 $this->substMarkerCache[$storeKey] = $storeArr;
2076 // Storing the cached data:
2077 $GLOBALS['TSFE']->sys_page->storeHash($storeKey, $storeArr, 'substMarkArrayCached');
2078 $GLOBALS['TT']->setTSlogMessage('Parsing', 0);
2079 }
2080 }
2081 // Substitution/Merging:
2082 // Merging content types together, resetting
2083 $valueArr = array_merge($markContentArray, $subpartContentArray, $wrappedSubpartContentArray);
2084 $wSCA_reg = array();
2085 $content = '';
2086 // Traversing the keyList array and merging the static and dynamic content
2087 foreach ($storeArr['k'] as $n => $keyN) {
2088 $content .= $storeArr['c'][$n];
2089 if (!is_array($valueArr[$keyN])) {
2090 $content .= $valueArr[$keyN];
2091 } else {
2092 $content .= $valueArr[$keyN][(int)$wSCA_reg[$keyN] % 2];
2093 $wSCA_reg[$keyN]++;
2094 }
2095 }
2096 $content .= $storeArr['c'][count($storeArr['k'])];
2097 $GLOBALS['TT']->pull();
2098 return $content;
2099 }
2100
2101 /**
2102 * Traverses the input $markContentArray array and for each key the marker
2103 * by the same name (possibly wrapped and in upper case) will be
2104 * substituted with the keys value in the array.
2105 *
2106 * This is very useful if you have a data-record to substitute in some
2107 * content. In particular when you use the $wrap and $uppercase values to
2108 * pre-process the markers. Eg. a key name like "myfield" could effectively
2109 * be represented by the marker "###MYFIELD###" if the wrap value
2110 * was "###|###" and the $uppercase boolean TRUE.
2111 *
2112 * @param string $content The content stream, typically HTML template content.
2113 * @param array $markContentArray The array of key/value pairs being marker/content values used in the substitution. For each element in this array the function will substitute a marker in the content stream with the content.
2114 * @param string $wrap A wrap value - [part 1] | [part 2] - for the markers before substitution
2115 * @param bool $uppercase If set, all marker string substitution is done with upper-case markers.
2116 * @param bool $deleteUnused If set, all unused marker are deleted.
2117 * @return string The processed output stream
2118 * @see substituteMarker(), substituteMarkerInObject(), TEMPLATE()
2119 */
2120 public function substituteMarkerArray($content, array $markContentArray, $wrap = '', $uppercase = FALSE, $deleteUnused = FALSE) {
2121 return HtmlParser::substituteMarkerArray($content, $markContentArray, $wrap, $uppercase, $deleteUnused);
2122 }
2123
2124 /**
2125 * Substitute marker array in an array of values
2126 *
2127 * @param mixed $tree If string, then it just calls substituteMarkerArray. If array(and even multi-dim) then for each key/value pair the marker array will be substituted (by calling this function recursively)
2128 * @param array $markContentArray The array of key/value pairs being marker/content values used in the substitution. For each element in this array the function will substitute a marker in the content string/array values.
2129 * @return mixed The processed input variable.
2130 * @see substituteMarker()
2131 */
2132 public function substituteMarkerInObject(&$tree, array $markContentArray) {
2133 if (is_array($tree)) {
2134 foreach ($tree as $key => $value) {
2135 $this->substituteMarkerInObject($tree[$key], $markContentArray);
2136 }
2137 } else {
2138 $tree = $this->substituteMarkerArray($tree, $markContentArray);
2139 }
2140 return $tree;
2141 }
2142
2143 /**
2144 * Replaces all markers and subparts in a template with the content provided in the structured array.
2145 *
2146 * @param string $content
2147 * @param array $markersAndSubparts
2148 * @param string $wrap
2149 * @param bool $uppercase
2150 * @param bool $deleteUnused
2151 * @return string
2152 */
2153 public function substituteMarkerAndSubpartArrayRecursive($content, array $markersAndSubparts, $wrap = '', $uppercase = FALSE, $deleteUnused = FALSE) {
2154 return HtmlParser::substituteMarkerAndSubpartArrayRecursive($content, $markersAndSubparts, $wrap, $uppercase, $deleteUnused);
2155 }
2156
2157 /**
2158 * Adds elements to the input $markContentArray based on the values from
2159 * the fields from $fieldList found in $row
2160 *
2161 * @param array $markContentArray Array with key/values being marker-strings/substitution values.
2162 * @param array $row An array with keys found in the $fieldList (typically a record) which values should be moved to the $markContentArray
2163 * @param string $fieldList A list of fields from the $row array to add to the $markContentArray array. If empty all fields from $row will be added (unless they are integers)
2164 * @param bool $nl2br If set, all values added to $markContentArray will be nl2br()'ed
2165 * @param string $prefix Prefix string to the fieldname before it is added as a key in the $markContentArray. Notice that the keys added to the $markContentArray always start and end with "###
2166 * @param bool $HSC If set, all values are passed through htmlspecialchars() - RECOMMENDED to avoid most obvious XSS and maintain XHTML compliance.
2167 * @return array The modified $markContentArray
2168 */
2169 public function fillInMarkerArray(array $markContentArray, array $row, $fieldList = '', $nl2br = TRUE, $prefix = 'FIELD_', $HSC = FALSE) {
2170 if ($fieldList) {
2171 $fArr = GeneralUtility::trimExplode(',', $fieldList, TRUE);
2172 foreach ($fArr as $field) {
2173 $markContentArray['###' . $prefix . $field . '###'] = $nl2br ? nl2br($row[$field], !empty($GLOBALS['TSFE']->xhtmlDoctype)) : $row[$field];
2174 }
2175 } else {
2176 if (is_array($row)) {
2177 foreach ($row as $field => $value) {
2178 if (!MathUtility::canBeInterpretedAsInteger($field)) {
2179 if ($HSC) {
2180 $value = htmlspecialchars($value);
2181 }
2182 $markContentArray['###' . $prefix . $field . '###'] = $nl2br ? nl2br($value, !empty($GLOBALS['TSFE']->xhtmlDoctype)) : $value;
2183 }
2184 }
2185 }
2186 }
2187 return $markContentArray;
2188 }
2189
2190 /**
2191 * Sets the current file object during iterations over files.
2192 *
2193 * @param File $fileObject The file object.
2194 */
2195 public function setCurrentFile($fileObject) {
2196 $this->currentFile = $fileObject;
2197 }
2198
2199 /**
2200 * Gets the current file object during iterations over files.
2201 *
2202 * @return File The current file object.
2203 */
2204 public function getCurrentFile() {
2205 return $this->currentFile;
2206 }
2207
2208 /***********************************************
2209 *
2210 * "stdWrap" + sub functions
2211 *
2212 ***********************************************/
2213 /**
2214 * The "stdWrap" function. This is the implementation of what is known as "stdWrap properties" in TypoScript.
2215 * Basically "stdWrap" performs some processing of a value based on properties in the input $conf array(holding the TypoScript "stdWrap properties")
2216 * See the link below for a complete list of properties and what they do. The order of the table with properties found in TSref (the link) follows the actual order of implementation in this function.
2217 *
2218 * If $this->alternativeData is an array it's used instead of the $this->data array in ->getData
2219 *
2220 * @param string $content Input value undergoing processing in this function. Possibly substituted by other values fetched from another source.
2221 * @param array $conf TypoScript "stdWrap properties".
2222 * @return string The processed input value
2223 */
2224 public function stdWrap($content = '', $conf = array()) {
2225 // If there is any hook object, activate all of the process and override functions.
2226 // The hook interface ContentObjectStdWrapHookInterface takes care that all 4 methods exist.
2227 if ($this->stdWrapHookObjects) {
2228 $conf['stdWrapPreProcess'] = 1;
2229 $conf['stdWrapOverride'] = 1;
2230 $conf['stdWrapProcess'] = 1;
2231 $conf['stdWrapPostProcess'] = 1;
2232 }
2233
2234 if (!is_array($conf) || !$conf) {
2235 return $content;
2236 }
2237
2238 // Cache handling
2239 if (is_array($conf['cache.'])) {
2240 $conf['cache.']['key'] = $this->stdWrap($conf['cache.']['key'], $conf['cache.']['key.']);
2241 $conf['cache.']['tags'] = $this->stdWrap($conf['cache.']['tags'], $conf['cache.']['tags.']);
2242 $conf['cache.']['lifetime'] = $this->stdWrap($conf['cache.']['lifetime'], $conf['cache.']['lifetime.']);
2243 $conf['cacheRead'] = 1;
2244 $conf['cacheStore'] = 1;
2245 }
2246 // Check, which of the available stdWrap functions is needed for the current conf Array
2247 // and keep only those but still in the same order
2248 $sortedConf = array_intersect_key($this->stdWrapOrder, $conf);
2249 // Functions types that should not make use of nested stdWrap function calls to avoid conflicts with internal TypoScript used by these functions
2250 $stdWrapDisabledFunctionTypes = 'cObject,functionName,stdWrap';
2251 // Additional Array to check whether a function has already been executed
2252 $isExecuted = array();
2253 // Additional switch to make sure 'required', 'if' and 'fieldRequired'
2254 // will still stop rendering immediately in case they return FALSE
2255 $this->stdWrapRecursionLevel++;
2256 $this->stopRendering[$this->stdWrapRecursionLevel] = FALSE;
2257 // execute each function in the predefined order
2258 foreach ($sortedConf as $stdWrapName => $functionType) {
2259 // eliminate the second key of a pair 'key'|'key.' to make sure functions get called only once and check if rendering has been stopped
2260 if (!$isExecuted[$stdWrapName] && !$this->stopRendering[$this->stdWrapRecursionLevel]) {
2261 $functionName = rtrim($stdWrapName, '.');
2262 $functionProperties = $functionName . '.';
2263 // If there is any code on the next level, check if it contains "official" stdWrap functions
2264 // if yes, execute them first - will make each function stdWrap aware
2265 // so additional stdWrap calls within the functions can be removed, since the result will be the same
2266 // exception: the recursive stdWrap function and cObject will still be using their own stdWrap call, since it modifies the content and not a property
2267 if ($functionName !== 'stdWrap' && !empty($conf[$functionProperties]) && !GeneralUtility::inList($stdWrapDisabledFunctionTypes, $functionType)) {
2268 if (array_intersect_key($this->stdWrapOrder, $conf[$functionProperties])) {
2269 $conf[$functionName] = $this->stdWrap($conf[$functionName], $conf[$functionProperties]);
2270 }
2271 }
2272 // Check if key is still containing something, since it might have been changed by next level stdWrap before
2273 if ((isset($conf[$functionName]) || $conf[$functionProperties]) && ($functionType !== 'boolean' || $conf[$functionName])) {
2274 // Get just that part of $conf that is needed for the particular function
2275 $singleConf = array(
2276 $functionName => $conf[$functionName],
2277 $functionProperties => $conf[$functionProperties]
2278 );
2279 // In this special case 'spaceBefore' and 'spaceAfter' need additional stuff from 'space.''
2280 if ($functionName === 'spaceBefore' || $functionName === 'spaceAfter') {
2281 $singleConf['space.'] = $conf['space.'];
2282 }
2283 // Hand over the whole $conf array to the stdWrapHookObjects
2284 if ($functionType === 'hook') {
2285 $singleConf = $conf;
2286 }
2287 // Add both keys - with and without the dot - to the set of executed functions
2288 $isExecuted[$functionName] = TRUE;
2289 $isExecuted[$functionProperties] = TRUE;
2290 // Call the function with the prefix stdWrap_ to make sure nobody can execute functions just by adding their name to the TS Array
2291 $functionName = 'stdWrap_' . $functionName;
2292 $content = $this->{$functionName}($content, $singleConf);
2293 } elseif ($functionType == 'boolean' && !$conf[$functionName]) {
2294 $isExecuted[$functionName] = TRUE;
2295 $isExecuted[$functionProperties] = TRUE;
2296 }
2297 }
2298 }
2299 unset($this->stopRendering[$this->stdWrapRecursionLevel]);
2300 $this->stdWrapRecursionLevel--;
2301
2302 return $content;
2303 }
2304
2305 /**
2306 * Gets a configuration value by passing them through stdWrap first and taking a default value if stdWrap doesn't yield a result.
2307 *
2308 * @param string $key The config variable key (from TS array).
2309 * @param array $config The TypoScript array.
2310 * @param string $defaultValue Optional default value.
2311 * @return string Value of the config variable
2312 */
2313 public function stdWrapValue($key, array $config, $defaultValue = '') {
2314 if (isset($config[$key])) {
2315 if (!isset($config[$key . '.'])) {
2316 return $config[$key];
2317 }
2318 } elseif (isset($config[$key . '.'])) {
2319 $config[$key] = '';
2320 } else {
2321 return $defaultValue;
2322 }
2323 $stdWrapped = $this->stdWrap($config[$key], $config[$key . '.']);
2324 return $stdWrapped ?: $defaultValue;
2325 }
2326
2327 /**
2328 * stdWrap pre process hook
2329 * can be used by extensions authors to modify the behaviour of stdWrap functions to their needs
2330 * this hook will execute functions before any other stdWrap function can modify anything
2331 *
2332 * @param string $content Input value undergoing processing in these functions.
2333 * @param array $conf All stdWrap properties, not just the ones for a particular function.
2334 * @return string The processed input value
2335 */
2336 public function stdWrap_stdWrapPreProcess($content = '', $conf = array()) {
2337 foreach ($this->stdWrapHookObjects as $hookObject) {
2338 $content = $hookObject->stdWrapPreProcess($content, $conf, $this);
2339 }
2340 return $content;
2341 }
2342
2343 /**
2344 * Check if content was cached before (depending on the given cache key)
2345 *
2346 * @param string $content Input value undergoing processing in these functions.
2347 * @param array $conf All stdWrap properties, not just the ones for a particular function.
2348 * @return string The processed input value
2349 */
2350 public function stdWrap_cacheRead($content = '', $conf = array()) {
2351 if (!empty($conf['cache.']['key'])) {
2352 /** @var $cacheFrontend \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend */
2353 $cacheFrontend = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_hash');
2354 if ($cacheFrontend && $cacheFrontend->has($conf['cache.']['key'])) {
2355 $content = $cacheFrontend->get($conf['cache.']['key']);
2356 $this->stopRendering[$this->stdWrapRecursionLevel] = TRUE;
2357 }
2358 }
2359 return $content;
2360 }
2361
2362 /**
2363 * Add tags to page cache (comma-separated list)
2364 *
2365 * @param string $content Input value undergoing processing in these functions.
2366 * @param array $conf All stdWrap properties, not just the ones for a particular function.
2367 * @return string The processed input value
2368 */
2369 public function stdWrap_addPageCacheTags($content = '', $conf = array()) {
2370 $tags = isset($conf['addPageCacheTags.'])
2371 ? $this->stdWrap($conf['addPageCacheTags'], $conf['addPageCacheTags.'])
2372 : $conf['addPageCacheTags'];
2373 if (!empty($tags)) {
2374 $cacheTags = GeneralUtility::trimExplode(',', $tags, TRUE);
2375 $GLOBALS['TSFE']->addCacheTags($cacheTags);
2376 }
2377 return $content;
2378 }
2379
2380 /**
2381 * setContentToCurrent
2382 * actually it just does the contrary: Sets the value of 'current' based on current content
2383 *
2384 * @param string $content Input value undergoing processing in this function.
2385 * @param array $conf stdWrap properties for setContentToCurrent.
2386 * @return string The processed input value
2387 */
2388 public function stdWrap_setContentToCurrent($content = '', $conf = array()) {
2389 $this->data[$this->currentValKey] = $content;
2390 return $content;
2391 }
2392
2393 /**
2394 * setCurrent
2395 * Sets the value of 'current' based on the outcome of stdWrap operations
2396 *
2397 * @param string $content Input value undergoing processing in this function.
2398 * @param array $conf stdWrap properties for setCurrent.
2399 * @return string The processed input value
2400 */
2401 public function stdWrap_setCurrent($content = '', $conf = array()) {
2402 $this->data[$this->currentValKey] = $conf['setCurrent'];
2403 return $content;
2404 }
2405
2406 /**
2407 * lang
2408 * Translates content based on the language currently used by the FE
2409 *
2410 * @param string $content Input value undergoing processing in this function.
2411 * @param array $conf stdWrap properties for lang.
2412 * @return string The processed input value
2413 */
2414 public function stdWrap_lang($content = '', $conf = array()) {
2415 if (isset($conf['lang.']) && $GLOBALS['TSFE']->config['config']['language'] && isset($conf['lang.'][$GLOBALS['TSFE']->config['config']['language']])) {
2416 $content = $conf['lang.'][$GLOBALS['TSFE']->config['config']['language']];
2417 }
2418 return $content;
2419 }
2420
2421 /**
2422 * data
2423 * Gets content from different sources based on getText functions, makes use of alternativeData, when set
2424 *
2425 * @param string $content Input value undergoing processing in this function.
2426 * @param array $conf stdWrap properties for data.
2427 * @return string The processed input value
2428 */
2429 public function stdWrap_data($content = '', $conf = array()) {
2430 $content = $this->getData($conf['data'], is_array($this->alternativeData) ? $this->alternativeData : $this->data);
2431 // This must be unset directly after
2432 $this->alternativeData = '';
2433 return $content;
2434 }
2435
2436 /**
2437 * field
2438 * Gets content from a DB field
2439 *
2440 * @param string $content Input value undergoing processing in this function.
2441 * @param array $conf stdWrap properties for field.
2442 * @return string The processed input value
2443 */
2444 public function stdWrap_field($content = '', $conf = array()) {
2445 return $this->getFieldVal($conf['field']);
2446 }
2447
2448 /**
2449 * current
2450 * Gets content that has been perviously set as 'current'
2451 * Can be set via setContentToCurrent or setCurrent or will be set automatically i.e. inside the split function
2452 *
2453 * @param string $content Input value undergoing processing in this function.
2454 * @param array $conf stdWrap properties for current.
2455 * @return string The processed input value
2456 */
2457 public function stdWrap_current($content = '', $conf = array()) {
2458 return $this->data[$this->currentValKey];
2459 }
2460
2461 /**
2462 * cObject
2463 * Will replace the content with the value of a any official TypoScript cObject
2464 * like TEXT, COA, HMENU
2465 *
2466 * @param string $content Input value undergoing processing in this function.
2467 * @param array $conf stdWrap properties for cObject.
2468 * @return string The processed input value
2469 */
2470 public function stdWrap_cObject($content = '', $conf = array()) {
2471 return $this->cObjGetSingle($conf['cObject'], $conf['cObject.'], '/stdWrap/.cObject');
2472 }
2473
2474 /**
2475 * numRows
2476 * Counts the number of returned records of a DB operation
2477 * makes use of select internally
2478 *
2479 * @param string $content Input value undergoing processing in this function.
2480 * @param array $conf stdWrap properties for numRows.
2481 * @return string The processed input value
2482 */
2483 public function stdWrap_numRows($content = '', $conf = array()) {
2484 return $this->numRows($conf['numRows.']);
2485 }
2486
2487 /**
2488 * filelist
2489 * Will create a list of files based on some additional parameters
2490 *
2491 * @param string $content Input value undergoing processing in this function.
2492 * @param array $conf stdWrap properties for filelist.
2493 * @return string The processed input value
2494 */
2495 public function stdWrap_filelist($content = '', $conf = array()) {
2496 return $this->filelist($conf['filelist']);
2497 }
2498
2499 /**
2500 * preUserFunc
2501 * Will execute a user public function before the content will be modified by any other stdWrap function
2502 *
2503 * @param string $content Input value undergoing processing in this function.
2504 * @param array $conf stdWrap properties for preUserFunc.
2505 * @return string The processed input value
2506 */
2507 public function stdWrap_preUserFunc($content = '', $conf = array()) {
2508 return $this->callUserFunction($conf['preUserFunc'], $conf['preUserFunc.'], $content);
2509 }
2510
2511 /**
2512 * stdWrap override hook
2513 * can be used by extensions authors to modify the behaviour of stdWrap functions to their needs
2514 * this hook will execute functions on existing content but still before the content gets modified or replaced
2515 *
2516 * @param string $content Input value undergoing processing in these functions.
2517 * @param array $conf All stdWrap properties, not just the ones for a particular function.
2518 * @return string The processed input value
2519 */
2520 public function stdWrap_stdWrapOverride($content = '', $conf = array()) {
2521 foreach ($this->stdWrapHookObjects as $hookObject) {
2522 $content = $hookObject->stdWrapOverride($content, $conf, $this);
2523 }
2524 return $content;
2525 }
2526
2527 /**
2528 * override
2529 * Will override the current value of content with its own value'
2530 *
2531 * @param string $content Input value undergoing processing in this function.
2532 * @param array $conf stdWrap properties for override.
2533 * @return string The processed input value
2534 */
2535 public function stdWrap_override($content = '', $conf = array()) {
2536 if (trim($conf['override'])) {
2537 $content = $conf['override'];
2538 }
2539 return $content;
2540 }
2541
2542 /**
2543 * preIfEmptyListNum
2544 * Gets a value off a CSV list before the following ifEmpty check
2545 * Makes sure that the result of ifEmpty will be TRUE in case the CSV does not contain a value at the position given by preIfEmptyListNum
2546 *
2547 * @param string $content Input value undergoing processing in this function.
2548 * @param array $conf stdWrap properties for preIfEmptyListNum.
2549 * @return string The processed input value
2550 */
2551 public function stdWrap_preIfEmptyListNum($content = '', $conf = array()) {
2552 return $this->listNum($content, $conf['preIfEmptyListNum'], $conf['preIfEmptyListNum.']['splitChar']);
2553 }
2554
2555 /**
2556 * ifNull
2557 * Will set content to a replacement value in case the value of content is NULL
2558 *
2559 * @param string|NULL $content Input value undergoing processing in this function.
2560 * @param array $conf stdWrap properties for ifNull.
2561 * @return string The processed input value
2562 */
2563 public function stdWrap_ifNull($content = '', $conf = array()) {
2564 return $content !== NULL ? $content : $conf['ifNull'];
2565 }
2566
2567 /**
2568 * ifEmpty
2569 * Will set content to a replacement value in case the trimmed value of content returns FALSE
2570 * 0 (zero) will be replaced as well
2571 *
2572 * @param string $content Input value undergoing processing in this function.
2573 * @param array $conf stdWrap properties for ifEmpty.
2574 * @return string The processed input value
2575 */
2576 public function stdWrap_ifEmpty($content = '', $conf = array()) {
2577 if (!trim($content)) {
2578 $content = $conf['ifEmpty'];
2579 }
2580 return $content;
2581 }
2582
2583 /**
2584 * ifBlank
2585 * Will set content to a replacement value in case the trimmed value of content has no length
2586 * 0 (zero) will not be replaced
2587 *
2588 * @param string $content Input value undergoing processing in this function.
2589 * @param array $conf stdWrap properties for ifBlank.
2590 * @return string The processed input value
2591 */
2592 public function stdWrap_ifBlank($content = '', $conf = array()) {
2593 if (trim($content) === '') {
2594 $content = $conf['ifBlank'];
2595 }
2596 return $content;
2597 }
2598
2599 /**
2600 * listNum
2601 * Gets a value off a CSV list after ifEmpty check
2602 * Might return an empty value in case the CSV does not contain a value at the position given by listNum
2603 * Use preIfEmptyListNum to avoid that behaviour
2604 *
2605 * @param string $content Input value undergoing processing in this function.
2606 * @param array $conf stdWrap properties for listNum.
2607 * @return string The processed input value
2608 */
2609 public function stdWrap_listNum($content = '', $conf = array()) {
2610 return $this->listNum($content, $conf['listNum'], $conf['listNum.']['splitChar']);
2611 }
2612
2613 /**
2614 * trim
2615 * Cuts off any whitespace at the beginning and the end of the content
2616 *
2617 * @param string $content Input value undergoing processing in this function.
2618 * @param array $conf stdWrap properties for trim.
2619 * @return string The processed input value
2620 */
2621 public function stdWrap_trim($content = '', $conf = array()) {
2622 return trim($content);
2623 }
2624
2625 /**
2626 * strPad
2627 * Will return a string padded left/right/on both sides, based on configuration given as stdWrap properties
2628 *
2629 * @param string $content Input value undergoing processing in this function.
2630 * @param array $conf stdWrap properties for strPad.
2631 * @return string The processed input value
2632 */
2633 public function stdWrap_strPad($content = '', $conf = array()) {
2634 // Must specify a length in conf for this to make sense
2635 $length = 0;
2636 // Padding with space is PHP-default
2637 $padWith = ' ';
2638 // Padding on the right side is PHP-default
2639 $padType = STR_PAD_RIGHT;
2640 if (!empty($conf['strPad.']['length'])) {
2641 $length = isset($conf['strPad.']['length.']) ? $this->stdWrap($conf['strPad.']['length'], $conf['strPad.']['length.']) : $conf['strPad.']['length'];
2642 $length = (int)$length;
2643 }
2644 if (isset($conf['strPad.']['padWith']) && (string)$conf['strPad.']['padWith'] !== '') {
2645 $padWith = isset($conf['strPad.']['padWith.']) ? $this->stdWrap($conf['strPad.']['padWith'], $conf['strPad.']['padWith.']) : $conf['strPad.']['padWith'];
2646 }
2647 if (!empty($conf['strPad.']['type'])) {
2648 $type = isset($conf['strPad.']['type.']) ? $this->stdWrap($conf['strPad.']['type'], $conf['strPad.']['type.']) : $conf['strPad.']['type'];
2649 if (strtolower($type) === 'left') {
2650 $padType = STR_PAD_LEFT;
2651 } elseif (strtolower($type) === 'both') {
2652 $padType = STR_PAD_BOTH;
2653 }
2654 }
2655 $content = str_pad($content, $length, $padWith, $padType);
2656 return $content;
2657 }
2658
2659 /**
2660 * stdWrap
2661 * A recursive call of the stdWrap function set
2662 * This enables the user to execute stdWrap functions in another than the predefined order
2663 * It modifies the content, not the property
2664 * while the new feature of chained stdWrap functions modifies the property and not the content
2665 *
2666 * @param string $content Input value undergoing processing in this function.
2667 * @param array $conf stdWrap properties for stdWrap.
2668 * @return string The processed input value
2669 */
2670 public function stdWrap_stdWrap($content = '', $conf = array()) {
2671 return $this->stdWrap($content, $conf['stdWrap.']);
2672 }
2673
2674 /**
2675 * stdWrap process hook
2676 * can be used by extensions authors to modify the behaviour of stdWrap functions to their needs
2677 * this hook executes functions directly after the recursive stdWrap function call but still before the content gets modified
2678 *
2679 * @param string $content Input value undergoing processing in these functions.
2680 * @param array $conf All stdWrap properties, not just the ones for a particular function.
2681 * @return string The processed input value
2682 */
2683 public function stdWrap_stdWrapProcess($content = '', $conf = array()) {
2684 foreach ($this->stdWrapHookObjects as $hookObject) {
2685 $content = $hookObject->stdWrapProcess($content, $conf, $this);
2686 }
2687 return $content;
2688 }
2689
2690 /**
2691 * required
2692 * Will immediately stop rendering and return an empty value
2693 * when there is no content at this point
2694 *
2695 * @param string $content Input value undergoing processing in this function.
2696 * @param array $conf stdWrap properties for required.
2697 * @return string The processed input value
2698 */
2699 public function stdWrap_required($content = '', $conf = array()) {
2700 if ((string)$content === '') {
2701 $content = '';
2702 $this->stopRendering[$this->stdWrapRecursionLevel] = TRUE;
2703 }
2704 return $content;
2705 }
2706
2707 /**
2708 * if
2709 * Will immediately stop rendering and return an empty value
2710 * when the result of the checks returns FALSE
2711 *
2712 * @param string $content Input value undergoing processing in this function.
2713 * @param array $conf stdWrap properties for if.
2714 * @return string The processed input value
2715 */
2716 public function stdWrap_if($content = '', $conf = array()) {
2717 if (empty($conf['if.']) || $this->checkIf($conf['if.'])) {
2718 return $content;
2719 }
2720 $this->stopRendering[$this->stdWrapRecursionLevel] = TRUE;
2721 return '';
2722 }
2723
2724 /**
2725 * fieldRequired
2726 * Will immediately stop rendering and return an empty value
2727 * when there is no content in the field given by fieldRequired
2728 *
2729 * @param string $content Input value undergoing processing in this function.
2730 * @param array $conf stdWrap properties for fieldRequired.
2731 * @return string The processed input value
2732 */
2733 public function stdWrap_fieldRequired($content = '', $conf = array()) {
2734 if (!trim($this->data[$conf['fieldRequired']])) {
2735 $content = '';
2736 $this->stopRendering[$this->stdWrapRecursionLevel] = TRUE;
2737 }
2738 return $content;
2739 }
2740
2741 /**
2742 * csConv
2743 * Will convert the current chracter set of the content to the one given in csConv
2744 *
2745 * @param string $content Input value undergoing processing in this function.
2746 * @param array $conf stdWrap properties for csConv.
2747 * @return string The processed input value
2748 */
2749 public function stdWrap_csConv($content = '', $conf = array()) {
2750 return $GLOBALS['TSFE']->csConv($content, $conf['csConv']);
2751 }
2752
2753 /**
2754 * parseFunc
2755 * Will parse the content based on functions given as stdWrap properties
2756 * Heavily used together with RTE based content
2757 *
2758 * @param string $content Input value undergoing processing in this function.
2759 * @param array $conf stdWrap properties for parseFunc.
2760 * @return string The processed input value
2761 */
2762 public function stdWrap_parseFunc($content = '', $conf = array()) {
2763 return $this->parseFunc($content, $conf['parseFunc.'], $conf['parseFunc']);
2764 }
2765
2766 /**
2767 * HTMLparser
2768 * Will parse HTML content based on functions given as stdWrap properties
2769 * Heavily used together with RTE based content
2770 *
2771 * @param string $content Input value undergoing processing in this function.
2772 * @param array $conf stdWrap properties for HTMLparser.
2773 * @return string The processed input value
2774 */
2775 public function stdWrap_HTMLparser($content = '', $conf = array()) {
2776 if (is_array($conf['HTMLparser.'])) {
2777 $content = $this->HTMLparser_TSbridge($content, $conf['HTMLparser.']);
2778 }
2779 return $content;
2780 }
2781
2782 /**
2783 * split
2784 * Will split the content by a given token and treat the results separately
2785 * Automatically fills 'current' with a single result
2786 *
2787 * @param string $content Input value undergoing processing in this function.
2788 * @param array $conf stdWrap properties for split.
2789 * @return string The processed input value
2790 */
2791 public function stdWrap_split($content = '', $conf = array()) {
2792 return $this->splitObj($content, $conf['split.']);
2793 }
2794
2795 /**
2796 * replacement
2797 * Will execute replacements on the content (optionally with preg-regex)
2798 *
2799 * @param string $content Input value undergoing processing in this function.
2800 * @param array $conf stdWrap properties for replacement.
2801 * @return string The processed input value
2802 */
2803 public function stdWrap_replacement($content = '', $conf = array()) {
2804 return $this->replacement($content, $conf['replacement.']);
2805 }
2806
2807 /**
2808 * prioriCalc
2809 * Will use the content as a mathematical term and calculate the result
2810 * Can be set to 1 to just get a calculated value or 'intval' to get the integer of the result
2811 *
2812 * @param string $content Input value undergoing processing in this function.
2813 * @param array $conf stdWrap properties for prioriCalc.
2814 * @return string The processed input value
2815 */
2816 public function stdWrap_prioriCalc($content = '', $conf = array()) {
2817 $content = MathUtility::calculateWithParentheses($content);
2818 if ($conf['prioriCalc'] == 'intval') {
2819 $content = (int)$content;
2820 }
2821 return $content;
2822 }
2823
2824 /**
2825 * char
2826 * Will return a character based on its position within the current character set
2827 *
2828 * @param string $content Input value undergoing processing in this function.
2829 * @param array $conf stdWrap properties for char.
2830 * @return string The processed input value
2831 */
2832 public function stdWrap_char($content = '', $conf = array()) {
2833 return chr((int)$conf['char']);
2834 }
2835
2836 /**
2837 * intval
2838 * Will return an integer value of the current content
2839 *
2840 * @param string $content Input value undergoing processing in this function.
2841 * @param array $conf stdWrap properties for intval.
2842 * @return string The processed input value
2843 */
2844 public function stdWrap_intval($content = '', $conf = array()) {
2845 return (int)$content;
2846 }
2847
2848 /**
2849 * Will return a hashed value of the current content
2850 *
2851 * @param string $content Input value undergoing processing in this function.
2852 * @param array $conf stdWrap properties for hash.
2853 * @return string The processed input value
2854 * @link http://php.net/manual/de/function.hash-algos.php for a list of supported hash algorithms
2855 */
2856 public function stdWrap_hash($content = '', array $conf = array()) {
2857 $algorithm = isset($conf['hash.']) ? $this->stdWrap($conf['hash'], $conf['hash.']) : $conf['hash'];
2858 if (function_exists('hash') && in_array($algorithm, hash_algos())) {
2859 $content = hash($algorithm, $content);
2860 } else {
2861 // Non-existing hashing algorithm
2862 $content = '';
2863 }
2864 return $content;
2865 }
2866
2867 /**
2868 * stdWrap_round will return a rounded number with ceil(), floor() or round(), defaults to round()
2869 * Only the english number format is supported . (dot) as decimal point
2870 *
2871 * @param string $content Input value undergoing processing in this function.
2872 * @param array $conf stdWrap properties for round.
2873 * @return string The processed input value
2874 */
2875 public function stdWrap_round($content = '', $conf = array()) {
2876 return $this->round($content, $conf['round.']);
2877 }
2878
2879 /**
2880 * numberFormat
2881 * Will return a formatted number based on configuration given as stdWrap properties
2882 *
2883 * @param string $content Input value undergoing processing in this function.
2884 * @param array $conf stdWrap properties for numberFormat.
2885 * @return string The processed input value
2886 */
2887 public function stdWrap_numberFormat($content = '', $conf = array()) {
2888 return $this->numberFormat($content, $conf['numberFormat.']);
2889 }
2890
2891 /**
2892 * expandList
2893 * Will return a formatted number based on configuration given as stdWrap properties
2894 *
2895 * @param string $content Input value undergoing processing in this function.
2896 * @param array $conf stdWrap properties for expandList.
2897 * @return string The processed input value
2898 */
2899 public function stdWrap_expandList($content = '', $conf = array()) {
2900 return GeneralUtility::expandList($content);
2901 }
2902
2903 /**
2904 * date
2905 * Will return a formatted date based on configuration given according to PHP date/gmdate properties
2906 * Will return gmdate when the property GMT returns TRUE
2907 *
2908 * @param string $content Input value undergoing processing in this function.
2909 * @param array $conf stdWrap properties for date.
2910 * @return string The processed input value
2911 */
2912 public function stdWrap_date($content = '', $conf = array()) {
2913 // Check for zero length string to mimic default case of date/gmdate.
2914 $content = $content == '' ? $GLOBALS['EXEC_TIME'] : (int)$content;
2915 $content = $conf['date.']['GMT'] ? gmdate($conf['date'], $content) : date($conf['date'], $content);
2916 return $content;
2917 }
2918
2919 /**
2920 * strftime
2921 * Will return a formatted date based on configuration given according to PHP strftime/gmstrftime properties
2922 * Will return gmstrftime when the property GMT returns TRUE
2923 *
2924 * @param string $content Input value undergoing processing in this function.
2925 * @param array $conf stdWrap properties for strftime.
2926 * @return string The processed input value
2927 */
2928 public function stdWrap_strftime($content = '', $conf = array()) {
2929 // Check for zero length string to mimic default case of strtime/gmstrftime
2930 $content = $content == '' ? $GLOBALS['EXEC_TIME'] : (int)$content;
2931 $content = $conf['strftime.']['GMT'] ? gmstrftime($conf['strftime'], $content) : strftime($conf['strftime'], $content);
2932 $tmp_charset = $conf['strftime.']['charset'] ? $conf['strftime.']['charset'] : $GLOBALS['TSFE']->localeCharset;
2933 if ($tmp_charset) {
2934 $content = $GLOBALS['TSFE']->csConv($content, $tmp_charset);
2935 }
2936 return $content;
2937 }
2938
2939 /**
2940 * age
2941 * Will return the age of a given timestamp based on configuration given by stdWrap properties
2942 *
2943 * @param string $content Input value undergoing processing in this function.
2944 * @param array $conf stdWrap properties for age.
2945 * @return string The processed input value
2946 */
2947 public function stdWrap_age($content = '', $conf = array()) {
2948 return $this->calcAge($GLOBALS['EXEC_TIME'] - $content, $conf['age']);
2949 }
2950
2951 /**
2952 * case
2953 * Will transform the content to be upper or lower case only
2954 * Leaves HTML tags untouched
2955 *
2956 * @param string $content Input value undergoing processing in this function.
2957 * @param array $conf stdWrap properties for case.
2958 * @return string The processed input value
2959 */
2960 public function stdWrap_case($content = '', $conf = array()) {
2961 return $this->HTMLcaseshift($content, $conf['case']);
2962 }
2963
2964 /**
2965 * bytes
2966 * Will return the size of a given number in Bytes *
2967 *
2968 * @param string $content Input value undergoing processing in this function.
2969 * @param array $conf stdWrap properties for bytes.
2970 * @return string The processed input value
2971 */
2972 public function stdWrap_bytes($content = '', $conf = array()) {
2973 return GeneralUtility::formatSize($content, $conf['bytes.']['labels']);
2974 }
2975
2976 /**
2977 * substring
2978 * Will return a substring based on position information given by stdWrap properties
2979 *
2980 * @param string $content Input value undergoing processing in this function.
2981 * @param array $conf stdWrap properties for substring.
2982 * @return string The processed input value
2983 */
2984 public function stdWrap_substring($content = '', $conf = array()) {
2985 return $this->substring($content, $conf['substring']);
2986 }
2987
2988 /**
2989 * removeBadHTML
2990 * Removes HTML tags based on stdWrap properties
2991 *
2992 * @param string $content Input value undergoing processing in this function.
2993 * @param array $conf stdWrap properties for removeBadHTML.
2994 * @return string The processed input value
2995 */
2996 public function stdWrap_removeBadHTML($content = '', $conf = array()) {
2997 return $this->removeBadHTML($content, $conf['removeBadHTML.']);
2998 }
2999
3000 /**
3001 * cropHTML
3002 * Crops content to a given size while leaving HTML tags untouched
3003 *
3004 * @param string $content Input value undergoing processing in this function.
3005 * @param array $conf stdWrap properties for cropHTML.
3006 * @return string The processed input value
3007 */
3008 public function stdWrap_cropHTML($content = '', $conf = array()) {
3009 return $this->cropHTML($content, $conf['cropHTML']);
3010 }
3011
3012 /**
3013 * stripHtml
3014 * Copmletely removes HTML tags from content
3015 *
3016 * @param string $content Input value undergoing processing in this function.
3017 * @param array $conf stdWrap properties for stripHtml.
3018 * @return string The processed input value
3019 */
3020 public function stdWrap_stripHtml($content = '', $conf = array()) {
3021 return strip_tags($content);
3022 }
3023
3024 /**
3025 * crop
3026 * Crops content to a given size without caring about HTML tags
3027 *
3028 * @param string $content Input value undergoing processing in this function.
3029 * @param array $conf stdWrap properties for crop.
3030 * @return string The processed input value
3031 */
3032 public function stdWrap_crop($content = '', $conf = array()) {
3033 return $this->