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