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