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