[CLEANUP] Replace strlen() with === for zero length check
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Database / SoftReferenceIndex.php
1 <?php
2 namespace TYPO3\CMS\Core\Database;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2003-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 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28
29 /**
30 * Soft Reference processing class
31 * "Soft References" are references to database elements, files, email addresses, URls etc.
32 * which are found in-text in content. The <link [page_id]> tag from typical bodytext fields
33 * are an example of this.
34 * This class contains generic parsers for the most well-known types
35 * which are default for most TYPO3 installations. Soft References can also be userdefined.
36 * The Soft Reference parsers are used by the system to find these references and process them accordingly in import/export actions and copy operations.
37 *
38 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
39 */
40 /**
41 * Example of usage
42 * Soft References:
43 * if ($conf['softref'] && strlen($value)) { // Check if a TCA configured field has softreferences defined (see TYPO3 Core API document)
44 * $softRefs = \TYPO3\CMS\Backend\Utility\BackendUtility::explodeSoftRefParserList($conf['softref']); // Explode the list of softreferences/parameters
45 * foreach($softRefs as $spKey => $spParams) { // Traverse soft references
46 * $softRefObj = &\TYPO3\CMS\Backend\Utility\BackendUtility::softRefParserObj($spKey); // create / get object
47 * if (is_object($softRefObj)) { // If there was an object returned...:
48 * $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams); // Do processing
49 *
50 * Result Array:
51 * The Result array should contain two keys: "content" and "elements".
52 * "content" is a string containing the input content but possibly with tokens inside.
53 * Tokens are strings like {softref:[tokenID]} which is a placeholder for a value extracted by a softref parser
54 * For each token there MUST be an entry in the "elements" key which has a "subst" key defining the tokenID and the tokenValue. See below.
55 * "elements" is an array where the keys are insignificant, but the values are arrays with these keys:
56 * "matchString" => The value of the match. This is only for informational purposes to show what was found.
57 * "error" => An error message can be set here, like "file not found" etc.
58 * "subst" => array( // If this array is found there MUST be a token in the output content as well!
59 * "tokenID" => The tokenID string corresponding to the token in output content, {softref:[tokenID]}. This is typically an md5 hash of a string defining uniquely the position of the element.
60 * "tokenValue" => The value that the token substitutes in the text. Basically, if this value is inserted instead of the token the content should match what was inputted originally.
61 * "type" => file / db / string = the type of substitution. "file" means it is a relative file [automatically mapped], "db" means a database record reference [automatically mapped], "string" means it is manually modified string content (eg. an email address)
62 * "relFileName" => (for "file" type): Relative filename. May not necessarily exist. This could be noticed in the error key.
63 * "recordRef" => (for "db" type) : Reference to DB record on the form [table]:[uid]. May not necessarily exist.
64 * "title" => Title of element (for backend information)
65 * "description" => Description of element (for backend information)
66 * )
67 */
68 /**
69 * Class for processing of the default soft reference types for CMS:
70 *
71 * - 'substitute' : A full field value targeted for manual substitution (for import /export features)
72 * - 'notify' : Just report if a value is found, nothing more.
73 * - 'images' : HTML <img> tags for RTE images / images from fileadmin/
74 * - 'typolink' : references to page id or file, possibly with anchor/target, possibly commaseparated list.
75 * - 'typolink_tag' : As typolink, but searching for <link> tag to encapsulate it.
76 * - 'TSconfig' processing (filerefs? Domains? what do we know...)
77 * - 'TStemplate' : freetext references to "fileadmin/" files.
78 * - 'email' : Email highlight
79 * - 'url' : URL highlights (with a scheme)
80 *
81 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
82 */
83 class SoftReferenceIndex {
84
85 // External configuration
86 /**
87 * @todo Define visibility
88 */
89 public $fileAdminDir = '';
90
91 // Internal:
92 /**
93 * @todo Define visibility
94 */
95 public $tokenID_basePrefix = '';
96
97 /**
98 * Class construct to set global variable
99 *
100 */
101 public function __construct() {
102 $this->fileAdminDir = !empty($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir']) ? rtrim($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') : 'fileadmin';
103 }
104
105 /**
106 * Main function through which all processing happens
107 *
108 * @param string $table Database table name
109 * @param string $field Field name for which processing occurs
110 * @param integer $uid UID of the record
111 * @param string $content The content/value of the field
112 * @param string $spKey The softlink parser key. This is only interesting if more than one parser is grouped in the same class. That is the case with this parser.
113 * @param array $spParams Parameters of the softlink parser. Basically this is the content inside optional []-brackets after the softref keys. Parameters are exploded by ";
114 * @param string $structurePath If running from inside a FlexForm structure, this is the path of the tag.
115 * @return array Result array on positive matches, see description above. Otherwise FALSE
116 * @todo Define visibility
117 */
118 public function findRef($table, $field, $uid, $content, $spKey, $spParams, $structurePath = '') {
119 $retVal = FALSE;
120 $this->tokenID_basePrefix = $table . ':' . $uid . ':' . $field . ':' . $structurePath . ':' . $spKey;
121 switch ($spKey) {
122 case 'notify':
123 // Simple notification
124 $resultArray = array(
125 'elements' => array(
126 array(
127 'matchString' => $content
128 )
129 )
130 );
131 $retVal = $resultArray;
132 break;
133 case 'substitute':
134 $tokenID = $this->makeTokenID();
135 $resultArray = array(
136 'content' => '{softref:' . $tokenID . '}',
137 'elements' => array(
138 array(
139 'matchString' => $content,
140 'subst' => array(
141 'type' => 'string',
142 'tokenID' => $tokenID,
143 'tokenValue' => $content
144 )
145 )
146 )
147 );
148 $retVal = $resultArray;
149 break;
150 case 'images':
151 $retVal = $this->findRef_images($content, $spParams);
152 break;
153 case 'typolink':
154 $retVal = $this->findRef_typolink($content, $spParams);
155 break;
156 case 'typolink_tag':
157 $retVal = $this->findRef_typolink_tag($content, $spParams);
158 break;
159 case 'ext_fileref':
160 $retVal = $this->findRef_extension_fileref($content, $spParams);
161 break;
162 case 'TStemplate':
163 $retVal = $this->findRef_TStemplate($content, $spParams);
164 break;
165 case 'TSconfig':
166 $retVal = $this->findRef_TSconfig($content, $spParams);
167 break;
168 case 'email':
169 $retVal = $this->findRef_email($content, $spParams);
170 break;
171 case 'url':
172 $retVal = $this->findRef_url($content, $spParams);
173 break;
174 default:
175 $retVal = FALSE;
176 }
177 return $retVal;
178 }
179
180 /**
181 * Finding image tags in the content.
182 * All images that are not from external URLs will be returned with an info text
183 * Will only return files in fileadmin/ and files in uploads/ folders which are prefixed with "RTEmagic[C|P]_" for substitution
184 * Any "clear.gif" images are ignored.
185 *
186 * @param string $content The input content to analyse
187 * @param array $spParams Parameters set for the softref parser key in TCA/columns
188 * @return array Result array on positive matches, see description above. Otherwise FALSE
189 * @todo Define visibility
190 */
191 public function findRef_images($content, $spParams) {
192 // Start HTML parser and split content by image tag:
193 $htmlParser = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Html\\HtmlParser');
194 $splitContent = $htmlParser->splitTags('img', $content);
195 $elements = array();
196 // Traverse splitted parts:
197 foreach ($splitContent as $k => $v) {
198 if ($k % 2) {
199 // Get file reference:
200 $attribs = $htmlParser->get_tag_attributes($v);
201 $srcRef = htmlspecialchars_decode($attribs[0]['src']);
202 $pI = pathinfo($srcRef);
203 // If it looks like a local image, continue. Otherwise ignore it.
204 $absPath = GeneralUtility::getFileAbsFileName(PATH_site . $srcRef);
205 if (!$pI['scheme'] && !$pI['query'] && $absPath && $srcRef !== 'clear.gif') {
206 // Initialize the element entry with info text here:
207 $tokenID = $this->makeTokenID($k);
208 $elements[$k] = array();
209 $elements[$k]['matchString'] = $v;
210 // If the image seems to be from fileadmin/ folder or an RTE image, then proceed to set up substitution token:
211 if (GeneralUtility::isFirstPartOfStr($srcRef, $this->fileAdminDir . '/') || GeneralUtility::isFirstPartOfStr($srcRef, 'uploads/') && preg_match('/^RTEmagicC_/', basename($srcRef))) {
212 // Token and substitute value:
213 // Make sure the value we work on is found and will get substituted in the content (Very important that the src-value is not DeHSC'ed)
214 if (strstr($splitContent[$k], $attribs[0]['src'])) {
215 // Substitute value with token (this is not be an exact method if the value is in there twice, but we assume it will not)
216 $splitContent[$k] = str_replace($attribs[0]['src'], '{softref:' . $tokenID . '}', $splitContent[$k]);
217 $elements[$k]['subst'] = array(
218 'type' => 'file',
219 'relFileName' => $srcRef,
220 'tokenID' => $tokenID,
221 'tokenValue' => $attribs[0]['src']
222 );
223 // Finally, notice if the file does not exist.
224 if (!@is_file($absPath)) {
225 $elements[$k]['error'] = 'File does not exist!';
226 }
227 } else {
228 $elements[$k]['error'] = 'Could not substitute image source with token!';
229 }
230 }
231 }
232 }
233 }
234 // Return result:
235 if (count($elements)) {
236 $resultArray = array(
237 'content' => implode('', $splitContent),
238 'elements' => $elements
239 );
240 return $resultArray;
241 }
242 }
243
244 /**
245 * TypoLink value processing.
246 * Will process input value as a TypoLink value.
247 *
248 * @param string $content The input content to analyse
249 * @param array $spParams Parameters set for the softref parser key in TCA/columns. value "linkList" will split the string by comma before processing.
250 * @return array Result array on positive matches, see description above. Otherwise FALSE
251 * @see tslib_content::typolink(), getTypoLinkParts()
252 * @todo Define visibility
253 */
254 public function findRef_typolink($content, $spParams) {
255 // First, split the input string by a comma if the "linkList" parameter is set.
256 // An example: the link field for images in content elements of type "textpic" or "image". This field CAN be configured to define a link per image, separated by comma.
257 if (is_array($spParams) && in_array('linkList', $spParams)) {
258 // Preserving whitespace on purpose.
259 $linkElement = explode(',', $content);
260 } else {
261 // If only one element, just set in this array to make it easy below.
262 $linkElement = array($content);
263 }
264 // Traverse the links now:
265 $elements = array();
266 foreach ($linkElement as $k => $typolinkValue) {
267 $tLP = $this->getTypoLinkParts($typolinkValue);
268 $linkElement[$k] = $this->setTypoLinkPartsElement($tLP, $elements, $typolinkValue, $k);
269 }
270 // Return output:
271 if (count($elements)) {
272 $resultArray = array(
273 'content' => implode(',', $linkElement),
274 'elements' => $elements
275 );
276 return $resultArray;
277 }
278 }
279
280 /**
281 * TypoLink tag processing.
282 * Will search for <link ...> tags in the content string and process any found.
283 *
284 * @param string $content The input content to analyse
285 * @param array $spParams Parameters set for the softref parser key in TCA/columns
286 * @return array Result array on positive matches, see description above. Otherwise FALSE
287 * @see tslib_content::typolink(), getTypoLinkParts()
288 * @todo Define visibility
289 */
290 public function findRef_typolink_tag($content, $spParams) {
291 // Parse string for special TYPO3 <link> tag:
292 $htmlParser = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Html\\HtmlParser');
293 $linkTags = $htmlParser->splitTags('link', $content);
294 // Traverse result:
295 $elements = array();
296 foreach ($linkTags as $k => $foundValue) {
297 if ($k % 2) {
298 $typolinkValue = preg_replace('/<LINK[[:space:]]+/i', '', substr($foundValue, 0, -1));
299 $tLP = $this->getTypoLinkParts($typolinkValue);
300 $linkTags[$k] = '<LINK ' . $this->setTypoLinkPartsElement($tLP, $elements, $typolinkValue, $k) . '>';
301 }
302 }
303 // Return output:
304 if (count($elements)) {
305 $resultArray = array(
306 'content' => implode('', $linkTags),
307 'elements' => $elements
308 );
309 return $resultArray;
310 }
311 }
312
313 /**
314 * Processing the content expected from a TypoScript template
315 * This content includes references to files in fileadmin/ folders and file references in HTML tags like <img src="">, <a href=""> and <form action="">
316 *
317 * @param string $content The input content to analyse
318 * @param array $spParams Parameters set for the softref parser key in TCA/columns
319 * @return array Result array on positive matches, see description above. Otherwise FALSE
320 * @todo Define visibility
321 */
322 public function findRef_TStemplate($content, $spParams) {
323 $elements = array();
324 // First, try to find images and links:
325 $htmlParser = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Html\\HtmlParser');
326 $splitContent = $htmlParser->splitTags('img,a,form', $content);
327 // Traverse splitted parts:
328 foreach ($splitContent as $k => $v) {
329 if ($k % 2) {
330 $attribs = $htmlParser->get_tag_attributes($v);
331 $attributeName = '';
332 switch ($htmlParser->getFirstTagName($v)) {
333 case 'img':
334 $attributeName = 'src';
335 break;
336 case 'a':
337 $attributeName = 'href';
338 break;
339 case 'form':
340 $attributeName = 'action';
341 break;
342 }
343 // Get file reference:
344 if (isset($attribs[0][$attributeName])) {
345 $srcRef = htmlspecialchars_decode($attribs[0][$attributeName]);
346 // Set entry:
347 $tokenID = $this->makeTokenID($k);
348 $elements[$k] = array();
349 $elements[$k]['matchString'] = $v;
350 // OK, if it looks like a local file from fileadmin/, include it:
351 $pI = pathinfo($srcRef);
352 $absPath = GeneralUtility::getFileAbsFileName(PATH_site . $srcRef);
353 if (GeneralUtility::isFirstPartOfStr($srcRef, $this->fileAdminDir . '/') && !$pI['query'] && $absPath) {
354 // Token and substitute value:
355 // Very important that the src-value is not DeHSC'ed
356 if (strstr($splitContent[$k], $attribs[0][$attributeName])) {
357 $splitContent[$k] = str_replace($attribs[0][$attributeName], '{softref:' . $tokenID . '}', $splitContent[$k]);
358 $elements[$k]['subst'] = array(
359 'type' => 'file',
360 'relFileName' => $srcRef,
361 'tokenID' => $tokenID,
362 'tokenValue' => $attribs[0][$attributeName]
363 );
364 if (!@is_file($absPath)) {
365 $elements[$k]['error'] = 'File does not exist!';
366 }
367 } else {
368 $elements[$k]['error'] = 'Could not substitute attribute (' . $attributeName . ') value with token!';
369 }
370 }
371 }
372 }
373 }
374 $content = implode('', $splitContent);
375 // Process free fileadmin/ references as well:
376 $content = $this->fileadminReferences($content, $elements);
377 // Return output:
378 if (count($elements)) {
379 $resultArray = array(
380 'content' => $content,
381 'elements' => $elements
382 );
383 return $resultArray;
384 }
385 }
386
387 /**
388 * Processes possible references inside of Page and User TSconfig fields.
389 * Currently this only includes file references to fileadmin/ but in fact there are currently no properties that supports such references.
390 *
391 * @param string $content The input content to analyse
392 * @param array $spParams Parameters set for the softref parser key in TCA/columns
393 * @return array Result array on positive matches, see description above. Otherwise FALSE
394 * @todo Define visibility
395 */
396 public function findRef_TSconfig($content, $spParams) {
397 $elements = array();
398 // Process free fileadmin/ references from TSconfig
399 $content = $this->fileadminReferences($content, $elements);
400 // Return output:
401 if (count($elements)) {
402 $resultArray = array(
403 'content' => $content,
404 'elements' => $elements
405 );
406 return $resultArray;
407 }
408 }
409
410 /**
411 * Finding email addresses in content and making them substitutable.
412 *
413 * @param string $content The input content to analyse
414 * @param array $spParams Parameters set for the softref parser key in TCA/columns
415 * @return array Result array on positive matches, see description above. Otherwise FALSE
416 * @todo Define visibility
417 */
418 public function findRef_email($content, $spParams) {
419 $resultArray = array();
420 // Email:
421 $parts = preg_split('/([^[:alnum:]]+)([A-Za-z0-9\\._-]+[@][A-Za-z0-9\\._-]+[\\.].[A-Za-z0-9]+)/', ' ' . $content . ' ', 10000, PREG_SPLIT_DELIM_CAPTURE);
422 foreach ($parts as $idx => $value) {
423 if ($idx % 3 == 2) {
424 $tokenID = $this->makeTokenID($idx);
425 $elements[$idx] = array();
426 $elements[$idx]['matchString'] = $value;
427 if (is_array($spParams) && in_array('subst', $spParams)) {
428 $parts[$idx] = '{softref:' . $tokenID . '}';
429 $elements[$idx]['subst'] = array(
430 'type' => 'string',
431 'tokenID' => $tokenID,
432 'tokenValue' => $value
433 );
434 }
435 }
436 }
437 // Return output:
438 if (count($elements)) {
439 $resultArray = array(
440 'content' => substr(implode('', $parts), 1, -1),
441 'elements' => $elements
442 );
443 return $resultArray;
444 }
445 }
446
447 /**
448 * Finding URLs in content
449 *
450 * @param string $content The input content to analyse
451 * @param array $spParams Parameters set for the softref parser key in TCA/columns
452 * @return array Result array on positive matches, see description above. Otherwise FALSE
453 * @todo Define visibility
454 */
455 public function findRef_url($content, $spParams) {
456 $resultArray = array();
457 // Fileadmin files:
458 $parts = preg_split('/([^[:alnum:]"\']+)((http|ftp):\\/\\/[^[:space:]"\'<>]*)([[:space:]])/', ' ' . $content . ' ', 10000, PREG_SPLIT_DELIM_CAPTURE);
459 foreach ($parts as $idx => $value) {
460 if ($idx % 5 == 3) {
461 unset($parts[$idx]);
462 }
463 if ($idx % 5 == 2) {
464 $tokenID = $this->makeTokenID($idx);
465 $elements[$idx] = array();
466 $elements[$idx]['matchString'] = $value;
467 if (is_array($spParams) && in_array('subst', $spParams)) {
468 $parts[$idx] = '{softref:' . $tokenID . '}';
469 $elements[$idx]['subst'] = array(
470 'type' => 'string',
471 'tokenID' => $tokenID,
472 'tokenValue' => $value
473 );
474 }
475 }
476 }
477 // Return output:
478 if (count($elements)) {
479 $resultArray = array(
480 'content' => substr(implode('', $parts), 1, -1),
481 'elements' => $elements
482 );
483 return $resultArray;
484 }
485 }
486
487 /**
488 * Finding reference to files from extensions in content, but only to notify about their existence. No substitution
489 *
490 * @param string $content The input content to analyse
491 * @param array $spParams Parameters set for the softref parser key in TCA/columns
492 * @return array Result array on positive matches, see description above. Otherwise FALSE
493 * @todo Define visibility
494 */
495 public function findRef_extension_fileref($content, $spParams) {
496 $resultArray = array();
497 // Fileadmin files:
498 $parts = preg_split('/([^[:alnum:]"\']+)(EXT:[[:alnum:]_]+\\/[^[:space:]"\',]*)/', ' ' . $content . ' ', 10000, PREG_SPLIT_DELIM_CAPTURE);
499 foreach ($parts as $idx => $value) {
500 if ($idx % 3 == 2) {
501 $tokenID = $this->makeTokenID($idx);
502 $elements[$idx] = array();
503 $elements[$idx]['matchString'] = $value;
504 }
505 }
506 // Return output:
507 if (count($elements)) {
508 $resultArray = array(
509 'content' => substr(implode('', $parts), 1, -1),
510 'elements' => $elements
511 );
512 return $resultArray;
513 }
514 }
515
516 /*************************
517 *
518 * Helper functions
519 *
520 *************************/
521 /**
522 * Searches the content for a reference to a file in "fileadmin/".
523 * When a match is found it will get substituted with a token.
524 *
525 * @param string $content Input content to analyse
526 * @param array $elements Element array to be modified with new entries. Passed by reference.
527 * @return string Output content, possibly with tokens inserted.
528 * @todo Define visibility
529 */
530 public function fileadminReferences($content, &$elements) {
531 // Fileadmin files are found
532 $parts = preg_split('/([^[:alnum:]]+)(' . preg_quote($this->fileAdminDir, '/') . '\\/[^[:space:]"\'<>]*)/', ' ' . $content . ' ', 10000, PREG_SPLIT_DELIM_CAPTURE);
533 // Traverse files:
534 foreach ($parts as $idx => $value) {
535 if ($idx % 3 == 2) {
536 // when file is found, set up an entry for the element:
537 $tokenID = $this->makeTokenID('fileadminReferences:' . $idx);
538 $elements['fileadminReferences.' . $idx] = array();
539 $elements['fileadminReferences.' . $idx]['matchString'] = $value;
540 $elements['fileadminReferences.' . $idx]['subst'] = array(
541 'type' => 'file',
542 'relFileName' => $value,
543 'tokenID' => $tokenID,
544 'tokenValue' => $value
545 );
546 $parts[$idx] = '{softref:' . $tokenID . '}';
547 // Check if the file actually exists:
548 $absPath = GeneralUtility::getFileAbsFileName(PATH_site . $value);
549 if (!@is_file($absPath)) {
550 $elements['fileadminReferences.' . $idx]['error'] = 'File does not exist!';
551 }
552 }
553 }
554 // Implode the content again, removing prefixed and trailing white space:
555 return substr(implode('', $parts), 1, -1);
556 }
557
558 /**
559 * Analyse content as a TypoLink value and return an array with properties.
560 * TypoLinks format is: <link [typolink] [browser target] [css class]>. See tslib_content::typolink()
561 * The syntax of the [typolink] part is: [typolink] = [page id or alias][,[type value]][#[anchor, if integer = tt_content uid]]
562 * The extraction is based on how tslib_content::typolink() behaves.
563 *
564 * @param string $typolinkValue TypoLink value.
565 * @return array Array with the properties of the input link specified. The key "LINK_TYPE" will reveal the type. If that is blank it could not be determined.
566 * @see tslib_content::typolink(), setTypoLinkPartsElement()
567 * @todo Define visibility
568 */
569 public function getTypoLinkParts($typolinkValue) {
570 $finalTagParts = array();
571 // Split by space into link / target / class
572 list($link_param, $browserTarget, $cssClass) = GeneralUtility::trimExplode(' ', $typolinkValue, TRUE);
573 if ($browserTarget !== '') {
574 $finalTagParts['target'] = $browserTarget;
575 }
576 if ($cssClass !== '') {
577 $finalTagParts['class'] = $cssClass;
578 }
579 // Parse URL:
580 $pU = @parse_url($link_param);
581 // Detecting the kind of reference:
582 if (strstr($link_param, '@') && !$pU['scheme']) {
583 // If it's a mail address:
584 $link_param = preg_replace('/^mailto:/i', '', $link_param);
585 $finalTagParts['LINK_TYPE'] = 'mailto';
586 $finalTagParts['url'] = trim($link_param);
587 } else {
588 // Check for FAL link-handler keyword
589 list ($linkHandlerKeyword, $linkHandlerValue) = explode(':', trim($link_param), 2);
590 if ($linkHandlerKeyword === 'file') {
591 $finalTagParts['LINK_TYPE'] = 'file';
592 $finalTagParts['identifier'] = trim($link_param);
593 } else {
594 $isLocalFile = 0;
595 $fileChar = (int)strpos($link_param, '/');
596 $urlChar = (int)strpos($link_param, '.');
597
598 // Detects if a file is found in site-root and if so it will be treated like a normal file.
599 list($rootFileDat) = explode('?', rawurldecode($link_param));
600 $containsSlash = strstr($rootFileDat, '/');
601 $rFD_fI = pathinfo($rootFileDat);
602 if (trim($rootFileDat) && !$containsSlash && (@is_file(PATH_site . $rootFileDat) || GeneralUtility::inList('php,html,htm', strtolower($rFD_fI['extension'])))) {
603 $isLocalFile = 1;
604 } elseif ($containsSlash) {
605 // Adding this so realurl directories are linked right (non-existing).
606 $isLocalFile = 2;
607 }
608 if ($pU['scheme'] || ($isLocalFile != 1 && $urlChar && (!$containsSlash || $urlChar < $fileChar))) { // url (external): If doubleSlash or if a '.' comes before a '/'.
609 $finalTagParts['LINK_TYPE'] = 'url';
610 $finalTagParts['url'] = $link_param;
611 } elseif ($containsSlash || $isLocalFile) { // file (internal)
612 $splitLinkParam = explode('?', $link_param);
613 if (file_exists(rawurldecode($splitLinkParam[0])) || $isLocalFile) {
614 $finalTagParts['LINK_TYPE'] = 'file';
615 $finalTagParts['filepath'] = rawurldecode($splitLinkParam[0]);
616 $finalTagParts['query'] = $splitLinkParam[1];
617 }
618 } else {
619 // integer or alias (alias is without slashes or periods or commas, that is
620 // 'nospace,alphanum_x,lower,unique' according to definition in $GLOBALS['TCA']!)
621 $finalTagParts['LINK_TYPE'] = 'page';
622
623 $link_params_parts = explode('#', $link_param);
624 // Link-data del
625 $link_param = trim($link_params_parts[0]);
626
627 $linkAnchor = isset($link_params_parts[1]) ? trim($link_params_parts[1]) : '';
628 if ($linkAnchor !== '') {
629 $finalTagParts['anchor'] = $linkAnchor;
630 }
631
632 // Splitting the parameter by ',' and if the array counts more than 1 element it's a id/type/? pair
633 $pairParts = GeneralUtility::trimExplode(',', $link_param);
634 if (count($pairParts) > 1) {
635 $link_param = $pairParts[0];
636 $finalTagParts['type'] = $pairParts[1]; // Overruling 'type'
637 }
638
639 // Checking if the id-parameter is an alias.
640 if ((string)$link_param !== '') {
641 if (!\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($link_param)) {
642 $finalTagParts['alias'] = $link_param;
643 $link_param = $this->getPageIdFromAlias($link_param);
644 }
645
646 $finalTagParts['page_id'] = (int)$link_param;
647 }
648 }
649 }
650 }
651 return $finalTagParts;
652 }
653
654 /**
655 * Recompile a TypoLink value from the array of properties made with getTypoLinkParts() into an elements array
656 *
657 * @param array $tLP TypoLink properties
658 * @param array $elements Array of elements to be modified with substitution / information entries.
659 * @param string $content The content to process.
660 * @param integer $idx Index value of the found element - user to make unique but stable tokenID
661 * @return string The input content, possibly containing tokens now according to the added substitution entries in $elements
662 * @see getTypoLinkParts()
663 * @todo Define visibility
664 */
665 public function setTypoLinkPartsElement($tLP, &$elements, $content, $idx) {
666 // Initialize, set basic values. In any case a link will be shown
667 $tokenID = $this->makeTokenID('setTypoLinkPartsElement:' . $idx);
668 $elements[$tokenID . ':' . $idx] = array();
669 $elements[$tokenID . ':' . $idx]['matchString'] = $content;
670 // Based on link type, maybe do more:
671 switch ((string) $tLP['LINK_TYPE']) {
672 case 'mailto':
673
674 case 'url':
675 // Mail addresses and URLs can be substituted manually:
676 $elements[$tokenID . ':' . $idx]['subst'] = array(
677 'type' => 'string',
678 'tokenID' => $tokenID,
679 'tokenValue' => $tLP['url']
680 );
681 // Output content will be the token instead:
682 $content = '{softref:' . $tokenID . '}';
683 break;
684 case 'file':
685 // Process files referenced by their FAL uid
686 if ($tLP['identifier']) {
687 list ($linkHandlerKeyword, $linkHandlerValue) = explode(':', trim($tLP['identifier']), 2);
688 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($linkHandlerValue)) {
689 // Token and substitute value
690 $elements[$tokenID . ':' . $idx]['subst'] = array(
691 'type' => 'db',
692 'recordRef' => 'sys_file:' . $linkHandlerValue,
693 'tokenID' => $tokenID,
694 'tokenValue' => $tLP['identifier'],
695 );
696 // Output content will be the token instead:
697 $content = '{softref:' . $tokenID . '}';
698 } else {
699 // This is a link to a folder...
700 return $content;
701 }
702
703 // Process files found in fileadmin directory:
704 } elseif (!$tLP['query']) {
705 // We will not process files which has a query added to it. That will look like a script we don't want to move.
706 // File must be inside fileadmin/
707 if (GeneralUtility::isFirstPartOfStr($tLP['filepath'], $this->fileAdminDir . '/')) {
708 // Set up the basic token and token value for the relative file:
709 $elements[$tokenID . ':' . $idx]['subst'] = array(
710 'type' => 'file',
711 'relFileName' => $tLP['filepath'],
712 'tokenID' => $tokenID,
713 'tokenValue' => $tLP['filepath']
714 );
715 // Depending on whether the file exists or not we will set the
716 $absPath = GeneralUtility::getFileAbsFileName(PATH_site . $tLP['filepath']);
717 if (!@is_file($absPath)) {
718 $elements[$tokenID . ':' . $idx]['error'] = 'File does not exist!';
719 }
720 // Output content will be the token instead
721 $content = '{softref:' . $tokenID . '}';
722 } else {
723 return $content;
724 }
725 } else {
726 return $content;
727 }
728 break;
729 case 'page':
730 // Rebuild page reference typolink part:
731 $content = '';
732 // Set page id:
733 if ($tLP['page_id']) {
734 $content .= '{softref:' . $tokenID . '}';
735 $elements[$tokenID . ':' . $idx]['subst'] = array(
736 'type' => 'db',
737 'recordRef' => 'pages:' . $tLP['page_id'],
738 'tokenID' => $tokenID,
739 'tokenValue' => $tLP['alias'] ? $tLP['alias'] : $tLP['page_id']
740 );
741 }
742 // Add type if applicable
743 if ((string)$tLP['type'] !== '') {
744 $content .= ',' . $tLP['type'];
745 }
746 // Add anchor if applicable
747 if ((string)$tLP['anchor'] !== '') {
748 // Anchor is assumed to point to a content elements:
749 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($tLP['anchor'])) {
750 // Initialize a new entry because we have a new relation:
751 $newTokenID = $this->makeTokenID('setTypoLinkPartsElement:anchor:' . $idx);
752 $elements[$newTokenID . ':' . $idx] = array();
753 $elements[$newTokenID . ':' . $idx]['matchString'] = 'Anchor Content Element: ' . $tLP['anchor'];
754 $content .= '#{softref:' . $newTokenID . '}';
755 $elements[$newTokenID . ':' . $idx]['subst'] = array(
756 'type' => 'db',
757 'recordRef' => 'tt_content:' . $tLP['anchor'],
758 'tokenID' => $newTokenID,
759 'tokenValue' => $tLP['anchor']
760 );
761 } else {
762 // Anchor is a hardcoded string
763 $content .= '#' . $tLP['type'];
764 }
765 }
766 break;
767 default:
768 $elements[$tokenID . ':' . $idx]['error'] = 'Couldn\\t decide typolink mode.';
769 return $content;
770 }
771 // Finally, for all entries that was rebuild with tokens, add target and class in the end:
772 if ($content !== '' && $tLP['target'] !== '') {
773 $content .= ' ' . $tLP['target'];
774 if ($tLP['class'] !== '') {
775 $content .= ' ' . $tLP['class'];
776 }
777 }
778 // Return rebuilt typolink value:
779 return $content;
780 }
781
782 /**
783 * Look up and return page uid for alias
784 *
785 * @param integer $link_param Page alias string value
786 * @return integer Page uid corresponding to alias value.
787 * @todo Define visibility
788 */
789 public function getPageIdFromAlias($link_param) {
790 $pRec = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecordsByField('pages', 'alias', $link_param);
791 return $pRec[0]['uid'];
792 }
793
794 /**
795 * Make Token ID for input index.
796 *
797 * @param string $index Suffix value.
798 * @return string Token ID
799 * @todo Define visibility
800 */
801 public function makeTokenID($index = '') {
802 return md5($this->tokenID_basePrefix . ':' . $index);
803 }
804
805 }