‪TYPO3CMS  ‪main
LegacyLinkNotationConverter.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
27 
35 {
39  protected ‪$resourceFactory;
40 
56  public function ‪resolve(string $linkParameter): array
57  {
58  $a = [];
59  if (stripos(rawurldecode(trim($linkParameter)), 'phar://') === 0) {
60  throw new \RuntimeException(
61  'phar scheme not allowed as soft reference target',
62  1530030673
63  );
64  }
65 
66  $result = [];
67 
68  // Resolve FAL-api "file:UID-of-sys_file-record" and "file:combined-identifier"
69  if (stripos($linkParameter, 'file:') === 0) {
70  $result = $this->‪getFileOrFolderObjectFromMixedIdentifier(substr($linkParameter, 5));
71  } elseif (GeneralUtility::validEmail((string)parse_url($linkParameter, PHP_URL_PATH))) {
72  $result['type'] = ‪LinkService::TYPE_EMAIL;
73  $result['email'] = $linkParameter;
74  } elseif (str_starts_with($linkParameter, 'tel:')) {
75  $result['type'] = ‪LinkService::TYPE_TELEPHONE;
76  $result['telephone'] = $linkParameter;
77  } elseif (str_contains($linkParameter, ':')) {
78  // Check for link-handler keyword
79  [$linkHandlerKeyword, $linkHandlerValue] = explode(':', $linkParameter, 2);
80  $result['type'] = strtolower(trim($linkHandlerKeyword));
81  $result['url'] = $linkParameter;
82  $result['value'] = $linkHandlerValue;
83  if ($result['type'] === ‪LinkService::TYPE_RECORD) {
84  [$a['identifier'], $tableAndUid] = explode(':', $linkHandlerValue, 2);
85  $tableAndUid = explode(':', $tableAndUid);
86  if (count($tableAndUid) > 1) {
87  $a['table'] = $tableAndUid[0];
88  $a['uid'] = $tableAndUid[1];
89  } else {
90  // this case can happen if there is the very old linkhandler syntax, which was only record:<table>:<uid>
91  $a['table'] = $a['identifier'];
92  $a['uid'] = $tableAndUid[0];
93  }
94  $result = array_merge($result, $a);
95  }
96  } else {
97  // special handling without a scheme
98  $isLocalFile = 0;
99  $fileChar = (int)strpos($linkParameter, '/');
100  $urlChar = (int)strpos($linkParameter, '.');
101 
102  $isIdOrAlias = ‪MathUtility::canBeInterpretedAsInteger($linkParameter);
103  $matches = [];
104  // capture old RTE links relative to TYPO3 Backend /typo3/
105  if (preg_match('#../(?:index\\.php)?\\?id=([^&]+)#', $linkParameter, $matches)) {
106  $linkParameter = $matches[1];
107  $isIdOrAlias = true;
108  }
109  $containsSlash = false;
110  if (!$isIdOrAlias) {
111  // Detects if a file is found in site-root and if so it will be treated like a normal file.
112  [$rootFileDat] = explode('?', rawurldecode($linkParameter));
113  $containsSlash = str_contains($rootFileDat, '/');
114  $pathInfo = pathinfo($rootFileDat);
115  $fileExtension = strtolower($pathInfo['extension'] ?? '');
116  if (!$containsSlash
117  && trim($rootFileDat)
118  && (
119  @is_file(‪Environment::getPublicPath() . '/' . $rootFileDat)
120  || $fileExtension === 'php'
121  || $fileExtension === 'html'
122  || $fileExtension === 'htm'
123  )
124  ) {
125  $isLocalFile = 1;
126  } elseif ($containsSlash) {
127  // Adding this so realurl directories are linked right (non-existing).
128  $isLocalFile = 2;
129  }
130  }
131 
132  // url (external): If doubleSlash or if a '.' comes before a '/'.
133  if (!$isIdOrAlias && $isLocalFile !== 1 && $urlChar && (!$containsSlash || $urlChar < $fileChar)) {
134  $result['type'] = ‪LinkService::TYPE_URL;
135  $result['url'] = ‪UrlLinkHandler::getDefaultScheme() . '://' . $linkParameter;
136  // file (internal) or folder
137  } elseif ($containsSlash || $isLocalFile) {
138  $result = $this->‪getFileOrFolderObjectFromMixedIdentifier($linkParameter);
139  } else {
140  // Integer or alias (alias is without slashes or periods or commas, that is
141  // 'nospace,alphanum_x,lower,unique' according to definition in $GLOBALS['TCA']!)
142  $result = $this->‪resolvePageRelatedParameters($linkParameter);
143  }
144  }
145 
146  return $result;
147  }
148 
156  protected function ‪resolvePageRelatedParameters(string $data): array
157  {
158  $result = ['type' => ‪LinkService::TYPE_PAGE];
159  if (str_contains($data, '#')) {
160  [$data, $result['fragment']] = explode('#', $data, 2);
161  }
162  // check for additional parameters
163  if (str_contains($data, '?')) {
164  [$data, $result['parameters']] = explode('?', $data, 2);
165  } elseif (str_contains($data, '&')) {
166  [$data, $result['parameters']] = explode('&', $data, 2);
167  }
168  $data = rtrim($data, ',');
169  if (empty($data)) {
170  $result['pageuid'] = 'current';
171  } elseif ($data[0] === '#') {
172  $result['pageuid'] = 'current';
173  $result['fragment'] = substr($data, 1);
174  } elseif (str_contains($data, ',')) {
175  [$result['pageuid'], $result['pagetype']] = explode(',', $data, 2);
176  } elseif (str_contains($data, '/')) {
177  $data = explode('/', trim($data, '/'));
178  $result['pageuid'] = array_shift($data);
179  foreach ($data as $k => $item) {
180  if ($data[$k] % 2 === 0 && !empty($data[$k + 1])) {
181  $result['page' . $data[$k]] = $data[$k + 1];
182  }
183  }
184  } else {
185  $result['pageuid'] = $data;
186  }
187  return $result;
188  }
189 
197  protected function ‪getFileOrFolderObjectFromMixedIdentifier(string $mixedIdentifier): array
198  {
199  $result = [];
200  try {
201  $fileIdentifier = $mixedIdentifier;
202  $fragment = null;
203  if (str_contains($fileIdentifier, '#')) {
204  [$fileIdentifier, $fragment] = explode('#', $fileIdentifier, 2);
205  }
206  $fileOrFolderObject = $this->‪getResourceFactory()->retrieveFileOrFolderObject($fileIdentifier);
207  // Link to a folder or file
208  if ($fileOrFolderObject instanceof ‪File) {
209  $result['type'] = ‪LinkService::TYPE_FILE;
210  $result['file'] = $fileOrFolderObject;
211  if ($fragment) {
212  $result['fragment'] = $fragment;
213  }
214  } elseif ($fileOrFolderObject instanceof ‪Folder) {
215  $result['type'] = ‪LinkService::TYPE_FOLDER;
216  $result['folder'] = $fileOrFolderObject;
217  if ($fragment) {
218  $result['fragment'] = $fragment;
219  }
220  } else {
221  $result['type'] = ‪LinkService::TYPE_UNKNOWN;
222  $result['file'] = $mixedIdentifier;
223  }
224  } catch (\RuntimeException $e) {
225  // Element wasn't found
226  $result['type'] = ‪LinkService::TYPE_UNKNOWN;
227  $result['file'] = $mixedIdentifier;
228  } catch (‪ResourceDoesNotExistException $e) {
229  // Resource was not found
230  $result['type'] = ‪LinkService::TYPE_UNKNOWN;
231  $result['file'] = $mixedIdentifier;
232  }
233 
234  return $result;
235  }
236 
240  protected function ‪getResourceFactory(): ‪ResourceFactory
241  {
242  if (!$this->resourceFactory) {
243  $this->resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
244  }
246  }
247 }
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static getPublicPath()
Definition: Environment.php:187
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger(mixed $var)
Definition: MathUtility.php:69
‪TYPO3\CMS\Core\Resource\Folder
Definition: Folder.php:37
‪TYPO3\CMS\Core\Resource\ResourceFactory
Definition: ResourceFactory.php:41
‪TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException
Definition: ResourceDoesNotExistException.php:24
‪TYPO3\CMS\Core\Resource\File
Definition: File.php:24
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:41
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:51