[TASK] Cleanup character after PHP closing tag
[Packages/TYPO3.CMS.git] / typo3 / sysext / linkvalidator / Classes / Task / ValidatorTask.php
1 <?php
2 namespace TYPO3\CMS\Linkvalidator\Task;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2010 - 2011 Michael Miousse (michael.miousse@infoglobe.ca)
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 * This class provides Scheduler plugin implementation
28 *
29 * @author Michael Miousse <michael.miousse@infoglobe.ca>
30 * @package TYPO3
31 * @subpackage linkvalidator
32 */
33 class ValidatorTask extends \TYPO3\CMS\Scheduler\Task {
34
35 /**
36 * @var integer
37 */
38 protected $sleepTime;
39
40 /**
41 * @var integer
42 */
43 protected $sleepAfterFinish;
44
45 /**
46 * @var integer
47 */
48 protected $countInARun;
49
50 /**
51 * Total number of broken links
52 *
53 * @var integer
54 */
55 protected $totalBrokenLink = 0;
56
57 /**
58 * Total number of broken links from the last run
59 *
60 * @var integer
61 */
62 protected $oldTotalBrokenLink = 0;
63
64 /**
65 * Mail template fetched from the given template file
66 *
67 * @var string
68 */
69 protected $templateMail;
70
71 /**
72 * specific TSconfig for this task.
73 *
74 * @var array
75 */
76 protected $configuration = array();
77
78 /**
79 * Shows if number of result was different from the result of the last check or not
80 *
81 * @var boolean
82 */
83 protected $dif;
84
85 /**
86 * Template to be used for the email
87 *
88 * @var string
89 */
90 protected $emailTemplateFile;
91
92 /**
93 * Level of pages the task should check
94 *
95 * @var integer
96 */
97 protected $depth;
98
99 /**
100 * UID of the start page for this task
101 *
102 * @var integer
103 */
104 protected $page;
105
106 /**
107 * Email address to which an email report is sent
108 *
109 * @var string
110 */
111 protected $email;
112
113 /**
114 * Only send an email, if new broken links were found
115 *
116 * @var boolean
117 */
118 protected $emailOnBrokenLinkOnly;
119
120 /**
121 * Get the value of the protected property email
122 *
123 * @return string Email address to which an email report is sent
124 */
125 public function getEmail() {
126 return $this->email;
127 }
128
129 /**
130 * Set the value of the private property email.
131 *
132 * @param string $email Email address to which an email report is sent
133 * @return void
134 */
135 public function setEmail($email) {
136 $this->email = $email;
137 }
138
139 /**
140 * Get the value of the protected property emailOnBrokenLinkOnly
141 *
142 * @return boolean Whether to send an email, if new broken links were found
143 */
144 public function getEmailOnBrokenLinkOnly() {
145 return $this->emailOnBrokenLinkOnly;
146 }
147
148 /**
149 * Set the value of the private property emailOnBrokenLinkOnly
150 *
151 * @param boolean $emailOnBrokenLinkOnly Only send an email, if new broken links were found
152 * @return void
153 */
154 public function setEmailOnBrokenLinkOnly($emailOnBrokenLinkOnly) {
155 $this->emailOnBrokenLinkOnly = $emailOnBrokenLinkOnly;
156 }
157
158 /**
159 * Get the value of the protected property page
160 *
161 * @return integer UID of the start page for this task
162 */
163 public function getPage() {
164 return $this->page;
165 }
166
167 /**
168 * Set the value of the private property page
169 *
170 * @param integer $page UID of the start page for this task.
171 * @return void
172 */
173 public function setPage($page) {
174 $this->page = $page;
175 }
176
177 /**
178 * Get the value of the protected property depth
179 *
180 * @return integer Level of pages the task should check
181 */
182 public function getDepth() {
183 return $this->depth;
184 }
185
186 /**
187 * Set the value of the private property depth
188 *
189 * @param integer $depth Level of pages the task should check
190 * @return void
191 */
192 public function setDepth($depth) {
193 $this->depth = $depth;
194 }
195
196 /**
197 * Get the value of the protected property emailTemplateFile
198 *
199 * @return string Template to be used for the email
200 */
201 public function getEmailTemplateFile() {
202 return $this->emailTemplateFile;
203 }
204
205 /**
206 * Set the value of the private property emailTemplateFile
207 *
208 * @param string $emailTemplateFile Template to be used for the email
209 * @return void
210 */
211 public function setEmailTemplateFile($emailTemplateFile) {
212 $this->emailTemplateFile = $emailTemplateFile;
213 }
214
215 /**
216 * Get the value of the protected property configuration
217 *
218 * @return array specific TSconfig for this task
219 */
220 public function getConfiguration() {
221 return $this->configuration;
222 }
223
224 /**
225 * Set the value of the private property configuration
226 *
227 * @param array $configuration specific TSconfig for this task
228 * @return void
229 */
230 public function setConfiguration($configuration) {
231 $this->configuration = $configuration;
232 }
233
234 /**
235 * Function execute from the Scheduler
236 *
237 * @return boolean TRUE on successful execution, FALSE on error
238 */
239 public function execute() {
240 $this->setCliArguments();
241 $successfullyExecuted = TRUE;
242 if (!file_exists(($file = \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName($this->emailTemplateFile))) && !empty($this->email)) {
243 throw new \Exception($GLOBALS['LANG']->sL('LLL:EXT:linkvalidator/locallang.xml:tasks.error.invalidEmailTemplateFile'), '1295476972');
244 }
245 $htmlFile = \TYPO3\CMS\Core\Utility\GeneralUtility::getURL($file);
246 $this->templateMail = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($htmlFile, '###REPORT_TEMPLATE###');
247 // The array to put the content into
248 $html = array();
249 $pageSections = '';
250 $this->dif = FALSE;
251 $pageList = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->page, 1);
252 $modTS = $this->loadModTSconfig($this->page);
253 if (is_array($pageList)) {
254 foreach ($pageList as $page) {
255 $pageSections .= $this->checkPageLinks($page);
256 }
257 }
258 if ($this->totalBrokenLink != $this->oldTotalBrokenLink) {
259 $this->dif = TRUE;
260 }
261 if ($this->totalBrokenLink > 0 && (!$this->emailOnBrokenLinkOnly || $this->dif) && !empty($this->email)) {
262 $successfullyExecuted = $this->reportEmail($pageSections, $modTS);
263 }
264 return $successfullyExecuted;
265 }
266
267 /**
268 * Validate all links for a page based on the task configuration
269 *
270 * @param integer $page Uid of the page to parse
271 * @return string $pageSections Content of page section
272 */
273 protected function checkPageLinks($page) {
274 $page = intval($page);
275 $pageSections = '';
276 $pageIds = '';
277 $oldLinkCounts = array();
278 $modTS = $this->loadModTSconfig($page);
279 $searchFields = $this->getSearchField($modTS);
280 $linkTypes = $this->getLinkTypes($modTS);
281 /** @var \TYPO3\CMS\Linkvalidator\LinkAnalyzer $processor */
282 $processor = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Linkvalidator\\LinkAnalyzer');
283 if ($page === 0) {
284 $rootLineHidden = FALSE;
285 } else {
286 $pageRow = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('*', 'pages', 'uid=' . $page);
287 $rootLineHidden = $processor->getRootLineIsHidden($pageRow);
288 }
289 if (!$rootLineHidden || $modTS['checkhidden'] == 1) {
290 $pageIds = $processor->extGetTreeList($page, $this->depth, 0, '1=1', $modTS['checkhidden']);
291 if ($pageRow['hidden'] == 0 || $modTS['checkhidden'] == 1) {
292 // tx_linkvalidator_Processor::extGetTreeList always adds trailing comma:
293 $pageIds .= $page;
294 }
295 }
296 if (!empty($pageIds)) {
297 $processor->init($searchFields, $pageIds);
298 if (!empty($this->email)) {
299 $oldLinkCounts = $processor->getLinkCounts($page);
300 $this->oldTotalBrokenLink += $oldLinkCounts['brokenlinkCount'];
301 }
302 $processor->getLinkStatistics($linkTypes, $modTS['checkhidden']);
303 if (!empty($this->email)) {
304 $linkCounts = $processor->getLinkCounts($page);
305 $this->totalBrokenLink += $linkCounts['brokenlinkCount'];
306 $pageSections = $this->buildMail($page, $pageIds, $linkCounts, $oldLinkCounts);
307 }
308 }
309 return $pageSections;
310 }
311
312 /**
313 * Get the linkvalidator modTSconfig for a page
314 *
315 * @param integer $page Uid of the page
316 * @return array $modTS mod.linkvalidator TSconfig array
317 */
318 protected function loadModTSconfig($page) {
319 $modTS = \TYPO3\CMS\Backend\Utility\BackendUtility::getModTSconfig($page, 'mod.linkvalidator');
320 $parseObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\TypoScript\\Parser\\TypoScriptParser');
321 $parseObj->parse($this->configuration);
322 if (count($parseObj->errors) > 0) {
323 $parseErrorMessage = $GLOBALS['LANG']->sL('LLL:EXT:linkvalidator/locallang.xml:tasks.error.invalidTSconfig') . '<br />';
324 foreach ($parseObj->errors as $errorInfo) {
325 $parseErrorMessage .= $errorInfo[0] . '<br />';
326 }
327 throw new \Exception($parseErrorMessage, '1295476989');
328 }
329 $TSconfig = $parseObj->setup;
330 $modTS = $modTS['properties'];
331 $overrideTs = $TSconfig['mod.']['tx_linkvalidator.'];
332 if (is_array($overrideTs)) {
333 $modTS = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($modTS, $overrideTs);
334 }
335 return $modTS;
336 }
337
338 /**
339 * Get the list of fields to parse in modTSconfig
340 *
341 * @param array $modTS mod.linkvalidator TSconfig array
342 * @return array $searchFields List of fields
343 */
344 protected function getSearchField(array $modTS) {
345 // Get the searchFields from TypoScript
346 foreach ($modTS['searchFields.'] as $table => $fieldList) {
347 $fields = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $fieldList);
348 foreach ($fields as $field) {
349 $searchFields[$table][] = $field;
350 }
351 }
352 return isset($searchFields) ? $searchFields : array();
353 }
354
355 /**
356 * Get the list of linkTypes to parse in modTSconfig
357 *
358 * @param array $modTS mod.linkvalidator TSconfig array
359 * @return array $linkTypes list of link types
360 */
361 protected function getLinkTypes(array $modTS) {
362 $linkTypes = array();
363 $typesTmp = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $modTS['linktypes'], 1);
364 if (is_array($typesTmp)) {
365 if (!empty($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks']) && is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'])) {
366 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'] as $type => $value) {
367 if (in_array($type, $typesTmp)) {
368 $linkTypes[$type] = 1;
369 }
370 }
371 }
372 }
373 return $linkTypes;
374 }
375
376 /**
377 * Build and send warning email when new broken links were found
378 *
379 * @param string $pageSections Content of page section
380 * @param array $modTS TSconfig array
381 * @return boolean TRUE if mail was sent, FALSE if or not
382 */
383 protected function reportEmail($pageSections, array $modTS) {
384 $content = \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart($this->templateMail, '###PAGE_SECTION###', $pageSections);
385 /** @var array $markerArray */
386 $markerArray = array();
387 /** @var array $validEmailList */
388 $validEmailList = array();
389 /** @var boolean $sendEmail */
390 $sendEmail = TRUE;
391 $markerArray['totalBrokenLink'] = $this->totalBrokenLink;
392 $markerArray['totalBrokenLink_old'] = $this->oldTotalBrokenLink;
393 // Hook
394 if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['reportEmailMarkers'])) {
395 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['reportEmailMarkers'] as $userFunc) {
396 $params = array(
397 'pObj' => &$this,
398 'markerArray' => $markerArray
399 );
400 $newMarkers = \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($userFunc, $params, $this);
401 if (is_array($newMarkers)) {
402 $markerArray = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge($markerArray, $newMarkers);
403 }
404 unset($params);
405 }
406 }
407 $content = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($content, $markerArray, '###|###', TRUE, TRUE);
408 /** @var \TYPO3\CMS\Core\Mail\MailMessage $mail */
409 $mail = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Mail\\MailMessage');
410 if (empty($modTS['mail.']['fromemail'])) {
411 $modTS['mail.']['fromemail'] = \TYPO3\CMS\Core\Utility\MailUtility::getSystemFromAddress();
412 }
413 if (empty($modTS['mail.']['fromname'])) {
414 $modTS['mail.']['fromname'] = \TYPO3\CMS\Core\Utility\MailUtility::getSystemFromName();
415 }
416 if (\TYPO3\CMS\Core\Utility\GeneralUtility::validEmail($modTS['mail.']['fromemail'])) {
417 $mail->setFrom(array($modTS['mail.']['fromemail'] => $modTS['mail.']['fromname']));
418 } else {
419 throw new \Exception($GLOBALS['LANG']->sL('LLL:EXT:linkvalidator/locallang.xml:tasks.error.invalidFromEmail'), '1295476760');
420 }
421 if (\TYPO3\CMS\Core\Utility\GeneralUtility::validEmail($modTS['mail.']['replytoemail'])) {
422 $mail->setReplyTo(array($modTS['mail.']['replytoemail'] => $modTS['mail.']['replytoname']));
423 }
424 if (!empty($modTS['mail.']['subject'])) {
425 $mail->setSubject($modTS['mail.']['subject']);
426 } else {
427 throw new \Exception($GLOBALS['LANG']->sL('LLL:EXT:linkvalidator/locallang.xml:tasks.error.noSubject'), '1295476808');
428 }
429 if (!empty($this->email)) {
430 $emailList = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->email);
431 foreach ($emailList as $emailAdd) {
432 if (!\TYPO3\CMS\Core\Utility\GeneralUtility::validEmail($emailAdd)) {
433 throw new \Exception($GLOBALS['LANG']->sL('LLL:EXT:linkvalidator/locallang.xml:tasks.error.invalidToEmail'), '1295476821');
434 } else {
435 $validEmailList[] = $emailAdd;
436 }
437 }
438 }
439 if (is_array($validEmailList) && !empty($validEmailList)) {
440 $mail->setTo($this->email);
441 } else {
442 $sendEmail = FALSE;
443 }
444 if ($sendEmail) {
445 $mail->setBody($content, 'text/html');
446 $mail->send();
447 }
448 return $sendEmail;
449 }
450
451 /**
452 * Build the mail content
453 *
454 * @param int $curPage Id of the current page
455 * @param string $pageList List of pages id
456 * @param array $markerArray Array of markers
457 * @param array $oldBrokenLink Marker array with the number of link found
458 * @return string Content of the mail
459 */
460 protected function buildMail($curPage, $pageList, array $markerArray, array $oldBrokenLink) {
461 $pageSectionHTML = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($this->templateMail, '###PAGE_SECTION###');
462 // Hook
463 if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['buildMailMarkers'])) {
464 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['buildMailMarkers'] as $userFunc) {
465 $params = array(
466 'curPage' => $curPage,
467 'pageList' => $pageList,
468 'markerArray' => $markerArray,
469 'oldBrokenLink' => $oldBrokenLink,
470 'pObj' => &$this
471 );
472 $newMarkers = \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($userFunc, $params, $this);
473 if (is_array($newMarkers)) {
474 $markerArray = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge($markerArray, $newMarkers);
475 }
476 unset($params);
477 }
478 }
479 if (is_array($markerArray)) {
480 foreach ($markerArray as $markerKey => $markerValue) {
481 if (empty($oldBrokenLink[$markerKey])) {
482 $oldBrokenLink[$markerKey] = 0;
483 }
484 if ($markerValue != $oldBrokenLink[$markerKey]) {
485 $this->dif = TRUE;
486 }
487 $markerArray[$markerKey . '_old'] = $oldBrokenLink[$markerKey];
488 }
489 }
490 $markerArray['title'] = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecordTitle('pages', \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('pages', $curPage));
491 $content = '';
492 if ($markerArray['brokenlinkCount'] > 0) {
493 $content = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($pageSectionHTML, $markerArray, '###|###', TRUE, TRUE);
494 }
495 return $content;
496 }
497
498 /**
499 * Simulate cli call with setting the required options to the $_SERVER['argv']
500 *
501 * @return void
502 */
503 protected function setCliArguments() {
504 $_SERVER['argv'] = array(
505 $_SERVER['argv'][0],
506 'tx_link_scheduler_link',
507 '0',
508 '-ss',
509 '--sleepTime',
510 $this->sleepTime,
511 '--sleepAfterFinish',
512 $this->sleepAfterFinish,
513 '--countInARun',
514 $this->countInARun
515 );
516 }
517 }
518 ?>