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