‪TYPO3CMS  11.5
InternalLinktype.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
22 
27 {
31  public const ‪DELETED = 'deleted';
32 
36  public const ‪HIDDEN = 'hidden';
37 
41  public const ‪MOVED = 'moved';
42 
46  public const ‪NOTEXISTING = 'notExisting';
47 
53  protected ‪$responsePage = true;
54 
60  protected ‪$responseContent = true;
61 
70  public function ‪checkLink($url, $softRefEntry, $reference)
71  {
72  $page = null;
73  $anchor = '';
74  $this->responseContent = true;
75  // Might already contain values - empty it
76  unset($this->errorParams);
77  // Only check pages records. Content elements will also be checked
78  // as we extract the anchor in the next step.
79  [$table] = explode(':', $softRefEntry['substr']['recordRef']);
80  if (!in_array($table, ['pages', 'tt_content'], true)) {
81  return true;
82  }
83  // Defines the linked page and anchor (if any).
84  if (str_contains($url, '#c')) {
85  $parts = explode('#c', $url);
86  $page = $parts[0];
87  $anchor = $parts[1];
88  } elseif (
89  $table === 'tt_content'
90  && strpos($softRefEntry['row'][$softRefEntry['field']], 't3://') === 0
91  ) {
92  $parsedTypoLinkUrl = @parse_url($softRefEntry['row'][$softRefEntry['field']]);
93  if ($parsedTypoLinkUrl['host'] === 'page') {
94  parse_str($parsedTypoLinkUrl['query'], $query);
95  if (isset($query['uid'])) {
96  $page = (int)$query['uid'];
97  $anchor = (int)$url;
98  }
99  }
100  } else {
101  $page = $url;
102  }
103  // Check if the linked page is OK
104  $this->responsePage = $this->‪checkPage((int)$page);
105  // Check if the linked content element is OK
106  if ($anchor) {
107  // Check if the content element is OK
108  $this->responseContent = $this->‪checkContent((int)$page, (int)$anchor);
109  }
110  if (
111  (is_array($this->errorParams['page'] ?? false) && !$this->responsePage)
112  || (is_array($this->errorParams['content'] ?? false) && !$this->responseContent)
113  ) {
114  $this->‪setErrorParams($this->errorParams);
115  }
116 
117  return $this->responsePage && ‪$this->responseContent;
118  }
119 
126  protected function ‪checkPage($page)
127  {
128  // Get page ID on which the content element in fact is located
129  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
130  $queryBuilder->getRestrictions()->removeAll();
131  $row = $queryBuilder
132  ->select('uid', 'title', 'deleted', 'hidden', 'starttime', 'endtime')
133  ->from('pages')
134  ->where(
135  $queryBuilder->expr()->eq(
136  'uid',
137  $queryBuilder->createNamedParameter($page, ‪Connection::PARAM_INT)
138  )
139  )
140  ->executeQuery()
141  ->fetchAssociative();
142  $this->responsePage = true;
143  if ($row) {
144  if ($row['deleted'] == '1') {
145  $this->errorParams['errorType']['page'] = ‪self::DELETED;
146  $this->errorParams['page']['title'] = $row['title'];
147  $this->errorParams['page']['uid'] = $row['uid'];
148  $this->responsePage = false;
149  } elseif ($row['hidden'] == '1'
150  || ‪$GLOBALS['EXEC_TIME'] < (int)$row['starttime']
151  || $row['endtime'] && (int)$row['endtime'] < ‪$GLOBALS['EXEC_TIME']
152  ) {
153  $this->errorParams['errorType']['page'] = ‪self::HIDDEN;
154  $this->errorParams['page']['title'] = $row['title'];
155  $this->errorParams['page']['uid'] = $row['uid'];
156  $this->responsePage = false;
157  }
158  } else {
159  $this->errorParams['errorType']['page'] = ‪self::NOTEXISTING;
160  $this->errorParams['page']['uid'] = (int)$page;
161  $this->responsePage = false;
162  }
163  return ‪$this->responsePage;
164  }
165 
173  protected function ‪checkContent($page, $anchor)
174  {
175  // Get page ID on which the content element in fact is located
176  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
177  $queryBuilder->getRestrictions()->removeAll();
178  $row = $queryBuilder
179  ->select('uid', 'pid', 'header', 'deleted', 'hidden', 'starttime', 'endtime')
180  ->from('tt_content')
181  ->where(
182  $queryBuilder->expr()->eq(
183  'uid',
184  $queryBuilder->createNamedParameter($anchor, ‪Connection::PARAM_INT)
185  )
186  )
187  ->executeQuery()
188  ->fetchAssociative();
189  $this->responseContent = true;
190  // this content element exists
191  if ($row) {
192  $page = (int)$page;
193  // page ID on which this CE is in fact located.
194  $correctPageID = (int)$row['pid'];
195  // Check if the element is on the linked page
196  // (The element might have been moved to another page)
197  if ($correctPageID !== $page) {
198  $this->errorParams['errorType']['content'] = ‪self::MOVED;
199  $this->errorParams['content']['title'] = BackendUtility::getRecordTitle('tt_content', $row);
200  $this->errorParams['content']['uid'] = $row['uid'];
201  $this->errorParams['content']['wrongPage'] = $page;
202  $this->errorParams['content']['rightPage'] = $correctPageID;
203  $this->responseContent = false;
204  } else {
205  // The element is located on the page to which the link is pointing
206  if ($row['deleted'] == '1') {
207  $this->errorParams['errorType']['content'] = ‪self::DELETED;
208  $this->errorParams['content']['title'] = BackendUtility::getRecordTitle('tt_content', $row);
209  $this->errorParams['content']['uid'] = $row['uid'];
210  $this->responseContent = false;
211  } elseif ($row['hidden'] == '1' || ‪$GLOBALS['EXEC_TIME'] < (int)$row['starttime'] || $row['endtime'] && (int)$row['endtime'] < ‪$GLOBALS['EXEC_TIME']) {
212  $this->errorParams['errorType']['content'] = ‪self::HIDDEN;
213  $this->errorParams['content']['title'] = BackendUtility::getRecordTitle('tt_content', $row);
214  $this->errorParams['content']['uid'] = $row['uid'];
215  $this->responseContent = false;
216  }
217  }
218  } else {
219  // The content element does not exist
220  $this->errorParams['errorType']['content'] = ‪self::NOTEXISTING;
221  $this->errorParams['content']['uid'] = (int)$anchor;
222  $this->responseContent = false;
223  }
225  }
226 
234  public function ‪getErrorMessage(‪$errorParams)
235  {
236  $lang = $this->‪getLanguageService();
237  $errorType = ‪$errorParams['errorType'] ?? '';
238  if ($errorType === '') {
239  return $lang->sL('LLL:EXT:linkvalidator/Resources/Private/Language/Module/locallang.xlf:list.report.noinformation');
240  }
241 
242  $errorPage = null;
243  $errorContent = null;
244  if (is_array(‪$errorParams['page'] ?? false)) {
245  switch ($errorType['page']) {
246  case ‪self::DELETED:
247  $errorPage = str_replace(
248  [
249  '###title###',
250  '###uid###',
251  ],
252  [
253  ‪$errorParams['page']['title'],
254  (string)‪$errorParams['page']['uid'],
255  ],
256  $lang->getLL('list.report.pagedeleted')
257  );
258  break;
259  case ‪self::HIDDEN:
260  $errorPage = str_replace(
261  [
262  '###title###',
263  '###uid###',
264  ],
265  [
266  ‪$errorParams['page']['title'],
267  (string)‪$errorParams['page']['uid'],
268  ],
269  $lang->getLL('list.report.pagenotvisible')
270  );
271  break;
272  default:
273  $errorPage = str_replace(
274  '###uid###',
275  (string)‪$errorParams['page']['uid'],
276  $lang->getLL('list.report.pagenotexisting')
277  );
278  }
279  }
280  if (is_array(‪$errorParams['content'] ?? false)) {
281  switch ($errorType['content']) {
282  case ‪self::DELETED:
283  $errorContent = str_replace(
284  [
285  '###title###',
286  '###uid###',
287  ],
288  [
289  ‪$errorParams['content']['title'],
290  (string)‪$errorParams['content']['uid'],
291  ],
292  $lang->getLL('list.report.contentdeleted')
293  );
294  break;
295  case ‪self::HIDDEN:
296  $errorContent = str_replace(
297  [
298  '###title###',
299  '###uid###',
300  ],
301  [
302  ‪$errorParams['content']['title'],
303  (string)‪$errorParams['content']['uid'],
304  ],
305  $lang->getLL('list.report.contentnotvisible')
306  );
307  break;
308  case ‪self::MOVED:
309  $errorContent = str_replace(
310  [
311  '###title###',
312  '###uid###',
313  '###wrongpage###',
314  '###rightpage###',
315  ],
316  [
317  ‪$errorParams['content']['title'],
318  (string)‪$errorParams['content']['uid'],
319  (string)‪$errorParams['content']['wrongPage'],
320  (string)‪$errorParams['content']['rightPage'],
321  ],
322  $lang->getLL('list.report.contentmoved')
323  );
324  break;
325  default:
326  $errorContent = str_replace('###uid###', (string)‪$errorParams['content']['uid'], $lang->getLL('list.report.contentnotexisting'));
327  }
328  }
329  if (isset($errorPage) && isset($errorContent)) {
330  $response = $errorPage . LF . $errorContent;
331  } elseif (isset($errorPage)) {
332  $response = $errorPage;
333  } elseif (isset($errorContent)) {
334  $response = $errorContent;
335  } else {
336  // This should not happen
337  $response = $lang->getLL('list.report.noinformation');
338  }
339  return $response;
340  }
341 
348  public function ‪getBrokenUrl($row)
349  {
350  $domain = rtrim(‪$GLOBALS['TYPO3_REQUEST']->getAttribute('normalizedParams')->getSiteUrl(), '/');
351  return $domain . '/index.php?id=' . $row['url'];
352  }
353 }
‪TYPO3\CMS\Linkvalidator\Linktype\InternalLinktype\checkLink
‪bool checkLink($url, $softRefEntry, $reference)
Definition: InternalLinktype.php:68
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:49
‪TYPO3\CMS\Linkvalidator\Linktype\AbstractLinktype\$errorParams
‪array $errorParams
Definition: AbstractLinktype.php:29
‪TYPO3\CMS\Linkvalidator\Linktype\AbstractLinktype\getLanguageService
‪LanguageService getLanguageService()
Definition: AbstractLinktype.php:93
‪TYPO3\CMS\Linkvalidator\Linktype\AbstractLinktype
Definition: AbstractLinktype.php:24
‪TYPO3\CMS\Linkvalidator\Linktype\InternalLinktype\MOVED
‪const MOVED
Definition: InternalLinktype.php:41
‪TYPO3\CMS\Linkvalidator\Linktype\InternalLinktype\$responseContent
‪bool $responseContent
Definition: InternalLinktype.php:58
‪TYPO3\CMS\Linkvalidator\Linktype
Definition: AbstractLinktype.php:16
‪TYPO3\CMS\Linkvalidator\Linktype\InternalLinktype
Definition: InternalLinktype.php:27
‪TYPO3\CMS\Linkvalidator\Linktype\InternalLinktype\getBrokenUrl
‪string getBrokenUrl($row)
Definition: InternalLinktype.php:346
‪TYPO3\CMS\Linkvalidator\Linktype\InternalLinktype\DELETED
‪const DELETED
Definition: InternalLinktype.php:31
‪TYPO3\CMS\Linkvalidator\Linktype\InternalLinktype\checkPage
‪bool checkPage($page)
Definition: InternalLinktype.php:124
‪TYPO3\CMS\Linkvalidator\Linktype\InternalLinktype\HIDDEN
‪const HIDDEN
Definition: InternalLinktype.php:36
‪TYPO3\CMS\Linkvalidator\Linktype\AbstractLinktype\setErrorParams
‪setErrorParams($value)
Definition: AbstractLinktype.php:63
‪TYPO3\CMS\Linkvalidator\Linktype\InternalLinktype\checkContent
‪bool checkContent($page, $anchor)
Definition: InternalLinktype.php:171
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:38
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Linkvalidator\Linktype\InternalLinktype\NOTEXISTING
‪const NOTEXISTING
Definition: InternalLinktype.php:46
‪TYPO3\CMS\Linkvalidator\Linktype\InternalLinktype\getErrorMessage
‪string getErrorMessage($errorParams)
Definition: InternalLinktype.php:232
‪TYPO3\CMS\Linkvalidator\Linktype\InternalLinktype\$responsePage
‪bool $responsePage
Definition: InternalLinktype.php:52