[TASK] CGL-Fix: Generic.CodeAnalysis.ForLoopWithTestFunctionCall
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Html / RteHtmlParser.php
1 <?php
2 namespace TYPO3\CMS\Core\Html;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 1999-2011 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 * Functions for parsing HTML, specially for TYPO3 processing in relation to TCEmain and Rich Text Editor (RTE)
31 * Revised for TYPO3 3.6 December/2003 by Kasper Skårhøj
32 * XHTML compatible.
33 *
34 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
35 * @internal
36 */
37 /**
38 * Class for parsing HTML for the Rich Text Editor. (also called transformations)
39 *
40 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
41 * @package TYPO3
42 * @subpackage t3lib
43 */
44 class RteHtmlParser extends \TYPO3\CMS\Core\Html\HtmlParser {
45
46 // Static:
47 /**
48 * @todo Define visibility
49 */
50 public $blockElementList = 'PRE,UL,OL,H1,H2,H3,H4,H5,H6,ADDRESS,DL,DD,HEADER,SECTION,FOOTER,NAV,ARTICLE,ASIDE';
51
52 // List of tags for these elements
53 // Internal, static:
54 // Set this to the pid of the record manipulated by the class.
55 /**
56 * @todo Define visibility
57 */
58 public $recPid = 0;
59
60 // Element reference [table]:[field], eg. "tt_content:bodytext"
61 /**
62 * @todo Define visibility
63 */
64 public $elRef = '';
65
66 // Relative path
67 /**
68 * @todo Define visibility
69 */
70 public $relPath = '';
71
72 // Relative back-path
73 /**
74 * @todo Define visibility
75 */
76 public $relBackPath = '';
77
78 // Current Page TSConfig
79 public $tsConfig = array();
80
81 // Set to the TSconfig options coming from Page TSconfig
82 /**
83 * @todo Define visibility
84 */
85 public $procOptions = '';
86
87 // Internal, dynamic
88 // Run-away brake for recursive calls.
89 /**
90 * @todo Define visibility
91 */
92 public $TS_transform_db_safecounter = 100;
93
94 // Parameters from TCA types configuration related to the RTE
95 /**
96 * @todo Define visibility
97 */
98 public $rte_p = '';
99
100 // Data caching for processing function
101 /**
102 * @todo Define visibility
103 */
104 public $getKeepTags_cache = array();
105
106 // Storage of the allowed CSS class names in the RTE
107 /**
108 * @todo Define visibility
109 */
110 public $allowedClasses = array();
111
112 // Set to tags to preserve from Page TSconfig configuration
113 /**
114 * @todo Define visibility
115 */
116 public $preserveTags = '';
117
118 /**
119 * Initialize, setting element reference and record PID
120 *
121 * @param string $elRef Element reference, eg "tt_content:bodytext
122 * @param integer $recPid PID of the record (page id)
123 * @return void
124 * @todo Define visibility
125 */
126 public function init($elRef = '', $recPid = 0) {
127 $this->recPid = $recPid;
128 $this->elRef = $elRef;
129 }
130
131 /**
132 * Setting the ->relPath and ->relBackPath to proper values so absolute references to links and images can be converted to relative dittos.
133 * This is used when editing files with the RTE
134 *
135 * @param string $path The relative path from PATH_site to the place where the file being edited is. Eg. "fileadmin/static".
136 * @return void There is no output, it is set in internal variables. With the above example of "fileadmin/static" as input this will yield ->relPath to be "fileadmin/static/" and ->relBackPath to be "../../
137 * @todo Define visibility
138 */
139 public function setRelPath($path) {
140 $path = trim($path);
141 $path = preg_replace('/^\\//', '', $path);
142 $path = preg_replace('/\\/$/', '', $path);
143 if ($path) {
144 $this->relPath = $path;
145 $this->relBackPath = '';
146 $partsC = count(explode('/', $this->relPath));
147 for ($a = 0; $a < $partsC; $a++) {
148 $this->relBackPath .= '../';
149 }
150 $this->relPath .= '/';
151 }
152 }
153
154 /**
155 * Evaluate the environment for editing a staticFileEdit file.
156 * Called for almost all fields being saved in the database. Is called without an instance of the object: t3lib_parsehtml_proc::evalWriteFile()
157 *
158 * @param array $pArr Parameters for the current field as found in types-config
159 * @param array $currentRecord Current record we are editing.
160 * @return mixed On success an array with various information is returned, otherwise a string with an error message
161 * @see t3lib_TCEmain, t3lib_transferData
162 */
163 static public function evalWriteFile($pArr, $currentRecord) {
164 // Write file configuration:
165 if (is_array($pArr)) {
166 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['staticFileEditPath'] && substr($GLOBALS['TYPO3_CONF_VARS']['BE']['staticFileEditPath'], -1) == '/' && @is_dir((PATH_site . $GLOBALS['TYPO3_CONF_VARS']['BE']['staticFileEditPath']))) {
167 $SW_p = $pArr['parameters'];
168 $SW_editFileField = trim($SW_p[0]);
169 $SW_editFile = $currentRecord[$SW_editFileField];
170 if ($SW_editFileField && $SW_editFile && \TYPO3\CMS\Core\Utility\GeneralUtility::validPathStr($SW_editFile)) {
171 $SW_relpath = $GLOBALS['TYPO3_CONF_VARS']['BE']['staticFileEditPath'] . $SW_editFile;
172 $SW_editFile = PATH_site . $SW_relpath;
173 if (@is_file($SW_editFile)) {
174 return array(
175 'editFile' => $SW_editFile,
176 'relEditFile' => $SW_relpath,
177 'contentField' => trim($SW_p[1]),
178 'markerField' => trim($SW_p[2]),
179 'loadFromFileField' => trim($SW_p[3]),
180 'statusField' => trim($SW_p[4])
181 );
182 } else {
183 return 'ERROR: Editfile \'' . $SW_relpath . '\' did not exist';
184 }
185 } else {
186 return 'ERROR: Edit file name could not be found or was bad.';
187 }
188 } else {
189 return 'ERROR: staticFileEditPath was not set, not set correctly or did not exist!';
190 }
191 }
192 }
193
194 /**********************************************
195 *
196 * Main function
197 *
198 **********************************************/
199 /**
200 * Transform value for RTE based on specConf in the direction specified by $direction (rte/db)
201 * This is the main function called from tcemain and transfer data classes
202 *
203 * @param string Input value
204 * @param array Special configuration for a field; This is coming from the types-configuration of the field in the TCA. In the types-configuration you can setup features for the field rendering and in particular the RTE takes al its major configuration options from there!
205 * @param string Direction of the transformation. Two keywords are allowed; "db" or "rte". If "db" it means the transformation will clean up content coming from the Rich Text Editor and goes into the database. The other direction, "rte", is of course when content is coming from database and must be transformed to fit the RTE.
206 * @param array Parsed TypoScript content configuring the RTE, probably coming from Page TSconfig.
207 * @return string Output value
208 * @see t3lib_TCEmain::fillInFieldArray(), t3lib_transferData::renderRecord_typesProc()
209 * @todo Define visibility
210 */
211 public function RTE_transform($value, $specConf, $direction = 'rte', $thisConfig = array()) {
212 // Init:
213 $this->tsConfig = $thisConfig;
214 $this->procOptions = $thisConfig['proc.'];
215 $this->preserveTags = strtoupper(implode(',', \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->procOptions['preserveTags'])));
216 // dynamic configuration of blockElementList
217 if ($this->procOptions['blockElementList']) {
218 $this->blockElementList = $this->procOptions['blockElementList'];
219 }
220 // Get parameters for rte_transformation:
221 $p = ($this->rte_p = \TYPO3\CMS\Backend\Utility\BackendUtility::getSpecConfParametersFromArray($specConf['rte_transform']['parameters']));
222 // Setting modes:
223 if (strcmp($this->procOptions['overruleMode'], '')) {
224 $modes = array_unique(\TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->procOptions['overruleMode']));
225 } else {
226 $modes = array_unique(\TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode('-', $p['mode']));
227 }
228 $revmodes = array_flip($modes);
229 // Find special modes and extract them:
230 if (isset($revmodes['ts'])) {
231 $modes[$revmodes['ts']] = 'ts_transform,ts_preserve,ts_images,ts_links';
232 }
233 // Find special modes and extract them:
234 if (isset($revmodes['ts_css'])) {
235 $modes[$revmodes['ts_css']] = 'css_transform,ts_images,ts_links';
236 }
237 // Make list unique
238 $modes = array_unique(\TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', implode(',', $modes), 1));
239 // Reverse order if direction is "rte"
240 if ($direction == 'rte') {
241 $modes = array_reverse($modes);
242 }
243 // Getting additional HTML cleaner configuration. These are applied either before or after the main transformation is done and is thus totally independant processing options you can set up:
244 $entry_HTMLparser = $this->procOptions['entryHTMLparser_' . $direction] ? $this->HTMLparserConfig($this->procOptions['entryHTMLparser_' . $direction . '.']) : '';
245 $exit_HTMLparser = $this->procOptions['exitHTMLparser_' . $direction] ? $this->HTMLparserConfig($this->procOptions['exitHTMLparser_' . $direction . '.']) : '';
246 // Line breaks of content is unified into char-10 only (removing char 13)
247 if (!$this->procOptions['disableUnifyLineBreaks']) {
248 $value = str_replace(CRLF, LF, $value);
249 }
250 // In an entry-cleaner was configured, pass value through the HTMLcleaner with that:
251 if (is_array($entry_HTMLparser)) {
252 $value = $this->HTMLcleaner($value, $entry_HTMLparser[0], $entry_HTMLparser[1], $entry_HTMLparser[2], $entry_HTMLparser[3]);
253 }
254 // Traverse modes:
255 foreach ($modes as $cmd) {
256 // ->DB
257 if ($direction == 'db') {
258 // Checking for user defined transformation:
259 if ($_classRef = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['transformation'][$cmd]) {
260 $_procObj = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($_classRef);
261 $_procObj->pObj = $this;
262 $_procObj->transformationKey = $cmd;
263 $value = $_procObj->transform_db($value, $this);
264 } else {
265 // ... else use defaults:
266 switch ($cmd) {
267 case 'ts_images':
268 $value = $this->TS_images_db($value);
269 break;
270 case 'ts_reglinks':
271 $value = $this->TS_reglinks($value, 'db');
272 break;
273 case 'ts_links':
274 $value = $this->TS_links_db($value);
275 break;
276 case 'ts_preserve':
277 $value = $this->TS_preserve_db($value);
278 break;
279 case 'ts_transform':
280
281 case 'css_transform':
282 // Has a very disturbing effect, so just remove all '13' - depend on '10'
283 $value = str_replace(CR, '', $value);
284 $this->allowedClasses = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->procOptions['allowedClasses'], 1);
285 $value = $this->TS_transform_db($value, $cmd == 'css_transform');
286 break;
287 case 'ts_strip':
288 $value = $this->TS_strip_db($value);
289 break;
290 default:
291 break;
292 }
293 }
294 }
295 // ->RTE
296 if ($direction == 'rte') {
297 // Checking for user defined transformation:
298 if ($_classRef = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['transformation'][$cmd]) {
299 $_procObj = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($_classRef);
300 $_procObj->pObj = $this;
301 $value = $_procObj->transform_rte($value, $this);
302 } else {
303 // ... else use defaults:
304 switch ($cmd) {
305 case 'ts_images':
306 $value = $this->TS_images_rte($value);
307 break;
308 case 'ts_reglinks':
309 $value = $this->TS_reglinks($value, 'rte');
310 break;
311 case 'ts_links':
312 $value = $this->TS_links_rte($value);
313 break;
314 case 'ts_preserve':
315 $value = $this->TS_preserve_rte($value);
316 break;
317 case 'ts_transform':
318
319 case 'css_transform':
320 // Has a very disturbing effect, so just remove all '13' - depend on '10'
321 $value = str_replace(CR, '', $value);
322 $value = $this->TS_transform_rte($value, $cmd == 'css_transform');
323 break;
324 default:
325 break;
326 }
327 }
328 }
329 }
330 // In an exit-cleaner was configured, pass value through the HTMLcleaner with that:
331 if (is_array($exit_HTMLparser)) {
332 $value = $this->HTMLcleaner($value, $exit_HTMLparser[0], $exit_HTMLparser[1], $exit_HTMLparser[2], $exit_HTMLparser[3]);
333 }
334 // Final clean up of linebreaks:
335 if (!$this->procOptions['disableUnifyLineBreaks']) {
336 // Make sure no \r\n sequences has entered in the meantime...
337 $value = str_replace(CRLF, LF, $value);
338 // ... and then change all \n into \r\n
339 $value = str_replace(LF, CRLF, $value);
340 }
341 // Return value:
342 return $value;
343 }
344
345 /************************************
346 *
347 * Specific RTE TRANSFORMATION functions
348 *
349 *************************************/
350 /**
351 * Transformation handler: 'ts_images' / direction: "db"
352 * Processing images inserted in the RTE.
353 * This is used when content goes from the RTE to the database.
354 * Images inserted in the RTE has an absolute URL applied to the src attribute. This URL is converted to a relative URL
355 * If it turns out that the URL is from another website than the current the image is read from that external URL and moved to the local server.
356 * Also "magic" images are processed here.
357 *
358 * @param string $value The content from RTE going to Database
359 * @return string Processed content
360 * @todo Define visibility
361 */
362 public function TS_images_db($value) {
363 // Split content by <img> tags and traverse the resulting array for processing:
364 $imgSplit = $this->splitTags('img', $value);
365 foreach ($imgSplit as $k => $v) {
366 // image found, do processing:
367 if ($k % 2) {
368 // Init
369 $attribArray = $this->get_tag_attributes_classic($v, 1);
370 $siteUrl = $this->siteUrl();
371 $sitePath = str_replace(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_REQUEST_HOST'), '', $siteUrl);
372 // It's always a absolute URL coming from the RTE into the Database.
373 $absRef = trim($attribArray['src']);
374 // Make path absolute if it is relative and we have a site path wich is not '/'
375 $pI = pathinfo($absRef);
376 if ($sitePath and !$pI['scheme'] && \TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($absRef, $sitePath)) {
377 // If site is in a subpath (eg. /~user_jim/) this path needs to be removed because it will be added with $siteUrl
378 $absRef = substr($absRef, strlen($sitePath));
379 $absRef = $siteUrl . $absRef;
380 }
381 // External image from another URL? In that case, fetch image (unless disabled feature).
382 if (!\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($absRef, $siteUrl) && !$this->procOptions['dontFetchExtPictures']) {
383 // Get it
384 $externalFile = $this->getUrl($absRef);
385 if ($externalFile) {
386 $pU = parse_url($absRef);
387 $pI = pathinfo($pU['path']);
388 if (\TYPO3\CMS\Core\Utility\GeneralUtility::inList('gif,png,jpeg,jpg', strtolower($pI['extension']))) {
389 $fileName = \TYPO3\CMS\Core\Utility\GeneralUtility::shortMD5($absRef) . '.' . $pI['extension'];
390 $folder = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->getFolderObjectFromCombinedIdentifier($this->rteImageStorageDir());
391 if ($folder instanceof \TYPO3\CMS\Core\Resource\Folder) {
392 $fileObject = $folder->createFile($fileName)->setContents($externalFile);
393 /** @var $magicImageService \TYPO3\CMS\Core\Resource\Service\MagicImageService */
394 $magicImageService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\Service\\MagicImageService');
395 $imageConfiguration = array(
396 'width' => $attribArray['width'],
397 'height' => $attribArray['height'],
398 'maxW' => 300,
399 'maxH' => 1000
400 );
401 $magicImage = $magicImageService->createMagicImage($fileObject, $imageConfiguration, $this->rteImageStorageDir());
402 if ($magicImage instanceof \TYPO3\CMS\Core\Resource\FileInterface) {
403 $filePath = $magicImage->getForLocalProcessing(FALSE);
404 $imageInfo = @getimagesize($filePath);
405 $attribArray['width'] = $imageInfo[0];
406 $attribArray['height'] = $imageInfo[1];
407 $attribArray['data-htmlarea-file-uid'] = $fileObject->getUid();
408 $absRef = $siteUrl . substr($filePath, strlen(PATH_site));
409 }
410 $attribArray['src'] = $absRef;
411 $params = \TYPO3\CMS\Core\Utility\GeneralUtility::implodeAttributes($attribArray, 1);
412 $imgSplit[$k] = '<img ' . $params . ' />';
413 }
414 }
415 }
416 }
417 // Check image as local file (siteURL equals the one of the image)
418 if (\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($absRef, $siteUrl)) {
419 // Rel-path, rawurldecoded for special characters.
420 $path = rawurldecode(substr($absRef, strlen($siteUrl)));
421 // Abs filepath, locked to relative path of this project.
422 $filepath = \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName($path);
423 // Check file existence (in relative dir to this installation!)
424 if ($filepath && @is_file($filepath)) {
425 // If "magic image":
426 $folder = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->getFolderObjectFromCombinedIdentifier($this->rteImageStorageDir());
427 if ($folder instanceof \TYPO3\CMS\Core\Resource\Folder) {
428 $storageConfiguration = $folder->getStorage()->getConfiguration();
429 $rteImageStorageDir = rtrim($storageConfiguration['basePath'], '/') . '/' . $folder->getName() . '/';
430 $pathPre = $rteImageStorageDir . 'RTEmagicC_';
431 if (\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($path, $pathPre)) {
432 // Find original file
433 if ($attribArray['data-htmlarea-file-uid']) {
434 $originalFileObject = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->getFileObject($attribArray['data-htmlarea-file-uid']);
435 } else {
436 // Backward compatibility mode
437 $pI = pathinfo(substr($path, strlen($pathPre)));
438 $filename = substr($pI['basename'], 0, -strlen(('.' . $pI['extension'])));
439 $origFilePath = PATH_site . $rteImageStorageDir . 'RTEmagicP_' . $filename;
440 if (@is_file($origFilePath)) {
441 $originalFileObject = $folder->addFile($origFilePath, $filename, 'changeName');
442 $attribArray['data-htmlarea-file-uid'] = $originalFileObject->getUid();
443 }
444 }
445 if (!empty($originalFileObject) && $originalFileObject instanceof \TYPO3\CMS\Core\Resource\FileInterface) {
446 /** @var $magicImageService \TYPO3\CMS\Core\Resource\Service\MagicImageService */
447 $magicImageService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\Service\\MagicImageService');
448 // Image dimensions of the current image
449 $imageDimensions = @getimagesize($filepath);
450 // Image dimensions as set on the img tag
451 $imgTagDimensions = $this->getWHFromAttribs($attribArray);
452 // If the dimensions have changed, we re-create the magic image
453 if ($imgTagDimensions[0] != $imageDimensions[0] || $imgTagDimensions[1] != $imageDimensions[1]) {
454 $imageConfiguration = array(
455 'width' => $imgTagDimensions[0],
456 'height' => $imgTagDimensions[1],
457 'maxW' => 300,
458 'maxH' => 1000
459 );
460 // TODO: Perhaps the existing magic image should be overridden?
461 $magicImage = $magicImageService->createMagicImage($originalFileObject, $imageConfiguration, $this->rteImageStorageDir());
462 if ($magicImage instanceof \TYPO3\CMS\Core\Resource\FileInterface) {
463 $filePath = $magicImage->getForLocalProcessing(FALSE);
464 $imageInfo = @getimagesize($filePath);
465 // Removing width and height from any style attribute
466 $attribArray['style'] = preg_replace('/((?:^|)\\s*(?:width|height)\\s*:[^;]*(?:$|;))/si', '', $attribArray['style']);
467 $attribArray['width'] = $imageInfo[0];
468 $attribArray['height'] = $imageInfo[1];
469 $attribArray['src'] = $this->siteURL() . substr($filePath, strlen(PATH_site));
470 $params = \TYPO3\CMS\Core\Utility\GeneralUtility::implodeAttributes($attribArray, 1);
471 $imgSplit[$k] = '<img ' . $params . ' />';
472 }
473 }
474 }
475 } elseif ($this->procOptions['plainImageMode']) {
476 // If "plain image" has been configured:
477 // Image dimensions as set in the image tag, if any
478 $curWH = $this->getWHFromAttribs($attribArray);
479 if ($curWH[0]) {
480 $attribArray['width'] = $curWH[0];
481 }
482 if ($curWH[1]) {
483 $attribArray['height'] = $curWH[1];
484 }
485 // Removing width and heigth form style attribute
486 $attribArray['style'] = preg_replace('/((?:^|)\\s*(?:width|height)\\s*:[^;]*(?:$|;))/si', '', $attribArray['style']);
487 // Finding dimensions of image file:
488 $fI = @getimagesize($filepath);
489 // Perform corrections to aspect ratio based on configuration:
490 switch ((string) $this->procOptions['plainImageMode']) {
491 case 'lockDimensions':
492 $attribArray['width'] = $fI[0];
493 $attribArray['height'] = $fI[1];
494 break;
495 case 'lockRatioWhenSmaller':
496 if ($attribArray['width'] > $fI[0]) {
497 $attribArray['width'] = $fI[0];
498 }
499 case 'lockRatio':
500 if ($fI[0] > 0) {
501 $attribArray['height'] = round($attribArray['width'] * ($fI[1] / $fI[0]));
502 }
503 break;
504 }
505 // Compile the image tag again:
506 $params = \TYPO3\CMS\Core\Utility\GeneralUtility::implodeAttributes($attribArray, 1);
507 $imgSplit[$k] = '<img ' . $params . ' />';
508 }
509 }
510 }
511 }
512 // Convert abs to rel url
513 if ($imgSplit[$k]) {
514 $attribArray = $this->get_tag_attributes_classic($imgSplit[$k], 1);
515 $absRef = trim($attribArray['src']);
516 if (\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($absRef, $siteUrl)) {
517 $attribArray['src'] = $this->relBackPath . substr($absRef, strlen($siteUrl));
518 if (!isset($attribArray['alt'])) {
519 $attribArray['alt'] = '';
520 }
521 // Must have alt-attribute for XHTML compliance.
522 $imgSplit[$k] = '<img ' . \TYPO3\CMS\Core\Utility\GeneralUtility::implodeAttributes($attribArray, 1, 1) . ' />';
523 }
524 }
525 }
526 }
527 return implode('', $imgSplit);
528 }
529
530 /**
531 * Transformation handler: 'ts_images' / direction: "rte"
532 * Processing images from database content going into the RTE.
533 * Processing includes converting the src attribute to an absolute URL.
534 *
535 * @param string $value Content input
536 * @return string Content output
537 * @todo Define visibility
538 */
539 public function TS_images_rte($value) {
540 $siteUrl = $this->siteUrl();
541 $sitePath = str_replace(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_REQUEST_HOST'), '', $siteUrl);
542 // Split content by <img> tags and traverse the resulting array for processing:
543 $imgSplit = $this->splitTags('img', $value);
544 foreach ($imgSplit as $k => $v) {
545 // image found:
546 if ($k % 2) {
547 // Init
548 $attribArray = $this->get_tag_attributes_classic($v, 1);
549 $absRef = trim($attribArray['src']);
550 // Unless the src attribute is already pointing to an external URL:
551 if (strtolower(substr($absRef, 0, 4)) != 'http') {
552 $attribArray['src'] = substr($attribArray['src'], strlen($this->relBackPath));
553 // If site is in a subpath (eg. /~user_jim/) this path needs to be removed because it will be added with $siteUrl
554 $attribArray['src'] = preg_replace('#^' . preg_quote($sitePath, '#') . '#', '', $attribArray['src']);
555 $attribArray['src'] = $siteUrl . $attribArray['src'];
556 if (!isset($attribArray['alt'])) {
557 $attribArray['alt'] = '';
558 }
559 $params = \TYPO3\CMS\Core\Utility\GeneralUtility::implodeAttributes($attribArray);
560 $imgSplit[$k] = '<img ' . $params . ' />';
561 }
562 }
563 }
564 // Return processed content:
565 return implode('', $imgSplit);
566 }
567
568 /**
569 * Transformation handler: 'ts_reglinks' / direction: "db"+"rte" depending on $direction variable.
570 * Converting <A>-tags to/from abs/rel
571 *
572 * @param string $value Content input
573 * @param string $direction Direction of conversion; "rte" (from database to RTE) or "db" (from RTE to database)
574 * @return string Content output
575 * @todo Define visibility
576 */
577 public function TS_reglinks($value, $direction) {
578 $retVal = '';
579 switch ($direction) {
580 case 'rte':
581 $retVal = $this->TS_AtagToAbs($value, 1);
582 break;
583 case 'db':
584 $siteURL = $this->siteUrl();
585 $blockSplit = $this->splitIntoBlock('A', $value);
586 foreach ($blockSplit as $k => $v) {
587 // Block
588 if ($k % 2) {
589 $attribArray = $this->get_tag_attributes_classic($this->getFirstTag($v), 1);
590 // If the url is local, remove url-prefix
591 if ($siteURL && substr($attribArray['href'], 0, strlen($siteURL)) == $siteURL) {
592 $attribArray['href'] = $this->relBackPath . substr($attribArray['href'], strlen($siteURL));
593 }
594 $bTag = '<a ' . \TYPO3\CMS\Core\Utility\GeneralUtility::implodeAttributes($attribArray, 1) . '>';
595 $eTag = '</a>';
596 $blockSplit[$k] = $bTag . $this->TS_reglinks($this->removeFirstAndLastTag($blockSplit[$k]), $direction) . $eTag;
597 }
598 }
599 $retVal = implode('', $blockSplit);
600 break;
601 }
602 return $retVal;
603 }
604
605 /**
606 * Transformation handler: 'ts_links' / direction: "db"
607 * Converting <A>-tags to <link tags>
608 *
609 * @param string $value Content input
610 * @return string Content output
611 * @see TS_links_rte()
612 * @todo Define visibility
613 */
614 public function TS_links_db($value) {
615 $conf = array();
616 // Split content into <a> tag blocks and process:
617 $blockSplit = $this->splitIntoBlock('A', $value);
618 foreach ($blockSplit as $k => $v) {
619 // If an A-tag was found:
620 if ($k % 2) {
621 $attribArray = $this->get_tag_attributes_classic($this->getFirstTag($v), 1);
622 $info = $this->urlInfoForLinkTags($attribArray['href']);
623 // Check options:
624 $attribArray_copy = $attribArray;
625 unset($attribArray_copy['href']);
626 unset($attribArray_copy['target']);
627 unset($attribArray_copy['class']);
628 unset($attribArray_copy['title']);
629 unset($attribArray_copy['data-htmlarea-external']);
630 // Unset "rteerror" and "style" attributes if "rteerror" is set!
631 if ($attribArray_copy['rteerror']) {
632 unset($attribArray_copy['style']);
633 unset($attribArray_copy['rteerror']);
634 }
635 // Remove additional parameters
636 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['removeParams_PostProc']) && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['removeParams_PostProc'])) {
637 $parameters = array(
638 'conf' => &$conf,
639 'aTagParams' => &$attribArray_copy
640 );
641 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['removeParams_PostProc'] as $objRef) {
642 $processor = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($objRef);
643 $attribArray_copy = $processor->removeParams($parameters, $this);
644 }
645 }
646 // Only if href, target, class and tile are the only attributes, we can alter the link!
647 if (!count($attribArray_copy)) {
648 // Quoting class and title attributes if they contain spaces
649 $attribArray['class'] = preg_match('/ /', $attribArray['class']) ? '"' . $attribArray['class'] . '"' : $attribArray['class'];
650 $attribArray['title'] = preg_match('/ /', $attribArray['title']) ? '"' . $attribArray['title'] . '"' : $attribArray['title'];
651 // Creating the TYPO3 pseudo-tag "<LINK>" for the link (includes href/url, target and class attributes):
652 // If data-htmlarea-external attribute is set, keep the href unchanged
653 $href = ($attribArray['data-htmlarea-external'] ? $attribArray['href'] : $info['url']) . ($info['query'] ? ',0,' . $info['query'] : '');
654 $bTag = '<link ' . $href . ($attribArray['target'] ? ' ' . $attribArray['target'] : ($attribArray['class'] || $attribArray['title'] ? ' -' : '')) . ($attribArray['class'] ? ' ' . $attribArray['class'] : ($attribArray['title'] ? ' -' : '')) . ($attribArray['title'] ? ' ' . $attribArray['title'] : '') . '>';
655 $eTag = '</link>';
656 // Modify parameters
657 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['modifyParams_LinksDb_PostProc']) && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['modifyParams_LinksDb_PostProc'])) {
658 $parameters = array(
659 'conf' => &$conf,
660 'currentBlock' => $v,
661 'url' => $href,
662 'attributes' => $attribArray
663 );
664 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['modifyParams_LinksDb_PostProc'] as $objRef) {
665 $processor = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($objRef);
666 $blockSplit[$k] = $processor->modifyParamsLinksDb($parameters, $this);
667 }
668 } else {
669 $blockSplit[$k] = $bTag . $this->TS_links_db($this->removeFirstAndLastTag($blockSplit[$k])) . $eTag;
670 }
671 } else {
672 // ... otherwise store the link as a-tag.
673 // Unsetting 'rtekeep' attribute if that had been set.
674 unset($attribArray['rtekeep']);
675 if (!$attribArray['data-htmlarea-external']) {
676 // If the url is local, remove url-prefix
677 $siteURL = $this->siteUrl();
678 if ($siteURL && substr($attribArray['href'], 0, strlen($siteURL)) == $siteURL) {
679 $attribArray['href'] = $this->relBackPath . substr($attribArray['href'], strlen($siteURL));
680 }
681 }
682 unset($attribArray['data-htmlarea-external']);
683 $bTag = '<a ' . \TYPO3\CMS\Core\Utility\GeneralUtility::implodeAttributes($attribArray, 1) . '>';
684 $eTag = '</a>';
685 $blockSplit[$k] = $bTag . $this->TS_links_db($this->removeFirstAndLastTag($blockSplit[$k])) . $eTag;
686 }
687 }
688 }
689 return implode('', $blockSplit);
690 }
691
692 /**
693 * Transformation handler: 'ts_links' / direction: "rte"
694 * Converting <link tags> to <A>-tags
695 *
696 * @param string $value Content input
697 * @return string Content output
698 * @see TS_links_rte()
699 * @todo Define visibility
700 */
701 public function TS_links_rte($value) {
702 $conf = array();
703 $value = $this->TS_AtagToAbs($value);
704 // Split content by the TYPO3 pseudo tag "<link>":
705 $blockSplit = $this->splitIntoBlock('link', $value, 1);
706 $siteUrl = $this->siteUrl();
707 foreach ($blockSplit as $k => $v) {
708 $error = '';
709 $external = FALSE;
710 // Block
711 if ($k % 2) {
712 $tagCode = \TYPO3\CMS\Core\Utility\GeneralUtility::unQuoteFilenames(trim(substr($this->getFirstTag($v), 0, -1)), TRUE);
713 $link_param = $tagCode[1];
714 $href = '';
715 // Parsing the typolink data. This parsing is roughly done like in tslib_content->typolink()
716 if (strstr($link_param, '@')) {
717 // mailadr
718 $href = 'mailto:' . preg_replace('/^mailto:/i', '', $link_param);
719 } elseif (substr($link_param, 0, 1) == '#') {
720 // check if anchor
721 $href = $siteUrl . $link_param;
722 } else {
723 // Check for FAL link-handler keyword:
724 list($linkHandlerKeyword, $linkHandlerValue) = explode(':', trim($link_param), 2);
725 if ($linkHandlerKeyword === 'file') {
726 $href = $siteUrl . '?' . $linkHandlerKeyword . ':' . rawurlencode($linkHandlerValue);
727 } else {
728 $fileChar = intval(strpos($link_param, '/'));
729 $urlChar = intval(strpos($link_param, '.'));
730 // Parse URL:
731 $pU = parse_url($link_param);
732 // Detects if a file is found in site-root.
733 list($rootFileDat) = explode('?', $link_param);
734 $rFD_fI = pathinfo($rootFileDat);
735 if (trim($rootFileDat) && !strstr($link_param, '/') && (@is_file((PATH_site . $rootFileDat)) || \TYPO3\CMS\Core\Utility\GeneralUtility::inList('php,html,htm', strtolower($rFD_fI['extension'])))) {
736 $href = $siteUrl . $link_param;
737 } elseif ($pU['scheme'] || $urlChar && (!$fileChar || $urlChar < $fileChar)) {
738 // url (external): if has scheme or if a '.' comes before a '/'.
739 $href = $link_param;
740 if (!$pU['scheme']) {
741 $href = 'http://' . $href;
742 }
743 $external = TRUE;
744 } elseif ($fileChar) {
745 // file (internal)
746 $href = $siteUrl . $link_param;
747 } else {
748 // integer or alias (alias is without slashes or periods or commas, that is 'nospace,alphanum_x,lower,unique' according to tables.php!!)
749 // Splitting the parameter by ',' and if the array counts more than 1 element it's a id/type/parameters triplet
750 $pairParts = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $link_param, TRUE);
751 $idPart = $pairParts[0];
752 $link_params_parts = explode('#', $idPart);
753 $idPart = trim($link_params_parts[0]);
754 $sectionMark = trim($link_params_parts[1]);
755 if (!strcmp($idPart, '')) {
756 $idPart = $this->recPid;
757 }
758 // If no id or alias is given, set it to class record pid
759 // Checking if the id-parameter is an alias.
760 if (!\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($idPart)) {
761 list($idPartR) = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecordsByField('pages', 'alias', $idPart);
762 $idPart = intval($idPartR['uid']);
763 }
764 $page = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('pages', $idPart);
765 if (is_array($page)) {
766 // Page must exist...
767 $href = $siteUrl . '?id=' . $idPart . ($pairParts[2] ? $pairParts[2] : '') . ($sectionMark ? '#' . $sectionMark : '');
768 } elseif (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['typolinkLinkHandler'][array_shift(explode(':', $link_param))])) {
769 $href = $link_param;
770 } else {
771 $href = $siteUrl . '?id=' . $link_param;
772 $error = 'No page found: ' . $idPart;
773 }
774 }
775 }
776 }
777 // Setting the A-tag:
778 $bTag = '<a href="' . htmlspecialchars($href) . '"' . ($tagCode[2] && $tagCode[2] != '-' ? ' target="' . htmlspecialchars($tagCode[2]) . '"' : '') . ($tagCode[3] && $tagCode[3] != '-' ? ' class="' . htmlspecialchars($tagCode[3]) . '"' : '') . ($tagCode[4] ? ' title="' . htmlspecialchars($tagCode[4]) . '"' : '') . ($external ? ' data-htmlarea-external="1"' : '') . ($error ? ' rteerror="' . htmlspecialchars($error) . '" style="background-color: yellow; border:2px red solid; color: black;"' : '') . '>';
779 $eTag = '</a>';
780 // Modify parameters
781 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['modifyParams_LinksRte_PostProc']) && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['modifyParams_LinksRte_PostProc'])) {
782 $parameters = array(
783 'conf' => &$conf,
784 'currentBlock' => $v,
785 'url' => $href,
786 'tagCode' => $tagCode,
787 'external' => $external,
788 'error' => $error
789 );
790 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['modifyParams_LinksRte_PostProc'] as $objRef) {
791 $processor = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($objRef);
792 $blockSplit[$k] = $processor->modifyParamsLinksRte($parameters, $this);
793 }
794 } else {
795 $blockSplit[$k] = $bTag . $this->TS_links_rte($this->removeFirstAndLastTag($blockSplit[$k])) . $eTag;
796 }
797 }
798 }
799 // Return content:
800 return implode('', $blockSplit);
801 }
802
803 /**
804 * Preserve special tags
805 *
806 * @param string $value Content input
807 * @return string Content output
808 * @todo Define visibility
809 */
810 public function TS_preserve_db($value) {
811 if (!$this->preserveTags) {
812 return $value;
813 }
814 // Splitting into blocks for processing (span-tags are used for special tags)
815 $blockSplit = $this->splitIntoBlock('span', $value);
816 foreach ($blockSplit as $k => $v) {
817 // Block
818 if ($k % 2) {
819 $attribArray = $this->get_tag_attributes_classic($this->getFirstTag($v));
820 if ($attribArray['specialtag']) {
821 $theTag = rawurldecode($attribArray['specialtag']);
822 $theTagName = $this->getFirstTagName($theTag);
823 $blockSplit[$k] = $theTag . $this->removeFirstAndLastTag($blockSplit[$k]) . '</' . $theTagName . '>';
824 }
825 }
826 }
827 return implode('', $blockSplit);
828 }
829
830 /**
831 * Preserve special tags
832 *
833 * @param string $value Content input
834 * @return string Content output
835 * @todo Define visibility
836 */
837 public function TS_preserve_rte($value) {
838 if (!$this->preserveTags) {
839 return $value;
840 }
841 $blockSplit = $this->splitIntoBlock($this->preserveTags, $value);
842 foreach ($blockSplit as $k => $v) {
843 // Block
844 if ($k % 2) {
845 $blockSplit[$k] = '<span specialtag="' . rawurlencode($this->getFirstTag($v)) . '">' . $this->removeFirstAndLastTag($blockSplit[$k]) . '</span>';
846 }
847 }
848 return implode('', $blockSplit);
849 }
850
851 /**
852 * Transformation handler: 'ts_transform' + 'css_transform' / direction: "db"
853 * Cleaning (->db) for standard content elements (ts)
854 *
855 * @param string $value Content input
856 * @param boolean $css If TRUE, the transformation was "css_transform", otherwise "ts_transform
857 * @return string Content output
858 * @see TS_transform_rte()
859 * @todo Define visibility
860 */
861 public function TS_transform_db($value, $css = FALSE) {
862 // Safety... so forever loops are avoided (they should not occur, but an error would potentially do this...)
863 $this->TS_transform_db_safecounter--;
864 if ($this->TS_transform_db_safecounter < 0) {
865 return $value;
866 }
867 // Split the content from RTE by the occurence of these blocks:
868 $blockSplit = $this->splitIntoBlock('TABLE,BLOCKQUOTE,' . ($this->procOptions['preserveDIVSections'] ? 'DIV,' : '') . $this->blockElementList, $value);
869 $cc = 0;
870 $aC = count($blockSplit);
871 // Avoid superfluous linebreaks by transform_db after ending headListTag
872 while ($aC && !strcmp(trim($blockSplit[($aC - 1)]), '')) {
873 unset($blockSplit[$aC - 1]);
874 $aC = count($blockSplit);
875 }
876 // Traverse the blocks
877 foreach ($blockSplit as $k => $v) {
878 $cc++;
879 $lastBR = $cc == $aC ? '' : LF;
880 if ($k % 2) {
881 // Inside block:
882 // Init:
883 $tag = $this->getFirstTag($v);
884 $tagName = strtolower($this->getFirstTagName($v));
885 // Process based on the tag:
886 switch ($tagName) {
887 case 'blockquote':
888
889 case 'dd':
890
891 case 'div':
892
893 case 'header':
894
895 case 'section':
896
897 case 'footer':
898
899 case 'nav':
900
901 case 'article':
902
903 case 'aside':
904 $blockSplit[$k] = $tag . $this->TS_transform_db($this->removeFirstAndLastTag($blockSplit[$k]), $css) . '</' . $tagName . '>' . $lastBR;
905 break;
906 case 'ol':
907
908 case 'ul':
909 // Transform lists into <typolist>-tags:
910 if (!$css) {
911 if (!isset($this->procOptions['typolist']) || $this->procOptions['typolist']) {
912 $parts = $this->getAllParts($this->splitIntoBlock('LI', $this->removeFirstAndLastTag($blockSplit[$k])), 1, 0);
913 foreach ($parts as $k2 => $value) {
914 $parts[$k2] = preg_replace('/[' . preg_quote((LF . CR)) . ']+/', '', $parts[$k2]);
915 // remove all linesbreaks!
916 $parts[$k2] = $this->defaultTStagMapping($parts[$k2], 'db');
917 $parts[$k2] = $this->cleanFontTags($parts[$k2], 0, 0, 0);
918 $parts[$k2] = $this->HTMLcleaner_db($parts[$k2], strtolower($this->procOptions['allowTagsInTypolists'] ? $this->procOptions['allowTagsInTypolists'] : 'br,font,b,i,u,a,img,span,strong,em'));
919 }
920 if ($tagName == 'ol') {
921 $params = ' type="1"';
922 } else {
923 $params = '';
924 }
925 $blockSplit[$k] = '<typolist' . $params . '>' . LF . implode(LF, $parts) . LF . '</typolist>' . $lastBR;
926 }
927 } else {
928 $blockSplit[$k] = preg_replace(('/[' . preg_quote((LF . CR)) . ']+/'), ' ', $this->transformStyledATags($blockSplit[$k])) . $lastBR;
929 }
930 break;
931 case 'table':
932 // Tables are NOT allowed in any form (unless preserveTables is set or CSS is the mode)
933 if (!$this->procOptions['preserveTables'] && !$css) {
934 $blockSplit[$k] = $this->TS_transform_db($this->removeTables($blockSplit[$k]));
935 } else {
936 $blockSplit[$k] = preg_replace(('/[' . preg_quote((LF . CR)) . ']+/'), ' ', $this->transformStyledATags($blockSplit[$k])) . $lastBR;
937 }
938 break;
939 case 'h1':
940
941 case 'h2':
942
943 case 'h3':
944
945 case 'h4':
946
947 case 'h5':
948
949 case 'h6':
950 if (!$css) {
951 $attribArray = $this->get_tag_attributes_classic($tag);
952 // Processing inner content here:
953 $innerContent = $this->HTMLcleaner_db($this->removeFirstAndLastTag($blockSplit[$k]));
954 if (!isset($this->procOptions['typohead']) || $this->procOptions['typohead']) {
955 $type = intval(substr($tagName, 1));
956 $blockSplit[$k] = '<typohead' . ($type != 6 ? ' type="' . $type . '"' : '') . ($attribArray['align'] ? ' align="' . $attribArray['align'] . '"' : '') . ($attribArray['class'] ? ' class="' . $attribArray['class'] . '"' : '') . '>' . $innerContent . '</typohead>' . $lastBR;
957 } else {
958 $blockSplit[$k] = '<' . $tagName . ($attribArray['align'] ? ' align="' . htmlspecialchars($attribArray['align']) . '"' : '') . ($attribArray['class'] ? ' class="' . htmlspecialchars($attribArray['class']) . '"' : '') . '>' . $innerContent . '</' . $tagName . '>' . $lastBR;
959 }
960 } else {
961 // Eliminate true linebreaks inside Hx tags
962 $blockSplit[$k] = preg_replace(('/[' . preg_quote((LF . CR)) . ']+/'), ' ', $this->transformStyledATags($blockSplit[$k])) . $lastBR;
963 }
964 break;
965 default:
966 // Eliminate true linebreaks inside other headlist tags
967 $blockSplit[$k] = preg_replace(('/[' . preg_quote((LF . CR)) . ']+/'), ' ', $this->transformStyledATags($blockSplit[$k])) . $lastBR;
968 break;
969 }
970 } else {
971 // NON-block:
972 if (strcmp(trim($blockSplit[$k]), '')) {
973 $blockSplit[$k] = preg_replace('/<hr\\/>/', '<hr />', $blockSplit[$k]);
974 // Remove linebreaks preceding hr tags
975 $blockSplit[$k] = preg_replace('/[' . preg_quote((LF . CR)) . ']+<(hr)(\\s[^>\\/]*)?[[:space:]]*\\/?>/', '<$1$2/>', $blockSplit[$k]);
976 // Remove linebreaks following hr tags
977 $blockSplit[$k] = preg_replace('/<(hr)(\\s[^>\\/]*)?[[:space:]]*\\/?>[' . preg_quote((LF . CR)) . ']+/', '<$1$2/>', $blockSplit[$k]);
978 // Replace other linebreaks with space
979 $blockSplit[$k] = preg_replace('/[' . preg_quote((LF . CR)) . ']+/', ' ', $blockSplit[$k]);
980 $blockSplit[$k] = $this->divideIntoLines($blockSplit[$k]) . $lastBR;
981 $blockSplit[$k] = $this->transformStyledATags($blockSplit[$k]);
982 } else {
983 unset($blockSplit[$k]);
984 }
985 }
986 }
987 $this->TS_transform_db_safecounter++;
988 return implode('', $blockSplit);
989 }
990
991 /**
992 * Wraps a-tags that contain a style attribute with a span-tag
993 *
994 * @param string $value Content input
995 * @return string Content output
996 * @todo Define visibility
997 */
998 public function transformStyledATags($value) {
999 $blockSplit = $this->splitIntoBlock('A', $value);
1000 foreach ($blockSplit as $k => $v) {
1001 // If an A-tag was found
1002 if ($k % 2) {
1003 $attribArray = $this->get_tag_attributes_classic($this->getFirstTag($v), 1);
1004 // If "style" attribute is set and rteerror is not set!
1005 if ($attribArray['style'] && !$attribArray['rteerror']) {
1006 $attribArray_copy['style'] = $attribArray['style'];
1007 unset($attribArray['style']);
1008 $bTag = '<span ' . \TYPO3\CMS\Core\Utility\GeneralUtility::implodeAttributes($attribArray_copy, 1) . '><a ' . \TYPO3\CMS\Core\Utility\GeneralUtility::implodeAttributes($attribArray, 1) . '>';
1009 $eTag = '</a></span>';
1010 $blockSplit[$k] = $bTag . $this->removeFirstAndLastTag($blockSplit[$k]) . $eTag;
1011 }
1012 }
1013 }
1014 return implode('', $blockSplit);
1015 }
1016
1017 /**
1018 * Transformation handler: 'ts_transform' + 'css_transform' / direction: "rte"
1019 * Set (->rte) for standard content elements (ts)
1020 *
1021 * @param string Content input
1022 * @param boolean If TRUE, the transformation was "css_transform", otherwise "ts_transform
1023 * @return string Content output
1024 * @see TS_transform_db()
1025 * @todo Define visibility
1026 */
1027 public function TS_transform_rte($value, $css = 0) {
1028 // Split the content from Database by the occurence of these blocks:
1029 $blockSplit = $this->splitIntoBlock('TABLE,BLOCKQUOTE,TYPOLIST,TYPOHEAD,' . ($this->procOptions['preserveDIVSections'] ? 'DIV,' : '') . $this->blockElementList, $value);
1030 // Traverse the blocks
1031 foreach ($blockSplit as $k => $v) {
1032 if ($k % 2) {
1033 // Inside one of the blocks:
1034 // Init:
1035 $tag = $this->getFirstTag($v);
1036 $tagName = strtolower($this->getFirstTagName($v));
1037 $attribArray = $this->get_tag_attributes_classic($tag);
1038 // Based on tagname, we do transformations:
1039 switch ($tagName) {
1040 case 'blockquote':
1041
1042 case 'dd':
1043
1044 case 'div':
1045
1046 case 'header':
1047
1048 case 'section':
1049
1050 case 'footer':
1051
1052 case 'nav':
1053
1054 case 'article':
1055
1056 case 'aside':
1057 $blockSplit[$k] = $tag . $this->TS_transform_rte($this->removeFirstAndLastTag($blockSplit[$k]), $css) . '</' . $tagName . '>';
1058 break;
1059 case 'typolist':
1060 // Transform typolist blocks into OL/UL lists. Type 1 is expected to be numerical block
1061 if (!isset($this->procOptions['typolist']) || $this->procOptions['typolist']) {
1062 $tListContent = $this->removeFirstAndLastTag($blockSplit[$k]);
1063 $tListContent = preg_replace('/^[ ]*' . LF . '/', '', $tListContent);
1064 $tListContent = preg_replace('/' . LF . '[ ]*$/', '', $tListContent);
1065 $lines = explode(LF, $tListContent);
1066 $typ = $attribArray['type'] == 1 ? 'ol' : 'ul';
1067 $blockSplit[$k] = '<' . $typ . '>' . LF . '<li>' . implode(('</li>' . LF . '<li>'), $lines) . '</li>' . '</' . $typ . '>';
1068 }
1069 break;
1070 case 'typohead':
1071 // Transform typohead into Hx tags.
1072 if (!isset($this->procOptions['typohead']) || $this->procOptions['typohead']) {
1073 $tC = $this->removeFirstAndLastTag($blockSplit[$k]);
1074 $typ = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($attribArray['type'], 0, 6);
1075 if (!$typ) {
1076 $typ = 6;
1077 }
1078 $align = $attribArray['align'] ? ' align="' . $attribArray['align'] . '"' : '';
1079 $class = $attribArray['class'] ? ' class="' . $attribArray['class'] . '"' : '';
1080 $blockSplit[$k] = '<h' . $typ . $align . $class . '>' . $tC . '</h' . $typ . '>';
1081 }
1082 break;
1083 }
1084 $blockSplit[$k + 1] = preg_replace('/^[ ]*' . LF . '/', '', $blockSplit[$k + 1]);
1085 } else {
1086 // NON-block:
1087 $nextFTN = $this->getFirstTagName($blockSplit[$k + 1]);
1088 $singleLineBreak = $blockSplit[$k] == LF;
1089 if (\TYPO3\CMS\Core\Utility\GeneralUtility::inList('TABLE,BLOCKQUOTE,TYPOLIST,TYPOHEAD,' . ($this->procOptions['preserveDIVSections'] ? 'DIV,' : '') . $this->blockElementList, $nextFTN)) {
1090 // Removing linebreak if typolist/typohead
1091 $blockSplit[$k] = preg_replace('/' . LF . '[ ]*$/', '', $blockSplit[$k]);
1092 }
1093 // If $blockSplit[$k] is blank then unset the line. UNLESS the line happend to be a single line break.
1094 if (!strcmp($blockSplit[$k], '') && !$singleLineBreak) {
1095 unset($blockSplit[$k]);
1096 } else {
1097 $blockSplit[$k] = $this->setDivTags($blockSplit[$k], $this->procOptions['useDIVasParagraphTagForRTE'] ? 'div' : 'p');
1098 }
1099 }
1100 }
1101 return implode(LF, $blockSplit);
1102 }
1103
1104 /**
1105 * Transformation handler: 'ts_strip' / direction: "db"
1106 * Removing all non-allowed tags
1107 *
1108 * @param string $value Content input
1109 * @return string Content output
1110 * @todo Define visibility
1111 */
1112 public function TS_strip_db($value) {
1113 $value = strip_tags($value, '<' . implode('><', explode(',', 'b,i,u,a,img,br,div,center,pre,font,hr,sub,sup,p,strong,em,li,ul,ol,blockquote')) . '>');
1114 return $value;
1115 }
1116
1117 /***************************************************************
1118 *
1119 * Generic RTE transformation, analysis and helper functions
1120 *
1121 **************************************************************/
1122 /**
1123 * Reads the file or url $url and returns the content
1124 *
1125 * @param string $url Filepath/URL to read
1126 * @return string The content from the resource given as input.
1127 * @see t3lib_div::getUrl()
1128 * @todo Define visibility
1129 */
1130 public function getUrl($url) {
1131 return \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($url);
1132 }
1133
1134 /**
1135 * Function for cleaning content going into the database.
1136 * Content is cleaned eg. by removing unallowed HTML and ds-HSC content
1137 * It is basically calling HTMLcleaner from the parent class with some preset configuration specifically set up for cleaning content going from the RTE into the db
1138 *
1139 * @param string $content Content to clean up
1140 * @param string $tagList Comma list of tags to specifically allow. Default comes from getKeepTags and is
1141 * @return string Clean content
1142 * @see getKeepTags()
1143 * @todo Define visibility
1144 */
1145 public function HTMLcleaner_db($content, $tagList = '') {
1146 if (!$tagList) {
1147 $keepTags = $this->getKeepTags('db');
1148 } else {
1149 $keepTags = $this->getKeepTags('db', $tagList);
1150 }
1151 // Default: remove unknown tags.
1152 $kUknown = $this->procOptions['dontRemoveUnknownTags_db'] ? 1 : 0;
1153 // Default: re-convert literals to characters (that is &lt; to <)
1154 $hSC = $this->procOptions['dontUndoHSC_db'] ? 0 : -1;
1155 // Create additional configuration in order to honor the setting RTE.default.proc.HTMLparser_db.xhtml_cleaning=1
1156 $addConfig = array();
1157 if (is_array($this->procOptions['HTMLparser_db.']) && $this->procOptions['HTMLparser_db.']['xhtml_cleaning'] || is_array($this->procOptions['entryHTMLparser_db.']) && $this->procOptions['entryHTMLparser_db.']['xhtml_cleaning'] || is_array($this->procOptions['exitHTMLparser_db.']) && $this->procOptions['exitHTMLparser_db.']['xhtml_cleaning']) {
1158 $addConfig['xhtml'] = 1;
1159 }
1160 return $this->HTMLcleaner($content, $keepTags, $kUknown, $hSC, $addConfig);
1161 }
1162
1163 /**
1164 * Creates an array of configuration for the HTMLcleaner function based on whether content go TO or FROM the Rich Text Editor ($direction)
1165 * Unless "tagList" is given, the function will cache the configuration for next time processing goes on. (In this class that is the case only if we are processing a bulletlist)
1166 *
1167 * @param string $direction The direction of the content being processed by the output configuration; "db" (content going into the database FROM the rte) or "rte" (content going into the form)
1168 * @param string $tagList Comma list of tags to keep (overriding default which is to keep all + take notice of internal configuration)
1169 * @return array Configuration array
1170 * @see HTMLcleaner_db()
1171 * @todo Define visibility
1172 */
1173 public function getKeepTags($direction = 'rte', $tagList = '') {
1174 if (!is_array($this->getKeepTags_cache[$direction]) || $tagList) {
1175 // Setting up allowed tags:
1176 // If the $tagList input var is set, this will take precedence
1177 if (strcmp($tagList, '')) {
1178 $keepTags = array_flip(\TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $tagList, 1));
1179 } else {
1180 // Default is to get allowed/denied tags from internal array of processing options:
1181 // Construct default list of tags to keep:
1182 $typoScript_list = 'b,i,u,a,img,br,div,center,pre,font,hr,sub,sup,p,strong,em,li,ul,ol,blockquote,strike,span';
1183 $keepTags = array_flip(\TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $typoScript_list . ',' . strtolower($this->procOptions['allowTags']), 1));
1184 // For tags to deny, remove them from $keepTags array:
1185 $denyTags = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->procOptions['denyTags'], 1);
1186 foreach ($denyTags as $dKe) {
1187 unset($keepTags[$dKe]);
1188 }
1189 }
1190 // Based on the direction of content, set further options:
1191 switch ($direction) {
1192 case 'rte':
1193 if (!isset($this->procOptions['transformBoldAndItalicTags']) || $this->procOptions['transformBoldAndItalicTags']) {
1194 // Transform bold/italics tags to strong/em
1195 if (isset($keepTags['b'])) {
1196 $keepTags['b'] = array('remap' => 'STRONG');
1197 }
1198 if (isset($keepTags['i'])) {
1199 $keepTags['i'] = array('remap' => 'EM');
1200 }
1201 }
1202 // Transforming keepTags array so it can be understood by the HTMLcleaner function. This basically converts the format of the array from TypoScript (having .'s) to plain multi-dimensional array.
1203 list($keepTags) = $this->HTMLparserConfig($this->procOptions['HTMLparser_rte.'], $keepTags);
1204 break;
1205 case 'db':
1206 if (!isset($this->procOptions['transformBoldAndItalicTags']) || $this->procOptions['transformBoldAndItalicTags']) {
1207 // Transform strong/em back to bold/italics:
1208 if (isset($keepTags['strong'])) {
1209 $keepTags['strong'] = array('remap' => 'b');
1210 }
1211 if (isset($keepTags['em'])) {
1212 $keepTags['em'] = array('remap' => 'i');
1213 }
1214 }
1215 // Setting up span tags if they are allowed:
1216 if (isset($keepTags['span'])) {
1217 $classes = array_merge(array(''), $this->allowedClasses);
1218 $keepTags['span'] = array(
1219 'allowedAttribs' => 'id,class,style,title,lang,xml:lang,dir',
1220 'fixAttrib' => array(
1221 'class' => array(
1222 'list' => $classes,
1223 'removeIfFalse' => 1
1224 )
1225 ),
1226 'rmTagIfNoAttrib' => 1
1227 );
1228 if (!$this->procOptions['allowedClasses']) {
1229 unset($keepTags['span']['fixAttrib']['class']['list']);
1230 }
1231 }
1232 // Setting up font tags if they are allowed:
1233 if (isset($keepTags['font'])) {
1234 $colors = array_merge(array(''), \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->procOptions['allowedFontColors'], 1));
1235 $keepTags['font'] = array(
1236 'allowedAttribs' => 'face,color,size',
1237 'fixAttrib' => array(
1238 'face' => array(
1239 'removeIfFalse' => 1
1240 ),
1241 'color' => array(
1242 'removeIfFalse' => 1,
1243 'list' => $colors
1244 ),
1245 'size' => array(
1246 'removeIfFalse' => 1
1247 )
1248 ),
1249 'rmTagIfNoAttrib' => 1
1250 );
1251 if (!$this->procOptions['allowedFontColors']) {
1252 unset($keepTags['font']['fixAttrib']['color']['list']);
1253 }
1254 }
1255 // Setting further options, getting them from the processiong options:
1256 $TSc = $this->procOptions['HTMLparser_db.'];
1257 if (!$TSc['globalNesting']) {
1258 $TSc['globalNesting'] = 'b,i,u,a,center,font,sub,sup,strong,em,strike,span';
1259 }
1260 if (!$TSc['noAttrib']) {
1261 $TSc['noAttrib'] = 'b,i,u,br,center,hr,sub,sup,strong,em,li,ul,ol,blockquote,strike';
1262 }
1263 // Transforming the array from TypoScript to regular array:
1264 list($keepTags) = $this->HTMLparserConfig($TSc, $keepTags);
1265 break;
1266 }
1267 // Caching (internally, in object memory) the result unless tagList is set:
1268 if (!$tagList) {
1269 $this->getKeepTags_cache[$direction] = $keepTags;
1270 } else {
1271 return $keepTags;
1272 }
1273 }
1274 // Return result:
1275 return $this->getKeepTags_cache[$direction];
1276 }
1277
1278 /**
1279 * This resolves the $value into parts based on <div></div>-sections and <p>-sections and <br />-tags. These are returned as lines separated by LF.
1280 * This point is to resolve the HTML-code returned from RTE into ordinary lines so it's 'human-readable'
1281 * The function ->setDivTags does the opposite.
1282 * This function processes content to go into the database.
1283 *
1284 * @param string $value Value to process.
1285 * @param integer $count Recursion brake. Decremented on each recursion down to zero. Default is 5 (which equals the allowed nesting levels of p/div tags).
1286 * @param boolean $returnArray If TRUE, an array with the lines is returned, otherwise a string of the processed input value.
1287 * @return string Processed input value.
1288 * @see setDivTags()
1289 * @todo Define visibility
1290 */
1291 public function divideIntoLines($value, $count = 5, $returnArray = FALSE) {
1292 // Internalize font tags (move them from OUTSIDE p/div to inside it that is the case):
1293 if ($this->procOptions['internalizeFontTags']) {
1294 $value = $this->internalizeFontTags($value);
1295 }
1296 // Setting configuration for processing:
1297 $allowTagsOutside = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', strtolower($this->procOptions['allowTagsOutside'] ? 'hr,' . $this->procOptions['allowTagsOutside'] : 'hr,img'), 1);
1298 $remapParagraphTag = strtoupper($this->procOptions['remapParagraphTag']);
1299 $divSplit = $this->splitIntoBlock('div,p', $value, 1);
1300 // Setting the third param to 1 will eliminate false end-tags. Maybe this is a good thing to do...?
1301 if ($this->procOptions['keepPDIVattribs']) {
1302 $keepAttribListArr = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', strtolower($this->procOptions['keepPDIVattribs']), 1);
1303 } else {
1304 $keepAttribListArr = array();
1305 }
1306 // Returns plainly the value if there was no div/p sections in it
1307 if (count($divSplit) <= 1 || $count <= 0) {
1308 // Wrap hr tags with LF's
1309 $newValue = preg_replace('/<(hr)(\\s[^>\\/]*)?[[:space:]]*\\/?>/i', LF . '<$1$2/>' . LF, $value);
1310 $newValue = preg_replace('/' . preg_quote((LF . LF)) . '/i', LF, $newValue);
1311 $newValue = preg_replace('/(^' . preg_quote(LF) . ')|(' . preg_quote(LF) . '$)/i', '', $newValue);
1312 return $newValue;
1313 }
1314 // Traverse the splitted sections:
1315 foreach ($divSplit as $k => $v) {
1316 if ($k % 2) {
1317 // Inside
1318 $v = $this->removeFirstAndLastTag($v);
1319 // Fetching 'sub-lines' - which will explode any further p/div nesting...
1320 $subLines = $this->divideIntoLines($v, $count - 1, 1);
1321 // So, if there happend to be sub-nesting of p/div, this is written directly as the new content of THIS section. (This would be considered 'an error')
1322 if (is_array($subLines)) {
1323
1324 } else {
1325 //... but if NO subsection was found, we process it as a TRUE line without erronous content:
1326 $subLines = array($subLines);
1327 // process break-tags, if configured for. Simply, the breaktags will here be treated like if each was a line of content...
1328 if (!$this->procOptions['dontConvBRtoParagraph']) {
1329 $subLines = preg_split('/<br[[:space:]]*[\\/]?>/i', $v);
1330 }
1331 // Traverse sublines (there is typically one, except if <br/> has been converted to lines as well!)
1332 foreach ($subLines as $sk => $value) {
1333 // Clear up the subline for DB.
1334 $subLines[$sk] = $this->HTMLcleaner_db($subLines[$sk]);
1335 // Get first tag, attributes etc:
1336 $fTag = $this->getFirstTag($divSplit[$k]);
1337 $tagName = strtolower($this->getFirstTagName($divSplit[$k]));
1338 $attribs = $this->get_tag_attributes($fTag);
1339 // Keep attributes (lowercase)
1340 $newAttribs = array();
1341 if (count($keepAttribListArr)) {
1342 foreach ($keepAttribListArr as $keepA) {
1343 if (isset($attribs[0][$keepA])) {
1344 $newAttribs[$keepA] = $attribs[0][$keepA];
1345 }
1346 }
1347 }
1348 // ALIGN attribute:
1349 if (!$this->procOptions['skipAlign'] && strcmp(trim($attribs[0]['align']), '') && strtolower($attribs[0]['align']) != 'left') {
1350 // Set to value, but not 'left'
1351 $newAttribs['align'] = strtolower($attribs[0]['align']);
1352 }
1353 // CLASS attribute:
1354 // Set to whatever value
1355 if (!$this->procOptions['skipClass'] && strcmp(trim($attribs[0]['class']), '')) {
1356 if (!count($this->allowedClasses) || in_array($attribs[0]['class'], $this->allowedClasses)) {
1357 $newAttribs['class'] = $attribs[0]['class'];
1358 } else {
1359 $classes = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(' ', $attribs[0]['class'], TRUE);
1360 $newClasses = array();
1361 foreach ($classes as $class) {
1362 if (in_array($class, $this->allowedClasses)) {
1363 $newClasses[] = $class;
1364 }
1365 }
1366 if (count($newClasses)) {
1367 $newAttribs['class'] = implode(' ', $newClasses);
1368 }
1369 }
1370 }
1371 // Remove any line break char (10 or 13)
1372 $subLines[$sk] = preg_replace('/' . LF . '|' . CR . '/', '', $subLines[$sk]);
1373 // If there are any attributes or if we are supposed to remap the tag, then do so:
1374 if (count($newAttribs) && strcmp($remapParagraphTag, '1')) {
1375 if ($remapParagraphTag == 'P') {
1376 $tagName = 'p';
1377 }
1378 if ($remapParagraphTag == 'DIV') {
1379 $tagName = 'div';
1380 }
1381 $subLines[$sk] = '<' . trim(($tagName . ' ' . $this->compileTagAttribs($newAttribs))) . '>' . $subLines[$sk] . '</' . $tagName . '>';
1382 }
1383 }
1384 }
1385 // Add the processed line(s)
1386 $divSplit[$k] = implode(LF, $subLines);
1387 // If it turns out the line is just blank (containing a &nbsp; possibly) then just make it pure blank.
1388 // But, prevent filtering of lines that are blank in sense above, but whose tags contain attributes.
1389 // Those attributes should have been filtered before; if they are still there they must be considered as possible content.
1390 if (trim(strip_tags($divSplit[$k])) == '&nbsp;' && !preg_match('/\\<(img)(\\s[^>]*)?\\/?>/si', $divSplit[$k]) && !preg_match('/\\<([^>]*)?( align| class| style| id| title| dir| lang| xml:lang)([^>]*)?>/si', trim($divSplit[$k]))) {
1391 $divSplit[$k] = '';
1392 }
1393 } else {
1394 // outside div:
1395 // Remove positions which are outside div/p tags and without content
1396 $divSplit[$k] = trim(strip_tags($divSplit[$k], '<' . implode('><', $allowTagsOutside) . '>'));
1397 // Wrap hr tags with LF's
1398 $divSplit[$k] = preg_replace('/<(hr)(\\s[^>\\/]*)?[[:space:]]*\\/?>/i', LF . '<$1$2/>' . LF, $divSplit[$k]);
1399 $divSplit[$k] = preg_replace('/' . preg_quote((LF . LF)) . '/i', LF, $divSplit[$k]);
1400 $divSplit[$k] = preg_replace('/(^' . preg_quote(LF) . ')|(' . preg_quote(LF) . '$)/i', '', $divSplit[$k]);
1401 if (!strcmp($divSplit[$k], '')) {
1402 unset($divSplit[$k]);
1403 }
1404 }
1405 }
1406 // Return value:
1407 return $returnArray ? $divSplit : implode(LF, $divSplit);
1408 }
1409
1410 /**
1411 * Converts all lines into <div></div>/<p></p>-sections (unless the line is a div-section already)
1412 * For processing of content going FROM database TO RTE.
1413 *
1414 * @param string $value Value to convert
1415 * @param string $dT Tag to wrap with. Either "p" or "div" should it be. Lowercase preferably.
1416 * @return string Processed value.
1417 * @see divideIntoLines()
1418 * @todo Define visibility
1419 */
1420 public function setDivTags($value, $dT = 'p') {
1421 // First, setting configuration for the HTMLcleaner function. This will process each line between the <div>/<p> section on their way to the RTE
1422 $keepTags = $this->getKeepTags('rte');
1423 // Default: remove unknown tags.
1424 $kUknown = $this->procOptions['dontProtectUnknownTags_rte'] ? 0 : 'protect';
1425 // Default: re-convert literals to characters (that is &lt; to <)
1426 $hSC = $this->procOptions['dontHSC_rte'] ? 0 : 1;
1427 $convNBSP = !$this->procOptions['dontConvAmpInNBSP_rte'] ? 1 : 0;
1428 // Divide the content into lines, based on LF:
1429 $parts = explode(LF, $value);
1430 foreach ($parts as $k => $v) {
1431 // Processing of line content:
1432 // If the line is blank, set it to &nbsp;
1433 if (!strcmp(trim($parts[$k]), '')) {
1434 $parts[$k] = '&nbsp;';
1435 } else {
1436 // Clean the line content:
1437 $parts[$k] = $this->HTMLcleaner($parts[$k], $keepTags, $kUknown, $hSC);
1438 if ($convNBSP) {
1439 $parts[$k] = str_replace('&amp;nbsp;', '&nbsp;', $parts[$k]);
1440 }
1441 }
1442 // Wrapping the line in <$dT> if not already wrapped and does not contain an hr tag
1443 if (!preg_match('/<(hr)(\\s[^>\\/]*)?[[:space:]]*\\/?>/i', $parts[$k])) {
1444 $testStr = strtolower(trim($parts[$k]));
1445 if (substr($testStr, 0, 4) != '<div' || substr($testStr, -6) != '</div>') {
1446 if (substr($testStr, 0, 2) != '<p' || substr($testStr, -4) != '</p>') {
1447 // Only set p-tags if there is not already div or p tags:
1448 $parts[$k] = '<' . $dT . '>' . $parts[$k] . '</' . $dT . '>';
1449 }
1450 }
1451 }
1452 }
1453 // Implode result:
1454 return implode(LF, $parts);
1455 }
1456
1457 /**
1458 * This splits the $value in font-tag chunks.
1459 * If there are any <P>/<DIV> sections inside of them, the font-tag is wrapped AROUND the content INSIDE of the P/DIV sections and the outer font-tag is removed.
1460 * This functions seems to be a good choice for pre-processing content if it has been pasted into the RTE from eg. star-office.
1461 * In that case the font-tags are normally on the OUTSIDE of the sections.
1462 * This function is used by eg. divideIntoLines() if the procesing option 'internalizeFontTags' is set.
1463 *
1464 * @param string Input content
1465 * @return string Output content
1466 * @see divideIntoLines()
1467 * @todo Define visibility
1468 */
1469 public function internalizeFontTags($value) {
1470 // Splitting into font tag blocks:
1471 $fontSplit = $this->splitIntoBlock('font', $value);
1472 foreach ($fontSplit as $k => $v) {
1473 // Inside
1474 if ($k % 2) {
1475 // Fint font-tag
1476 $fTag = $this->getFirstTag($v);
1477 $divSplit_sub = $this->splitIntoBlock('div,p', $this->removeFirstAndLastTag($v), 1);
1478 // If there were div/p sections inside the font-tag, do something about it...
1479 if (count($divSplit_sub) > 1) {
1480 // Traverse those sections:
1481 foreach ($divSplit_sub as $k2 => $v2) {
1482 // Inside
1483 if ($k2 % 2) {
1484 // Fint font-tag
1485 $div_p = $this->getFirstTag($v2);
1486 // Fint font-tag
1487 $div_p_tagname = $this->getFirstTagName($v2);
1488 // ... and remove it from original.
1489 $v2 = $this->removeFirstAndLastTag($v2);
1490 $divSplit_sub[$k2] = $div_p . $fTag . $v2 . '</font>' . '</' . $div_p_tagname . '>';
1491 } elseif (trim(strip_tags($v2))) {
1492 $divSplit_sub[$k2] = $fTag . $v2 . '</font>';
1493 }
1494 }
1495 $fontSplit[$k] = implode('', $divSplit_sub);
1496 }
1497 }
1498 }
1499 return implode('', $fontSplit);
1500 }
1501
1502 /**
1503 * Returns SiteURL based on thisScript.
1504 *
1505 * @return string Value of t3lib_div::getIndpEnv('TYPO3_SITE_URL');
1506 * @see t3lib_div::getIndpEnv()
1507 * @todo Define visibility
1508 */
1509 public function siteUrl() {
1510 return \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SITE_URL');
1511 }
1512
1513 /**
1514 * Return the storage folder of RTE image files.
1515 * Default is $GLOBALS['TYPO3_CONF_VARS']['BE']['RTE_imageStorageDir'] unless something else is configured in the types configuration for the RTE.
1516 *
1517 * @return string
1518 * @todo Define visibility
1519 */
1520 public function rteImageStorageDir() {
1521 return $this->rte_p['imgpath'] ? $this->rte_p['imgpath'] : $GLOBALS['TYPO3_CONF_VARS']['BE']['RTE_imageStorageDir'];
1522 }
1523
1524 /**
1525 * Remove all tables from incoming code
1526 * The function is trying to to this is some more or less respectfull way. The approach is to resolve each table cells content and implode it all by <br /> chars. Thus at least the content is preserved in some way.
1527 *
1528 * @param string $value Input value
1529 * @param string $breakChar Break character to use for linebreaks.
1530 * @return string Output value
1531 * @todo Define visibility
1532 */
1533 public function removeTables($value, $breakChar = '<br />') {
1534 // Splitting value into table blocks:
1535 $tableSplit = $this->splitIntoBlock('table', $value);
1536 // Traverse blocks of tables:
1537 foreach ($tableSplit as $k => $v) {
1538 if ($k % 2) {
1539 $tableSplit[$k] = '';
1540 $rowSplit = $this->splitIntoBlock('tr', $v);
1541 foreach ($rowSplit as $k2 => $v2) {
1542 if ($k2 % 2) {
1543 $cellSplit = $this->getAllParts($this->splitIntoBlock('td', $v2), 1, 0);
1544 foreach ($cellSplit as $k3 => $v3) {
1545 $tableSplit[$k] .= $v3 . $breakChar;
1546 }
1547 }
1548 }
1549 }
1550 }
1551 // Implode it all again:
1552 return implode($breakChar, $tableSplit);
1553 }
1554
1555 /**
1556 * Default tag mapping for TS
1557 *
1558 * @param string $code Input code to process
1559 * @param string $direction Direction To databsae (db) or from database to RTE (rte)
1560 * @return string Processed value
1561 * @todo Define visibility
1562 */
1563 public function defaultTStagMapping($code, $direction = 'rte') {
1564 if ($direction == 'db') {
1565 $code = $this->mapTags($code, array(
1566 // Map tags
1567 'strong' => 'b',
1568 'em' => 'i'
1569 ));
1570 }
1571 if ($direction == 'rte') {
1572 $code = $this->mapTags($code, array(
1573 // Map tags
1574 'b' => 'strong',
1575 'i' => 'em'
1576 ));
1577 }
1578 return $code;
1579 }
1580
1581 /**
1582 * Finds width and height from attrib-array
1583 * If the width and height is found in the style-attribute, use that!
1584 *
1585 * @param array $attribArray Array of attributes from tag in which to search. More specifically the content of the key "style" is used to extract "width:xxx / height:xxx" information
1586 * @return array Integer w/h in key 0/1. Zero is returned if not found.
1587 * @todo Define visibility
1588 */
1589 public function getWHFromAttribs($attribArray) {
1590 $style = trim($attribArray['style']);
1591 if ($style) {
1592 $regex = '[[:space:]]*:[[:space:]]*([0-9]*)[[:space:]]*px';
1593 // Width
1594 $reg = array();
1595 preg_match('/width' . $regex . '/i', $style, $reg);
1596 $w = intval($reg[1]);
1597 // Height
1598 preg_match('/height' . $regex . '/i', $style, $reg);
1599 $h = intval($reg[1]);
1600 }
1601 if (!$w) {
1602 $w = $attribArray['width'];
1603 }
1604 if (!$h) {
1605 $h = $attribArray['height'];
1606 }
1607 return array(intval($w), intval($h));
1608 }
1609
1610 /**
1611 * Parse <A>-tag href and return status of email,external,file or page
1612 *
1613 * @param string $url URL to analyse.
1614 * @return array Information in an array about the URL
1615 * @todo Define visibility
1616 */
1617 public function urlInfoForLinkTags($url) {
1618 $info = array();
1619 $url = trim($url);
1620 if (substr(strtolower($url), 0, 7) == 'mailto:') {
1621 $info['url'] = trim(substr($url, 7));
1622 $info['type'] = 'email';
1623 } elseif (strpos($url, '?file:') !== FALSE) {
1624 $info['type'] = 'file';
1625 $info['url'] = rawurldecode(substr($url, strpos($url, '?file:') + 1));
1626 } else {
1627 $curURL = $this->siteUrl();
1628 $urlLength = strlen($url);
1629 for ($a = 0; $a < $urlLength; $a++) {
1630 if ($url[$a] != $curURL[$a]) {
1631 break;
1632 }
1633 }
1634 $info['relScriptPath'] = substr($curURL, $a);
1635 $info['relUrl'] = substr($url, $a);
1636 $info['url'] = $url;
1637 $info['type'] = 'ext';
1638 $siteUrl_parts = parse_url($url);
1639 $curUrl_parts = parse_url($curURL);
1640 // Hosts should match
1641 if ($siteUrl_parts['host'] == $curUrl_parts['host'] && (!$info['relScriptPath'] || defined('TYPO3_mainDir') && substr($info['relScriptPath'], 0, strlen(TYPO3_mainDir)) == TYPO3_mainDir)) {
1642 // If the script path seems to match or is empty (FE-EDIT)
1643 // New processing order 100502
1644 $uP = parse_url($info['relUrl']);
1645 if (!strcmp(('#' . $siteUrl_parts['fragment']), $info['relUrl'])) {
1646 $info['url'] = $info['relUrl'];
1647 $info['type'] = 'anchor';
1648 } elseif (!trim($uP['path']) || !strcmp($uP['path'], 'index.php')) {
1649 // URL is a page (id parameter)
1650 $pp = preg_split('/^id=/', $uP['query']);
1651 $pp[1] = preg_replace('/&id=[^&]*/', '', $pp[1]);
1652 $parameters = explode('&', $pp[1]);
1653 $id = array_shift($parameters);
1654 if ($id) {
1655 $info['pageid'] = $id;
1656 $info['cElement'] = $uP['fragment'];
1657 $info['url'] = $id . ($info['cElement'] ? '#' . $info['cElement'] : '');
1658 $info['type'] = 'page';
1659 $info['query'] = $parameters[0] ? '&' . implode('&', $parameters) : '';
1660 }
1661 } else {
1662 $info['url'] = $info['relUrl'];
1663 $info['type'] = 'file';
1664 }
1665 } else {
1666 unset($info['relScriptPath']);
1667 unset($info['relUrl']);
1668 }
1669 }
1670 return $info;
1671 }
1672
1673 /**
1674 * Converting <A>-tags to absolute URLs (+ setting rtekeep attribute)
1675 *
1676 * @param string $value Content input
1677 * @param boolean $dontSetRTEKEEP If TRUE, then the "rtekeep" attribute will not be set.
1678 * @return string Content output
1679 * @todo Define visibility
1680 */
1681 public function TS_AtagToAbs($value, $dontSetRTEKEEP = FALSE) {
1682 $blockSplit = $this->splitIntoBlock('A', $value);
1683 foreach ($blockSplit as $k => $v) {
1684 // Block
1685 if ($k % 2) {
1686 $attribArray = $this->get_tag_attributes_classic($this->getFirstTag($v), 1);
1687 // Checking if there is a scheme, and if not, prepend the current url.
1688 // ONLY do this if href has content - the <a> tag COULD be an anchor and if so, it should be preserved...
1689 if (strlen($attribArray['href'])) {
1690 $uP = parse_url(strtolower($attribArray['href']));
1691 if (!$uP['scheme']) {
1692 $attribArray['href'] = $this->siteUrl() . substr($attribArray['href'], strlen($this->relBackPath));
1693 } elseif ($uP['scheme'] != 'mailto') {
1694 $attribArray['data-htmlarea-external'] = 1;
1695 }
1696 } else {
1697 $attribArray['rtekeep'] = 1;
1698 }
1699 if (!$dontSetRTEKEEP) {
1700 $attribArray['rtekeep'] = 1;
1701 }
1702 $bTag = '<a ' . \TYPO3\CMS\Core\Utility\GeneralUtility::implodeAttributes($attribArray, 1) . '>';
1703 $eTag = '</a>';
1704 $blockSplit[$k] = $bTag . $this->TS_AtagToAbs($this->removeFirstAndLastTag($blockSplit[$k])) . $eTag;
1705 }
1706 }
1707 return implode('', $blockSplit);
1708 }
1709
1710 }
1711
1712
1713 ?>