2 /***************************************************************
5 * (c) 2010 - 2011 Michael Miousse (michael.miousse@infoglobe.ca)
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
17 * This script is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
26 * This class provides Scheduler plugin implementation
28 * @author Michael Miousse <michael.miousse@infoglobe.ca>
30 * @subpackage linkvalidator
32 class tx_linkvalidator_tasks_Validator
extends tx_scheduler_Task
{
42 protected $sleepAfterFinish;
47 protected $countInARun;
50 * Total number of broken links
54 protected $totalBrokenLink = 0;
57 * Total number of broken links from the last run
61 protected $oldTotalBrokenLink = 0;
64 * Mail template fetched from the given template file
68 protected $templateMail;
71 * specific TSconfig for this task.
75 protected $configuration = array();
78 * Shows if number of result was different from the result of the last check or not
85 * Template to be used for the email
89 protected $emailTemplateFile;
92 * Level of pages the task should check
99 * UID of the start page for this task
106 * Email address to which an email report is sent
113 * Only send an email, if new broken links were found
117 protected $emailOnBrokenLinkOnly;
120 * Get the value of the protected property email
122 * @return string Email address to which an email report is sent
124 public function getEmail() {
129 * Set the value of the private property email.
131 * @param string $email Email address to which an email report is sent
134 public function setEmail($email) {
135 $this->email
= $email;
139 * Get the value of the protected property emailOnBrokenLinkOnly
141 * @return boolean Whether to send an email, if new broken links were found
143 public function getEmailOnBrokenLinkOnly() {
144 return $this->emailOnBrokenLinkOnly
;
148 * Set the value of the private property emailOnBrokenLinkOnly
150 * @param boolean $emailOnBrokenLinkOnly Only send an email, if new broken links were found
153 public function setEmailOnBrokenLinkOnly($emailOnBrokenLinkOnly) {
154 $this->emailOnBrokenLinkOnly
= $emailOnBrokenLinkOnly;
158 * Get the value of the protected property page
160 * @return integer UID of the start page for this task
162 public function getPage() {
167 * Set the value of the private property page
169 * @param integer $page UID of the start page for this task.
172 public function setPage($page) {
177 * Get the value of the protected property depth
179 * @return integer Level of pages the task should check
181 public function getDepth() {
186 * Set the value of the private property depth
188 * @param integer $depth Level of pages the task should check
191 public function setDepth($depth) {
192 $this->depth
= $depth;
196 * Get the value of the protected property emailTemplateFile
198 * @return string Template to be used for the email
200 public function getEmailTemplateFile() {
201 return $this->emailTemplateFile
;
205 * Set the value of the private property emailTemplateFile
207 * @param string $emailTemplateFile Template to be used for the email
210 public function setEmailTemplateFile($emailTemplateFile) {
211 $this->emailTemplateFile
= $emailTemplateFile;
215 * Get the value of the protected property configuration
217 * @return array specific TSconfig for this task
219 public function getConfiguration() {
220 return $this->configuration
;
224 * Set the value of the private property configuration
226 * @param array $configuration specific TSconfig for this task
229 public function setConfiguration($configuration) {
230 $this->configuration
= $configuration;
235 * Function execute from the Scheduler
237 * @return boolean TRUE on successful execution, FALSE on error
239 public function execute() {
240 $this->setCliArguments();
241 $successfullyExecuted = TRUE;
242 if (!file_exists($file = t3lib_div
::getFileAbsFileName($this->emailTemplateFile
)) && !empty($this->email
)) {
244 $GLOBALS['LANG']->sL('LLL:EXT:linkvalidator/locallang.xml:tasks.error.invalidEmailTemplateFile'),
248 $htmlFile = t3lib_div
::getURL($file);
249 $this->templateMail
= t3lib_parsehtml
::getSubpart($htmlFile, '###REPORT_TEMPLATE###');
251 // The array to put the content into
255 $pageList = t3lib_div
::trimExplode(',', $this->page
, 1);
256 $modTS = $this->loadModTSconfig($this->page
);
257 if (is_array($pageList)) {
258 foreach ($pageList as $page) {
259 $pageSections .= $this->checkPageLinks($page);
262 if ($this->totalBrokenLink
!= $this->oldTotalBrokenLink
) {
265 if ($this->totalBrokenLink
> 0
266 && (!$this->emailOnBrokenLinkOnly ||
$this->dif
)
267 && !empty($this->email
)
269 $successfullyExecuted = $this->reportEmail($pageSections, $modTS);
271 return $successfullyExecuted;
275 * Validate all links for a page based on the task configuration
277 * @param integer $page Uid of the page to parse
278 * @return string $pageSections Content of page section
280 protected function checkPageLinks($page) {
281 $page = intval($page);
284 $oldLinkCounts = array();
286 $modTS = $this->loadModTSconfig($page);
287 $searchFields = $this->getSearchField($modTS);
288 $linkTypes = $this->getLinkTypes($modTS);
290 /** @var tx_linkvalidator_processor $processor */
291 $processor = t3lib_div
::makeInstance('tx_linkvalidator_Processor');
294 $rootLineHidden = FALSE;
296 $pageRow = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('*', 'pages', 'uid=' . $page);
297 $rootLineHidden = $processor->getRootLineIsHidden($pageRow);
300 if (!$rootLineHidden ||
$modTS['checkhidden'] == 1) {
301 $pageIds = $processor->extGetTreeList($page, $this->depth
, 0, '1=1', $modTS['checkhidden']);
302 if ($pageRow['hidden'] == 0 ||
$modTS['checkhidden'] == 1) {
303 // tx_linkvalidator_Processor::extGetTreeList always adds trailing comma:
308 if (!empty($pageIds)) {
309 $processor->init($searchFields, $pageIds);
311 if (!empty($this->email
)) {
312 $oldLinkCounts = $processor->getLinkCounts($page);
313 $this->oldTotalBrokenLink +
= $oldLinkCounts['brokenlinkCount'];
316 $processor->getLinkStatistics($linkTypes, $modTS['checkhidden']);
318 if (!empty($this->email
)) {
319 $linkCounts = $processor->getLinkCounts($page);
320 $this->totalBrokenLink +
= $linkCounts['brokenlinkCount'];
321 $pageSections = $this->buildMail($page, $pageIds, $linkCounts, $oldLinkCounts);
325 return $pageSections;
329 * Get the linkvalidator modTSconfig for a page
331 * @param integer $page Uid of the page
332 * @return array $modTS mod.linkvalidator TSconfig array
334 protected function loadModTSconfig($page) {
335 $modTS = t3lib_BEfunc
::getModTSconfig($page, 'mod.linkvalidator');
336 $parseObj = t3lib_div
::makeInstance('t3lib_TSparser');
337 $parseObj->parse($this->configuration
);
338 if (count($parseObj->errors
) > 0) {
339 $parseErrorMessage = $GLOBALS['LANG']->sL('LLL:EXT:linkvalidator/locallang.xml:tasks.error.invalidTSconfig') . '<br />';
340 foreach ($parseObj->errors
as $errorInfo) {
341 $parseErrorMessage .= $errorInfo[0] . '<br />';
348 $TSconfig = $parseObj->setup
;
349 $modTS = $modTS['properties'];
350 $overrideTs = $TSconfig['mod.']['tx_linkvalidator.'];
351 if (is_array($overrideTs)) {
352 $modTS = t3lib_div
::array_merge_recursive_overrule($modTS, $overrideTs);
358 * Get the list of fields to parse in modTSconfig
360 * @param array $modTS mod.linkvalidator TSconfig array
361 * @return array $searchFields List of fields
363 protected function getSearchField(array $modTS) {
364 // Get the searchFields from TypoScript
365 foreach ($modTS['searchFields.'] as $table => $fieldList) {
366 $fields = t3lib_div
::trimExplode(',', $fieldList);
367 foreach ($fields as $field) {
368 $searchFields[$table][] = $field;
371 return isset($searchFields) ?
$searchFields : array();
375 * Get the list of linkTypes to parse in modTSconfig
377 * @param array $modTS mod.linkvalidator TSconfig array
378 * @return array $linkTypes list of link types
380 protected function getLinkTypes(array $modTS) {
381 $linkTypes = array();
382 $typesTmp = t3lib_div
::trimExplode(',', $modTS['linktypes'], 1);
383 if (is_array($typesTmp)) {
384 if (!empty($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'])
385 && is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'])) {
386 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['checkLinks'] as $type => $value) {
387 if (in_array($type, $typesTmp)) {
388 $linkTypes[$type] = 1;
397 * Build and send warning email when new broken links were found
399 * @param string $pageSections Content of page section
400 * @param array $modTS TSconfig array
401 * @return boolean TRUE if mail was sent, FALSE if or not
403 protected function reportEmail($pageSections, array $modTS) {
404 $content = t3lib_parsehtml
::substituteSubpart($this->templateMail
, '###PAGE_SECTION###', $pageSections);
405 /** @var array $markerArray */
406 $markerArray = array();
407 /** @var array $validEmailList */
408 $validEmailList = array();
409 /** @var boolean $sendEmail */
412 $markerArray['totalBrokenLink'] = $this->totalBrokenLink
;
413 $markerArray['totalBrokenLink_old'] = $this->oldTotalBrokenLink
;
416 if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['reportEmailMarkers'])) {
417 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['reportEmailMarkers'] as $userFunc) {
420 'markerArray' => $markerArray,
422 $newMarkers = t3lib_div
::callUserFunction($userFunc, $params, $this);
423 if (is_array($newMarkers)) {
424 $markerArray = t3lib_div
::array_merge($markerArray, $newMarkers);
430 $content = t3lib_parsehtml
::substituteMarkerArray($content, $markerArray, '###|###', TRUE, TRUE);
432 /** @var t3lib_mail_Message $mail */
433 $mail = t3lib_div
::makeInstance('t3lib_mail_Message');
434 if (empty($modTS['mail.']['fromemail'])) {
435 $modTS['mail.']['fromemail'] = t3lib_utility_Mail
::getSystemFromAddress();
437 if (empty($modTS['mail.']['fromname'])) {
438 $modTS['mail.']['fromname'] = t3lib_utility_Mail
::getSystemFromName();
440 if (t3lib_div
::validEmail($modTS['mail.']['fromemail'])) {
441 $mail->setFrom(array($modTS['mail.']['fromemail'] => $modTS['mail.']['fromname']));
444 $GLOBALS['LANG']->sL('LLL:EXT:linkvalidator/locallang.xml:tasks.error.invalidFromEmail'),
448 if (t3lib_div
::validEmail($modTS['mail.']['replytoemail'])) {
449 $mail->setReplyTo(array($modTS['mail.']['replytoemail'] => $modTS['mail.']['replytoname']));
452 if (!empty($modTS['mail.']['subject'])) {
453 $mail->setSubject($modTS['mail.']['subject']);
456 $GLOBALS['LANG']->sL('LLL:EXT:linkvalidator/locallang.xml:tasks.error.noSubject'),
460 if (!empty($this->email
)) {
461 $emailList = t3lib_div
::trimExplode(',', $this->email
);
462 foreach ($emailList as $emailAdd) {
463 if (!t3lib_div
::validEmail($emailAdd)) {
465 $GLOBALS['LANG']->sL('LLL:EXT:linkvalidator/locallang.xml:tasks.error.invalidToEmail'),
469 $validEmailList[] = $emailAdd;
473 if (is_array($validEmailList) && !empty($validEmailList)) {
474 $mail->setTo($this->email
);
480 $mail->setBody($content, 'text/html');
489 * Build the mail content
491 * @param int $curPage Id of the current page
492 * @param string $pageList List of pages id
493 * @param array $markerArray Array of markers
494 * @param array $oldBrokenLink Marker array with the number of link found
495 * @return string Content of the mail
497 protected function buildMail($curPage, $pageList, array $markerArray, array $oldBrokenLink) {
498 $pageSectionHTML = t3lib_parsehtml
::getSubpart($this->templateMail
, '###PAGE_SECTION###');
501 if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['buildMailMarkers'])) {
502 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['buildMailMarkers'] as $userFunc) {
504 'curPage' => $curPage,
505 'pageList' => $pageList,
506 'markerArray' => $markerArray,
507 'oldBrokenLink' => $oldBrokenLink,
510 $newMarkers = t3lib_div
::callUserFunction($userFunc, $params, $this);
511 if (is_array($newMarkers)) {
512 $markerArray = t3lib_div
::array_merge($markerArray, $newMarkers);
518 if (is_array($markerArray)) {
519 foreach ($markerArray as $markerKey => $markerValue) {
520 if (empty($oldBrokenLink[$markerKey])) {
521 $oldBrokenLink[$markerKey] = 0;
523 if ($markerValue != $oldBrokenLink[$markerKey]) {
526 $markerArray[$markerKey . '_old'] = $oldBrokenLink[$markerKey];
529 $markerArray['title'] = t3lib_BEfunc
::getRecordTitle('pages', t3lib_BEfunc
::getRecord('pages', $curPage));
532 if ($markerArray['brokenlinkCount'] > 0) {
533 $content = t3lib_parsehtml
::substituteMarkerArray($pageSectionHTML, $markerArray, '###|###', TRUE, TRUE);
540 * Simulate cli call with setting the required options to the $_SERVER['argv']
544 protected function setCliArguments() {
545 $_SERVER['argv'] = array(
547 'tx_link_scheduler_link',
552 '--sleepAfterFinish',
553 $this->sleepAfterFinish
,
560 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE
]['XCLASS']['ext/linkvalidator/classes/tasks/class.tx_linkvalidator_tasks_validator.php'])) {
561 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE
]['XCLASS']['ext/linkvalidator/classes/tasks/class.tx_linkvalidator_tasks_validator.php']);