‪TYPO3CMS  9.5
ValidatorTask.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 
27 
33 {
37  protected ‪$sleepTime;
38 
42  protected ‪$sleepAfterFinish;
43 
47  protected ‪$countInARun;
48 
54  protected ‪$totalBrokenLink = 0;
55 
61  protected ‪$oldTotalBrokenLink = 0;
62 
68  protected ‪$templateMail;
69 
75  protected ‪$configuration = [];
76 
82  protected ‪$isDifferentToLastRun;
83 
89  protected ‪$emailTemplateFile;
90 
96  protected ‪$depth;
97 
103  protected ‪$page;
104 
110  protected ‪$email;
111 
117  protected ‪$emailOnBrokenLinkOnly;
118 
122  protected ‪$templateService;
123 
129  protected ‪$languageFile = 'LLL:EXT:linkvalidator/Resources/Private/Language/locallang.xlf';
130 
136  public function ‪getEmail()
137  {
138  return ‪$this->email;
139  }
140 
146  public function ‪setEmail(‪$email)
147  {
148  $this->email = ‪$email;
149  }
150 
156  public function ‪getEmailOnBrokenLinkOnly()
157  {
159  }
160 
167  {
168  $this->emailOnBrokenLinkOnly = ‪$emailOnBrokenLinkOnly;
169  }
170 
176  public function ‪getPage()
177  {
178  return ‪$this->page;
179  }
180 
186  public function ‪setPage(‪$page)
187  {
188  $this->page = ‪$page;
189  }
190 
196  public function ‪getDepth()
197  {
198  return ‪$this->depth;
199  }
200 
206  public function ‪setDepth(‪$depth)
207  {
208  $this->depth = ‪$depth;
209  }
210 
216  public function ‪getEmailTemplateFile()
217  {
219  }
220 
227  {
228  $this->emailTemplateFile = ‪$emailTemplateFile;
229  }
230 
236  public function ‪getConfiguration()
237  {
239  }
240 
246  public function ‪setConfiguration(‪$configuration)
247  {
248  $this->configuration = ‪$configuration;
249  }
250 
257  public function ‪execute()
258  {
259  $this->‪setCliArguments();
260  $this->templateService = GeneralUtility::makeInstance(MarkerBasedTemplateService::class);
261  $successfullyExecuted = true;
262  if (!file_exists($file = GeneralUtility::getFileAbsFileName($this->emailTemplateFile))
263  && !empty($this->email)
264  ) {
265  if ($this->emailTemplateFile === 'EXT:linkvalidator/res/mailtemplate.html') {
266  // Update the default email template file path
267  $this->emailTemplateFile = 'EXT:linkvalidator/Resources/Private/Templates/mailtemplate.html';
268  $this->‪save();
269  } else {
270  $lang = $this->‪getLanguageService();
271  throw new \InvalidArgumentException(
272  $lang->sL($this->languageFile . ':tasks.error.invalidEmailTemplateFile'),
273  '1295476972'
274  );
275  }
276  }
277  $htmlFile = file_get_contents($file);
278  $this->templateMail = $this->templateService->getSubpart($htmlFile, '###REPORT_TEMPLATE###');
279  // The array to put the content into
280  $pageSections = '';
281  $this->isDifferentToLastRun = false;
282  $pageList = GeneralUtility::trimExplode(',', $this->page, true);
283  $modTs = $this->‪loadModTsConfig($this->page);
284  if (is_array($pageList)) {
285  // reset broken link counts as they were stored in the serialized object
286  $this->oldTotalBrokenLink = 0;
287  $this->totalBrokenLink = 0;
288  foreach ($pageList as ‪$page) {
289  $pageSections .= $this->‪checkPageLinks($page);
290  }
291  }
292  if ($this->totalBrokenLink != $this->oldTotalBrokenLink) {
293  $this->isDifferentToLastRun = true;
294  }
295  if ($this->totalBrokenLink > 0
296  && (!$this->emailOnBrokenLinkOnly || $this->isDifferentToLastRun)
297  && !empty($this->email)
298  ) {
299  $successfullyExecuted = $this->‪reportEmail($pageSections, $modTs);
300  }
301  return $successfullyExecuted;
302  }
303 
311  protected function ‪checkPageLinks(‪$page)
312  {
313  ‪$page = (int)‪$page;
314  $pageSections = '';
315  $pageIds = '';
316  $oldLinkCounts = [];
317  $modTs = $this->‪loadModTsConfig(‪$page);
318  $searchFields = $this->‪getSearchField($modTs);
319  $linkTypes = $this->‪getLinkTypes($modTs);
321  $processor = GeneralUtility::makeInstance(LinkAnalyzer::class);
322  if (‪$page === 0) {
323  $rootLineHidden = false;
324  } else {
325  $pageRow = ‪BackendUtility::getRecord('pages', ‪$page, '*', '', false);
326  if ($pageRow === null) {
327  throw new \InvalidArgumentException(
328  sprintf($this->‪getLanguageService()->sL($this->languageFile . ':tasks.error.invalidPageUid'), ‪$page),
329  1502800555
330  );
331  }
332  $rootLineHidden = $processor->getRootLineIsHidden($pageRow);
333  }
334  if (!$rootLineHidden || $modTs['checkhidden'] == 1) {
335  $pageIds = $processor->extGetTreeList(‪$page, $this->depth, 0, '1=1', $modTs['checkhidden']);
336  if (isset($pageRow) && $pageRow['hidden'] == 0 || $modTs['checkhidden'] == 1) {
337  // \TYPO3\CMS\Linkvalidator\LinkAnalyzer->extGetTreeList() always adds trailing comma
338  $pageIds .= ‪$page;
339  }
340  }
341  if (!empty($pageIds)) {
342  $processor->init($searchFields, $pageIds, $modTs);
343  if (!empty($this->email)) {
344  $oldLinkCounts = $processor->getLinkCounts(‪$page);
345  $this->oldTotalBrokenLink += $oldLinkCounts['brokenlinkCount'];
346  }
347  $processor->getLinkStatistics($linkTypes, $modTs['checkhidden']);
348  if (!empty($this->email)) {
349  $linkCounts = $processor->getLinkCounts(‪$page);
350  $this->totalBrokenLink += $linkCounts['brokenlinkCount'];
351  $pageSections = $this->‪buildMail(‪$page, $pageIds, $linkCounts, $oldLinkCounts);
352  }
353  }
354  return $pageSections;
355  }
356 
364  protected function ‪loadModTsConfig(‪$page)
365  {
366  $parseObj = GeneralUtility::makeInstance(TypoScriptParser::class);
367  $parseObj->parse($this->configuration);
368  if (!empty($parseObj->errors)) {
369  $languageService = $this->‪getLanguageService();
370  $parseErrorMessage = $languageService->sL($this->languageFile . ':tasks.error.invalidTSconfig')
371  . '<br />';
372  foreach ($parseObj->errors as $errorInfo) {
373  $parseErrorMessage .= $errorInfo[0] . '<br />';
374  }
375  throw new \Exception($parseErrorMessage, '1295476989');
376  }
377  $modTs = ‪BackendUtility::getPagesTSconfig(‪$page)['mod.']['linkvalidator.'] ?? [];
378  $tsConfig = $parseObj->setup;
379  $overrideTs = $tsConfig['mod.']['linkvalidator.'];
380  if (is_array($overrideTs)) {
381  ‪ArrayUtility::mergeRecursiveWithOverrule($modTs, $overrideTs);
382  }
383  return $modTs;
384  }
385 
392  protected function ‪getSearchField(array $modTS)
393  {
394  // Get the searchFields from TypoScript
395  foreach ($modTS['searchFields.'] as $table => $fieldList) {
396  ‪$fields = GeneralUtility::trimExplode(',', $fieldList);
397  foreach (‪$fields as $field) {
398  $searchFields[$table][] = $field;
399  }
400  }
401  return $searchFields ?? [];
402  }
403 
410  protected function ‪getLinkTypes(array $modTS)
411  {
412  $linkTypes = [];
413  $typesTmp = GeneralUtility::trimExplode(',', $modTS['linktypes'], true);
414  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'] ?? [] as $type => $value) {
415  if (in_array($type, $typesTmp)) {
416  $linkTypes[$type] = 1;
417  }
418  }
419  return $linkTypes;
420  }
421 
430  protected function ‪reportEmail($pageSections, array $modTsConfig)
431  {
432  $lang = $this->‪getLanguageService();
433  $content = $this->templateService->substituteSubpart($this->templateMail, '###PAGE_SECTION###', $pageSections);
435  $markerArray = [];
437  $validEmailList = [];
439  $sendEmail = true;
440  $markerArray['totalBrokenLink'] = ‪$this->totalBrokenLink;
441  $markerArray['totalBrokenLink_old'] = ‪$this->oldTotalBrokenLink;
442 
443  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['reportEmailMarkers'] ?? [] as $userFunc) {
444  $params = [
445  'pObj' => &$this,
446  'markerArray' => $markerArray
447  ];
448  $newMarkers = GeneralUtility::callUserFunction($userFunc, $params, $this);
449  if (is_array($newMarkers)) {
450  $markerArray = $newMarkers + $markerArray;
451  }
452  unset($params);
453  }
454  $content = $this->templateService->substituteMarkerArray($content, $markerArray, '###|###', true, true);
456  $mail = GeneralUtility::makeInstance(MailMessage::class);
457  if (empty($modTsConfig['mail.']['fromemail'])) {
458  $modTsConfig['mail.']['fromemail'] = ‪MailUtility::getSystemFromAddress();
459  }
460  if (empty($modTsConfig['mail.']['fromname'])) {
461  $modTsConfig['mail.']['fromname'] = ‪MailUtility::getSystemFromName();
462  }
463  if (GeneralUtility::validEmail($modTsConfig['mail.']['fromemail'])) {
464  $mail->setFrom([$modTsConfig['mail.']['fromemail'] => $modTsConfig['mail.']['fromname']]);
465  } else {
466  throw new \Exception(
467  $lang->sL($this->languageFile . ':tasks.error.invalidFromEmail'),
468  '1295476760'
469  );
470  }
471  if (GeneralUtility::validEmail($modTsConfig['mail.']['replytoemail'])) {
472  $mail->setReplyTo([$modTsConfig['mail.']['replytoemail'] => $modTsConfig['mail.']['replytoname']]);
473  }
474  if (!empty($modTsConfig['mail.']['subject'])) {
475  $mail->setSubject($modTsConfig['mail.']['subject']);
476  } else {
477  throw new \Exception(
478  $lang->sL($this->languageFile . ':tasks.error.noSubject'),
479  '1295476808'
480  );
481  }
482  if (!empty($this->email)) {
483  // Check if old input field value is still there and save the value a
484  if (strpos($this->email, ',') !== false) {
485  $emailList = GeneralUtility::trimExplode(',', $this->email, true);
486  $this->email = implode(LF, $emailList);
487  $this->‪save();
488  } else {
489  $emailList = GeneralUtility::trimExplode(LF, $this->email, true);
490  }
491 
492  foreach ($emailList as $emailAdd) {
493  if (!GeneralUtility::validEmail($emailAdd)) {
494  throw new \Exception(
495  $lang->sL($this->languageFile . ':tasks.error.invalidToEmail'),
496  '1295476821'
497  );
498  }
499  $validEmailList[] = $emailAdd;
500  }
501  }
502  if (is_array($validEmailList) && !empty($validEmailList)) {
503  $mail->setTo($validEmailList);
504  } else {
505  $sendEmail = false;
506  }
507  if ($sendEmail) {
508  $mail->setBody($content, 'text/html');
509  $mail->send();
510  }
511  return $sendEmail;
512  }
513 
523  protected function ‪buildMail($curPage, $pageList, array $markerArray, array $oldBrokenLink)
524  {
525  $pageSectionHtml = $this->templateService->getSubpart($this->templateMail, '###PAGE_SECTION###');
526  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['buildMailMarkers'] ?? [] as $userFunc) {
527  $params = [
528  'curPage' => $curPage,
529  'pageList' => $pageList,
530  'markerArray' => $markerArray,
531  'oldBrokenLink' => $oldBrokenLink,
532  'pObj' => &$this
533  ];
534  $newMarkers = GeneralUtility::callUserFunction($userFunc, $params, $this);
535  if (is_array($newMarkers)) {
536  $markerArray = $newMarkers + $markerArray;
537  }
538  unset($params);
539  }
540  foreach ($markerArray as $markerKey => $markerValue) {
541  if (empty($oldBrokenLink[$markerKey])) {
542  $oldBrokenLink[$markerKey] = 0;
543  }
544  if ($markerValue != $oldBrokenLink[$markerKey]) {
545  $this->isDifferentToLastRun = true;
546  }
547  $markerArray[$markerKey . '_old'] = $oldBrokenLink[$markerKey];
548  }
549  $markerArray['title'] = ‪BackendUtility::getRecordTitle(
550  'pages',
551  ‪BackendUtility::getRecord('pages', $curPage)
552  );
553  $content = '';
554  if ($markerArray['brokenlinkCount'] > 0) {
555  $content = $this->templateService->substituteMarkerArray(
556  $pageSectionHtml,
557  $markerArray,
558  '###|###',
559  true,
560  true
561  );
562  }
563  return $content;
564  }
565 
572  public function ‪getAdditionalInformation()
573  {
574  $additionalInformation = [];
575 
576  ‪$page = (int)$this->‪getPage();
577  $pageLabel = ‪$page;
578  if (‪$page !== 0) {
579  $pageData = ‪BackendUtility::getRecord('pages', ‪$page);
580  if (!empty($pageData)) {
581  $pageTitle = ‪BackendUtility::getRecordTitle('pages', $pageData);
582  $pageLabel = $pageTitle . ' (' . ‪$page . ')';
583  }
584  }
585  $lang = $this->‪getLanguageService();
586  ‪$depth = (int)$this->‪getDepth();
587  $additionalInformation[] = $lang->sL($this->languageFile . ':tasks.validate.page') . ': ' . $pageLabel;
588  $additionalInformation[] = $lang->sL($this->languageFile . ':tasks.validate.depth') . ': '
589  . $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.depth_' . (‪$depth === 999 ? 'infi' : ‪$depth));
590  $additionalInformation[] = $lang->sL($this->languageFile . ':tasks.validate.email') . ': '
591  . $this->‪getEmail();
592 
593  return implode(', ', $additionalInformation);
594  }
595 
599  protected function ‪setCliArguments()
600  {
601  $_SERVER['argv'] = [
602  $_SERVER['argv'][0],
603  'tx_link_scheduler_link',
604  '0',
605  '-ss',
606  '--sleepTime',
608  '--sleepAfterFinish',
610  '--countInARun',
612  ];
613  }
614 
618  protected function ‪getLanguageService()
619  {
620  return ‪$GLOBALS['LANG'];
621  }
622 }
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\setPage
‪setPage($page)
Definition: ValidatorTask.php:171
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\setEmailOnBrokenLinkOnly
‪setEmailOnBrokenLinkOnly($emailOnBrokenLinkOnly)
Definition: ValidatorTask.php:151
‪TYPO3\CMS\Scheduler\Task\AbstractTask\save
‪bool save()
Definition: AbstractTask.php:555
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$emailOnBrokenLinkOnly
‪bool $emailOnBrokenLinkOnly
Definition: ValidatorTask.php:104
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$page
‪int $page
Definition: ValidatorTask.php:92
‪TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser
Definition: TypoScriptParser.php:37
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$templateMail
‪string $templateMail
Definition: ValidatorTask.php:62
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\buildMail
‪string buildMail($curPage, $pageList, array $markerArray, array $oldBrokenLink)
Definition: ValidatorTask.php:508
‪TYPO3\CMS\Core\Utility\MailUtility\getSystemFromAddress
‪static string getSystemFromAddress()
Definition: MailUtility.php:73
‪TYPO3\CMS\Core\Mail\MailMessage
Definition: MailMessage.php:23
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\setEmail
‪setEmail($email)
Definition: ValidatorTask.php:131
‪TYPO3\CMS\Core\Utility\ArrayUtility\mergeRecursiveWithOverrule
‪static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
Definition: ArrayUtility.php:614
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\setCliArguments
‪setCliArguments()
Definition: ValidatorTask.php:584
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getConfiguration
‪array getConfiguration()
Definition: ValidatorTask.php:221
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\checkPageLinks
‪string checkPageLinks($page)
Definition: ValidatorTask.php:296
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\execute
‪bool execute()
Definition: ValidatorTask.php:242
‪$fields
‪$fields
Definition: pages.php:4
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$sleepAfterFinish
‪int $sleepAfterFinish
Definition: ValidatorTask.php:40
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$totalBrokenLink
‪int $totalBrokenLink
Definition: ValidatorTask.php:50
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$isDifferentToLastRun
‪bool $isDifferentToLastRun
Definition: ValidatorTask.php:74
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$languageFile
‪string $languageFile
Definition: ValidatorTask.php:114
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\loadModTsConfig
‪array loadModTsConfig($page)
Definition: ValidatorTask.php:349
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getAdditionalInformation
‪string getAdditionalInformation()
Definition: ValidatorTask.php:557
‪TYPO3\CMS\Scheduler\Task\AbstractTask
Definition: AbstractTask.php:32
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getEmailOnBrokenLinkOnly
‪bool getEmailOnBrokenLinkOnly()
Definition: ValidatorTask.php:141
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$oldTotalBrokenLink
‪int $oldTotalBrokenLink
Definition: ValidatorTask.php:56
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$depth
‪int $depth
Definition: ValidatorTask.php:86
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\setDepth
‪setDepth($depth)
Definition: ValidatorTask.php:191
‪TYPO3\CMS\Backend\Utility\BackendUtility\getRecordTitle
‪static string getRecordTitle($table, $row, $prep=false, $forceResult=true)
Definition: BackendUtility.php:1811
‪TYPO3\CMS\Core\Utility\MailUtility
Definition: MailUtility.php:24
‪TYPO3\CMS\Linkvalidator\Task
Definition: ValidatorTask.php:2
‪TYPO3\CMS\Backend\Utility\BackendUtility
Definition: BackendUtility.php:72
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$emailTemplateFile
‪string $emailTemplateFile
Definition: ValidatorTask.php:80
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$templateService
‪MarkerBasedTemplateService $templateService
Definition: ValidatorTask.php:108
‪TYPO3\CMS\Backend\Utility\BackendUtility\getRecord
‪static array null getRecord($table, $uid, $fields=' *', $where='', $useDeleteClause=true)
Definition: BackendUtility.php:130
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getLanguageService
‪LanguageService getLanguageService()
Definition: ValidatorTask.php:603
‪TYPO3\CMS\Backend\Utility\BackendUtility\getPagesTSconfig
‪static array getPagesTSconfig($id, $rootLine=null, $returnPartArray=false)
Definition: BackendUtility.php:864
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:23
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\setConfiguration
‪setConfiguration($configuration)
Definition: ValidatorTask.php:231
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\setEmailTemplateFile
‪setEmailTemplateFile($emailTemplateFile)
Definition: ValidatorTask.php:211
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$countInARun
‪int $countInARun
Definition: ValidatorTask.php:44
‪TYPO3\CMS\Core\Utility\MailUtility\getSystemFromName
‪static string getSystemFromName()
Definition: MailUtility.php:52
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getPage
‪int getPage()
Definition: ValidatorTask.php:161
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getDepth
‪int getDepth()
Definition: ValidatorTask.php:181
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getLinkTypes
‪array getLinkTypes(array $modTS)
Definition: ValidatorTask.php:395
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:29
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService
Definition: MarkerBasedTemplateService.php:25
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getSearchField
‪array getSearchField(array $modTS)
Definition: ValidatorTask.php:377
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$email
‪string $email
Definition: ValidatorTask.php:98
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\reportEmail
‪bool reportEmail($pageSections, array $modTsConfig)
Definition: ValidatorTask.php:415
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$configuration
‪array $configuration
Definition: ValidatorTask.php:68
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getEmail
‪string getEmail()
Definition: ValidatorTask.php:121
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getEmailTemplateFile
‪string getEmailTemplateFile()
Definition: ValidatorTask.php:201
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask
Definition: ValidatorTask.php:33
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$sleepTime
‪int $sleepTime
Definition: ValidatorTask.php:36