diff --git a/Classes/scheduler/AdditionalFieldsProvider.php b/Classes/scheduler/AdditionalFieldsProvider.php index 41d7595..09e0999 100644 --- a/Classes/scheduler/AdditionalFieldsProvider.php +++ b/Classes/scheduler/AdditionalFieldsProvider.php @@ -1,209 +1,237 @@ - -* All rights reserved -* -* This script is part of the TYPO3 project. The TYPO3 project is -* free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* The GNU General Public License can be found at -* http://www.gnu.org/copyleft/gpl.html. -* -* This script is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* This copyright notice MUST APPEAR in all copies of the script! -***************************************************************/ - -namespace DmitryDulepov\DdGooglesitemap\Scheduler; - -use TYPO3\CMS\Core\Utility\GeneralUtility; - -/** - * This class provides information about additional fields for the scheduler - * task of this extension. Additional fields are: - * - the URL of the eID script (users can use different parameters for the script!) - * - index file path (users will submit that to Google) - * - maximum number of URLs in the sitemap (to prevent out of memory errors) - * - * WARNING! Due to incompatible TYPO3 6.2 changes this class now shows PHP errors - * in TYPO3 4.5 and TYPO3 6.2 in the PhpStorm. These errors however do not happen - * at runtime. - * - * @author Dmitry Dulepov - */ -class AdditionalFieldsProvider implements \TYPO3\CMS\Scheduler\AdditionalFieldProviderInterface { - - /** - * Gets additional fields to render in the form to add/edit a task - * - * @param array $taskInfo Values of the fields from the add/edit task form - * @param \TYPO3\CMS\Scheduler\Task\AbstractTask $task The task object being edited. Null when adding a task! - * @param \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $schedulerModule Reference to the scheduler backend module - * @return array A two dimensional array, array('Identifier' => array('fieldId' => array('code' => '', 'label' => '', 'cshKey' => '', 'cshLabel' => '')) - */ - public function getAdditionalFields(array &$taskInfo, $task, \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $schedulerModule) { - /** @var \DmitryDulepov\DdGooglesitemap\Scheduler\Task $task */ - $additionalFields = array(); - - if (!$task) { - $url = GeneralUtility::locationHeaderUrl('/index.php?eID=dd_googlesitemap'); - $task = GeneralUtility::makeInstance('DmitryDulepov\\DdGooglesitemap\\Scheduler\\Task'); - } - else { - $url = $task->getEIdScriptUrl(); - } - $indexFilePath = $task->getIndexFilePath(); - $maxUrlsPerSitemap = $task->getMaxUrlsPerSitemap(); - - $additionalFields['eIdUrl'] = array( - 'code' => '', - 'label' => 'LLL:EXT:dd_googlesitemap/locallang.xml:scheduler.eIDFieldLabel', - 'cshKey' => '', - 'cshLabel' => '' - ); - $additionalFields['indexFilePath'] = array( - 'code' => '', - 'label' => 'LLL:EXT:dd_googlesitemap/locallang.xml:scheduler.indexFieldLabel', - 'cshKey' => '', - 'cshLabel' => '' - ); - $additionalFields['maxUrlsPerSitemap'] = array( - 'code' => '', - 'label' => 'LLL:EXT:dd_googlesitemap/locallang.xml:scheduler.maxUrlsPerSitemapLabel', - 'cshKey' => '', - 'cshLabel' => '' - ); - - return $additionalFields; - } - - /** - * Validates the additional fields' values - * - * @param array $submittedData An array containing the data submitted by the add/edit task form - * @param \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $schedulerModule Reference to the scheduler backend module - * @return boolean TRUE if validation was ok (or selected class is not relevant), FALSE otherwise - */ - public function validateAdditionalFields(array &$submittedData, \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $schedulerModule) { - $errors = array(); - - $this->validateEIdUrl($submittedData, $errors); - $this->validateMaxUrlsPerSitemap($submittedData, $errors); - $this->validateIndexFilePath($submittedData, $errors); - - foreach ($errors as $error) { - /** @noinspection PhpUndefinedMethodInspection */ - $error = $GLOBALS['LANG']->sL('LLL:EXT:dd_googlesitemap/locallang.xml:' . $error); - $this->addErrorMessage($error); - } - - return count($errors) == 0; - } - - /** - * Takes care of saving the additional fields' values in the task's object - * - * @param array $submittedData An array containing the data submitted by the add/edit task form - * @param \TYPO3\CMS\Scheduler\Task\AbstractTask $task Reference to the scheduler backend module - * @return void - */ - public function saveAdditionalFields(array $submittedData, \TYPO3\CMS\Scheduler\Task\AbstractTask $task) { - /** @var \DmitryDulepov\DdGooglesitemap\Scheduler\Task $task */ - $task->setEIdScriptUrl($submittedData['eIdUrl']); - $task->setMaxUrlsPerSitemap($submittedData['maxUrlsPerSitemap']); - $task->setIndexFilePath($submittedData['indexFilePath']); - } - - /** - * Adds a error message as a flash message. - * - * @param string $message - * @return void - */ - protected function addErrorMessage($message) { - $flashMessage = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessage', - $message, '', \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR - ); - /** @var \TYPO3\CMS\Core\Messaging\FlashMessage $flashMessage */ - $flashMessageService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessageService'); - /** @var \TYPO3\CMS\Core\Messaging\FlashMessageService $flashMessageService */ - $flashMessageService->getMessageQueueByIdentifier()->enqueue($flashMessage); - } - - /** - * Validates the number of urls per sitemap. - * - * @param array $submittedData - * @param array $errors - * @return void - */ - protected function validateMaxUrlsPerSitemap(array &$submittedData, array &$errors) { - $submittedData['maxUrlsPerSitemap'] = intval($submittedData['maxUrlsPerSitemap']); - if ($submittedData['maxUrlsPerSitemap'] <= 0) { - $errors[] = 'scheduler.error.badNumberOfUrls'; - } - } - - /** - * Validates index file path. - * - * @param array $submittedData - * @param array $errors - * @return void - */ - protected function validateIndexFilePath(array &$submittedData, array &$errors) { - if (GeneralUtility::isAbsPath($submittedData['indexFilePath'])) { - $errors[] = 'scheduler.error.badIndexFilePath'; - } - else { - $testPath = GeneralUtility::getFileAbsFileName($submittedData['indexFilePath'], TRUE); - if (!file_exists($testPath)) { - if (!@touch($testPath)) { - $errors[] = 'scheduler.error.badIndexFilePath'; - } - else { - unlink($testPath); - } - } - } - } - - /** - * Valies the URL of the eID script. - * - * @param array $submittedData - * @param array $errors - */ - protected function validateEIdUrl(array &$submittedData, array &$errors) { - foreach (GeneralUtility::trimExplode(chr(10), $submittedData['eIdUrl']) as $url) { - if (FALSE !== ($urlParts = parse_url($url))) { - if (!$urlParts['host']) { - $errors[] = 'scheduler.error.missingHost'; - } - else { - /** @noinspection PhpUndefinedMethodInspection */ - list($count) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('COUNT(*) AS counter', 'sys_domain', - 'domainName=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($urlParts['host'], 'sys_domain') - ); - if ($count['counter'] == 0) { - $errors[] = 'scheduler.error.missingHost'; - } - } - if (!preg_match('/(?:^|&)eID=dd_googlesitemap/', $urlParts['query'])) { - $errors[] = 'scheduler.error.badPath'; - } - if (preg_match('/(?:^|&)(?:offset|limit)=/', $urlParts['query'])) { - $errors[] = 'scheduler.error.badParameters'; - } - } - } - } -} + +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +namespace DmitryDulepov\DdGooglesitemap\Scheduler; + +use TYPO3\CMS\Core\Utility\GeneralUtility; + +/** + * This class provides information about additional fields for the scheduler + * task of this extension. Additional fields are: + * - the URL of the eID script (users can use different parameters for the script!) + * - index file path (users will submit that to Google) + * - maximum number of URLs in the sitemap (to prevent out of memory errors) + * + * WARNING! Due to incompatible TYPO3 6.2 changes this class now shows PHP errors + * in TYPO3 4.5 and TYPO3 6.2 in the PhpStorm. These errors however do not happen + * at runtime. + * + * @author Dmitry Dulepov + */ +class AdditionalFieldsProvider implements \TYPO3\CMS\Scheduler\AdditionalFieldProviderInterface { + + /** + * Gets additional fields to render in the form to add/edit a task + * + * @param array $taskInfo Values of the fields from the add/edit task form + * @param \TYPO3\CMS\Scheduler\Task\AbstractTask $task The task object being edited. Null when adding a task! + * @param \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $schedulerModule Reference to the scheduler backend module + * @return array A two dimensional array, array('Identifier' => array('fieldId' => array('code' => '', 'label' => '', 'cshKey' => '', 'cshLabel' => '')) + */ + public function getAdditionalFields(array &$taskInfo, $task, \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $schedulerModule) { + /** @var \DmitryDulepov\DdGooglesitemap\Scheduler\Task $task */ + $additionalFields = array(); + + if (!$task) { + $url = GeneralUtility::locationHeaderUrl('/index.php?eID=dd_googlesitemap'); + $task = GeneralUtility::makeInstance('DmitryDulepov\\DdGooglesitemap\\Scheduler\\Task'); + } + else { + $url = $task->getEIdScriptUrl(); + } + $indexFilePath = $task->getIndexFilePath(); + $maxUrlsPerSitemap = $task->getMaxUrlsPerSitemap(); + + $additionalFields['domainRecord'] = array( + 'code' => '', + 'label' => 'LLL:EXT:dd_googlesitemap/locallang.xml:scheduler.domainRecordLabel', + 'cshKey' => '', + 'cshLabel' => '' + ); + $additionalFields['eIdUrl'] = array( + 'code' => '', + 'label' => 'LLL:EXT:dd_googlesitemap/locallang.xml:scheduler.eIDFieldLabel', + 'cshKey' => '', + 'cshLabel' => '' + ); + $additionalFields['indexFilePath'] = array( + 'code' => '', + 'label' => 'LLL:EXT:dd_googlesitemap/locallang.xml:scheduler.indexFieldLabel', + 'cshKey' => '', + 'cshLabel' => '' + ); + $additionalFields['maxUrlsPerSitemap'] = array( + 'code' => '', + 'label' => 'LLL:EXT:dd_googlesitemap/locallang.xml:scheduler.maxUrlsPerSitemapLabel', + 'cshKey' => '', + 'cshLabel' => '' + ); + + return $additionalFields; + } + + /** + * Validates the additional fields' values + * + * @param array $submittedData An array containing the data submitted by the add/edit task form + * @param \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $schedulerModule Reference to the scheduler backend module + * @return boolean TRUE if validation was ok (or selected class is not relevant), FALSE otherwise + */ + public function validateAdditionalFields(array &$submittedData, \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $schedulerModule) { + $errors = array(); + + $this->validateDomainRecord($submittedData, $errors); + $this->validateEIdUrl($submittedData, $errors); + $this->validateMaxUrlsPerSitemap($submittedData, $errors); + $this->validateIndexFilePath($submittedData, $errors); + + foreach ($errors as $error) { + /** @noinspection PhpUndefinedMethodInspection */ + $error = $GLOBALS['LANG']->sL('LLL:EXT:dd_googlesitemap/locallang.xml:' . $error); + $this->addErrorMessage($error); + } + + return count($errors) == 0; + } + + /** + * Takes care of saving the additional fields' values in the task's object + * + * @param array $submittedData An array containing the data submitted by the add/edit task form + * @param \TYPO3\CMS\Scheduler\Task\AbstractTask $task Reference to the scheduler backend module + * @return void + */ + public function saveAdditionalFields(array $submittedData, \TYPO3\CMS\Scheduler\Task\AbstractTask $task) { + /** @var \DmitryDulepov\DdGooglesitemap\Scheduler\Task $task */ + $task->setDomainRecordId($submittedData['domainRecord']); + $task->setEIdScriptUrl($submittedData['eIdUrl']); + $task->setMaxUrlsPerSitemap($submittedData['maxUrlsPerSitemap']); + $task->setIndexFilePath($submittedData['indexFilePath']); + } + + /** + * Adds a error message as a flash message. + * + * @param string $message + * @return void + */ + protected function addErrorMessage($message) { + $flashMessage = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessage', + $message, '', \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR + ); + /** @var \TYPO3\CMS\Core\Messaging\FlashMessage $flashMessage */ + $flashMessageService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessageService'); + /** @var \TYPO3\CMS\Core\Messaging\FlashMessageService $flashMessageService */ + $flashMessageService->getMessageQueueByIdentifier()->enqueue($flashMessage); + } + + /** + * Validates the domain record. + * + * @param array $submittedData + * @param array $errors + */ + protected function validateDomainRecord(array &$submittedData, array &$errors) { + if (FALSE === empty($submittedData['domainRecord']) + || NULL === $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('uid', 'sys_domain', 'uid ='. intval($submittedData['domainRecord'])) ) { + + $errors[] = 'scheduler.error.missingHost'; + } + } + + /** + * Validates the number of urls per sitemap. + * + * @param array $submittedData + * @param array $errors + * @return void + */ + protected function validateMaxUrlsPerSitemap(array &$submittedData, array &$errors) { + $submittedData['maxUrlsPerSitemap'] = intval($submittedData['maxUrlsPerSitemap']); + if ($submittedData['maxUrlsPerSitemap'] <= 0) { + $errors[] = 'scheduler.error.badNumberOfUrls'; + } + } + + /** + * Validates index file path. + * + * @param array $submittedData + * @param array $errors + * @return void + */ + protected function validateIndexFilePath(array &$submittedData, array &$errors) { + if (GeneralUtility::isAbsPath($submittedData['indexFilePath'])) { + $errors[] = 'scheduler.error.badIndexFilePath'; + } + else { + $testPath = GeneralUtility::getFileAbsFileName($submittedData['indexFilePath'], TRUE); + if (!file_exists($testPath)) { + if (!@touch($testPath)) { + $errors[] = 'scheduler.error.badIndexFilePath'; + } + else { + unlink($testPath); + } + } + } + } + + /** + * Valies the URL of the eID script. + * + * @param array $submittedData + * @param array $errors + */ + protected function validateEIdUrl(array &$submittedData, array &$errors) { + foreach (GeneralUtility::trimExplode(chr(10), $submittedData['eIdUrl']) as $url) { + if (FALSE !== ($urlParts = parse_url($url))) { + if (!preg_match('/(?:^|&)eID=dd_googlesitemap/', $urlParts['query'])) { + $errors[] = 'scheduler.error.badPath'; + } + if (preg_match('/(?:^|&)(?:offset|limit)=/', $urlParts['query'])) { + $errors[] = 'scheduler.error.badParameters'; + } + } + } + } + + /** + * Generate selectbox items + * @param integer $selectedRecord + * @return string + */ + protected function buildSelectItems($selectedRecord) { + $availableDomainRecords = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,domainName', 'sys_domain', '1=1', '', 'domainName ASC'); + $list = array(''); + + if(NULL !== $availableDomainRecords) { + foreach($availableDomainRecords as $record) { + $selected = ($record['uid'] == $selectedRecord) ? ' selected="selected"': ''; + $list[] = ''; + } + } + return implode('', $list); + } +} diff --git a/Classes/scheduler/Task.php b/Classes/scheduler/Task.php index e1ea9fa..d9b07af 100644 --- a/Classes/scheduler/Task.php +++ b/Classes/scheduler/Task.php @@ -1,300 +1,318 @@ - -* All rights reserved -* -* This script is part of the TYPO3 project. The TYPO3 project is -* free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* The GNU General Public License can be found at -* http://www.gnu.org/copyleft/gpl.html. -* -* This script is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* This copyright notice MUST APPEAR in all copies of the script! -***************************************************************/ - -namespace DmitryDulepov\DdGooglesitemap\Scheduler; - -use TYPO3\CMS\Core\Utility\GeneralUtility; - -/** - * This class provides a scheduler task to create sitemap index as required - * by the Google sitemap protocol. - * - * @author Dmitry Dulepov - * @see http://support.google.com/webmasters/bin/answer.py?hl=en&answer=71453 - */ -class Task extends \TYPO3\CMS\Scheduler\Task\AbstractTask { - - const DEFAULT_FILE_PATH = 'typo3temp/dd_googlesitemap'; - - /** @var string */ - private $baseUrl; - - /** @var string */ - protected $eIdScriptUrl; - - /** @var string */ - protected $indexFilePath; - - /** @var int */ - protected $maxUrlsPerSitemap = 50000; - - /** @var string */ - private $sitemapFileFormat; - - /** @var int */ - private $offset; - - /** - * Creates the instance of the class. This call initializes the index file - * path to the random value. After the task is configured, the user may - * change the file and the file name will be serialized with the task and - * used later. - * - * @see __sleep - */ - public function __construct() { - parent::__construct(); - $this->indexFilePath = self::DEFAULT_FILE_PATH . '/' . GeneralUtility::getRandomHexString(24) . '.xml'; - } - - /** - * Reconstructs some variables after the object is unserialized. - * - * @return void - */ - public function __wakeup() { - $this->buildSitemapFileFormat(); - $this->buildBaseUrl(); - } - - /** - * This is the main method that is called when a task is executed - * It MUST be implemented by all classes inheriting from this one - * Note that there is no error handling, errors and failures are expected - * to be handled and logged by the client implementations. - * Should return true on successful execution, false on error. - * - * @return boolean Returns true on successful execution, false on error - */ - public function execute() { - $indexFilePathTemp = PATH_site . $this->indexFilePath . '.tmp'; - $indexFile = fopen($indexFilePathTemp, 'wt'); - fwrite($indexFile, '' . chr(10)); - fwrite($indexFile, '' . chr(10)); - - $eIDscripts = GeneralUtility::trimExplode(chr(10), $this->eIdScriptUrl); - $eIdIndex = 1; - foreach ($eIDscripts as $eIdScriptUrl) { - $this->offset = 0; - $currentFileNumber = 1; - $lastFileHash = ''; - do { - $sitemapFileName = sprintf($this->sitemapFileFormat, $eIdIndex, $currentFileNumber++); - $this->buildSitemap($eIdScriptUrl, $sitemapFileName); - - $isSitemapEmpty = $this->isSitemapEmpty($sitemapFileName); - $currentFileHash = md5_file(PATH_site . $sitemapFileName); - $stopLoop = $isSitemapEmpty || ($currentFileHash == $lastFileHash); - - if ($stopLoop) { - @unlink(PATH_site . $sitemapFileName); - } - else { - fwrite($indexFile, '' . htmlspecialchars($this->makeSitemapUrl($sitemapFileName)) . '' . chr(10)); - $lastFileHash = $currentFileHash; - } - } while (!$stopLoop); - $eIdIndex++; - } - - fwrite($indexFile, '' . chr(10)); - fclose($indexFile); - - @unlink(PATH_site . $this->indexFilePath); - rename($indexFilePathTemp, PATH_site . $this->indexFilePath); - - return true; - } - - /** - * This method is designed to return some additional information about the task, - * that may help to set it apart from other tasks from the same class - * This additional information is used - for example - in the Scheduler's BE module - * This method should be implemented in most task classes - * - * @return string Information to display - */ - public function getAdditionalInformation() { - /** @noinspection PhpUndefinedMethodInspection */ - $format = $GLOBALS['LANG']->sL('LLL:EXT:dd_googlesitemap/locallang.xml:scheduler.extra_info'); - return sprintf($format, $this->getIndexFileUrl()); - } - - /** - * Sets the url of the eID script. This is called from the task - * configuration inside scheduler. - * - * @return string - * @see tx_ddgooglesitemap_additionalfieldsprovider - */ - public function getEIdScriptUrl() { - return $this->eIdScriptUrl; - } - - /** - * Returns the index file path. This is called from the task - * configuration inside scheduler. - * - * @return string - * @see tx_ddgooglesitemap_additionalfieldsprovider - */ - public function getIndexFilePath() { - return $this->indexFilePath; - } - - /** - * Obtains the number of urls per sitemap. This is called from the task - * configuration inside scheduler. - * - * @return int - * @see tx_ddgooglesitemap_additionalfieldsprovider - */ - public function getMaxUrlsPerSitemap() { - return $this->maxUrlsPerSitemap; - } - - /** - * Sets the URl of the eID script. This is called from the task - * configuration inside scheduler. - * - * @param $url - * @see tx_ddgooglesitemap_additionalfieldsprovider - */ - public function setEIdScriptUrl($url) { - $this->eIdScriptUrl = $url; - } - - /** - * Sets the URL of the eID script. This is called from the task - * configuration inside scheduler. - * - * @param string $path - * @see tx_ddgooglesitemap_additionalfieldsprovider - */ - public function setIndexFilePath($path) { - $this->indexFilePath = $path; - } - - /** - * Sets the number of URLs per sitemap. This is called from the task - * configuration inside scheduler. - * - * @param int $maxUrlsPerSitemap - * @see tx_ddgooglesitemap_additionalfieldsprovider - */ - public function setMaxUrlsPerSitemap($maxUrlsPerSitemap) { - $this->maxUrlsPerSitemap = $maxUrlsPerSitemap; - } - - /** - * Creates a base url for sitemaps. - * - * @return void - */ - protected function buildBaseUrl() { - $urlParts = parse_url($this->eIdScriptUrl); - $this->baseUrl = $urlParts['scheme'] . '://'; - if ($urlParts['user']) { - $this->baseUrl .= $urlParts['user']; - if ($urlParts['pass']) { - $this->baseUrl .= ':' . $urlParts['pass']; - } - $this->baseUrl .= '@'; - } - $this->baseUrl .= $urlParts['host']; - if ($urlParts['port']) { - $this->baseUrl .= ':' . $urlParts['port']; - } - $this->baseUrl .= '/'; - } - - /** - * Builds the sitemap. - * - * @param string $eIdScriptUrl - * @param string $sitemapFileName - * @see tx_ddgooglesitemap_additionalfieldsprovider - */ - protected function buildSitemap($eIdScriptUrl, $sitemapFileName) { - $url = $eIdScriptUrl . sprintf('&offset=%d&limit=%d', $this->offset, $this->maxUrlsPerSitemap); - - $content = GeneralUtility::getURL($url); - if ($content) { - file_put_contents(PATH_site . $sitemapFileName, $content); - $this->offset += $this->maxUrlsPerSitemap; - } - } - - /** - * Creates the format string for the sitemap files. - * - * @return void - */ - protected function buildSitemapFileFormat() { - $fileParts = pathinfo($this->indexFilePath); - $this->sitemapFileFormat = $fileParts['dirname'] . '/' . $fileParts['filename'] . '_sitemap_%05d_%05d.xml'; - } - - /** - * Returns the index file url. - * - * @return string - */ - protected function getIndexFileUrl() { - return $this->baseUrl . $this->indexFilePath; - } - - /** - * Checks if the current sitemap has no entries. The function reads a chunk - * of the file, which is large enough to have a '' token in it and - * examines the chunk. If the token is not found, than the sitemap is either - * empty or corrupt. - * - * @param string $sitemapFileName - * @return bool - */ - protected function isSitemapEmpty($sitemapFileName) { - $result = TRUE; - - $fileDescriptor = @fopen(PATH_site . $sitemapFileName, 'rt'); - if ($fileDescriptor) { - $chunkSizeToCheck = 10240; - $testString = fread($fileDescriptor, $chunkSizeToCheck); - fclose($fileDescriptor); - $result = (strpos($testString, '') === FALSE); - } - - return $result; - } - - /** - * Creates a url to the sitemap. - * - * @param string $siteMapPath - * @return string - */ - protected function makeSitemapUrl($siteMapPath) { - return $this->baseUrl . $siteMapPath; - } -} + +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +namespace DmitryDulepov\DdGooglesitemap\Scheduler; + +use TYPO3\CMS\Core\Utility\GeneralUtility; + +/** + * This class provides a scheduler task to create sitemap index as required + * by the Google sitemap protocol. + * + * @author Dmitry Dulepov + * @see http://support.google.com/webmasters/bin/answer.py?hl=en&answer=71453 + */ +class Task extends \TYPO3\CMS\Scheduler\Task\AbstractTask { + + const DEFAULT_FILE_PATH = 'typo3temp/dd_googlesitemap'; + + /** @var string */ + private $urlScheme = 'http'; + + /** @var string */ + private $baseUrl; + + /** @var integer */ + protected $domainRecordId; + + /** @var string */ + protected $eIdScriptUrl; + + /** @var string */ + protected $indexFilePath; + + /** @var int */ + protected $maxUrlsPerSitemap = 50000; + + /** @var string */ + private $sitemapFileFormat; + + /** @var int */ + private $offset; + + /** + * Creates the instance of the class. This call initializes the index file + * path to the random value. After the task is configured, the user may + * change the file and the file name will be serialized with the task and + * used later. + * + * @see __sleep + */ + public function __construct() { + parent::__construct(); + $this->indexFilePath = self::DEFAULT_FILE_PATH . '/' . GeneralUtility::getRandomHexString(24) . '.xml'; + } + + /** + * Reconstructs some variables after the object is unserialized. + * + * @return void + */ + public function __wakeup() { + $this->buildSitemapFileFormat(); + $this->buildBaseUrl(); + } + + /** + * This is the main method that is called when a task is executed + * It MUST be implemented by all classes inheriting from this one + * Note that there is no error handling, errors and failures are expected + * to be handled and logged by the client implementations. + * Should return true on successful execution, false on error. + * + * @return boolean Returns true on successful execution, false on error + */ + public function execute() { + $indexFilePathTemp = PATH_site . $this->indexFilePath . '.tmp'; + $indexFile = fopen($indexFilePathTemp, 'wt'); + fwrite($indexFile, '' . chr(10)); + fwrite($indexFile, '' . chr(10)); + + $eIDscripts = GeneralUtility::trimExplode(chr(10), $this->eIdScriptUrl); + $eIdIndex = 1; + foreach ($eIDscripts as $eIdScriptUrl) { + $this->offset = 0; + $currentFileNumber = 1; + $lastFileHash = ''; + do { + $sitemapFileName = sprintf($this->sitemapFileFormat, $eIdIndex, $currentFileNumber++); + $this->buildSitemap($eIdScriptUrl, $sitemapFileName); + + $isSitemapEmpty = $this->isSitemapEmpty($sitemapFileName); + $currentFileHash = md5_file(PATH_site . $sitemapFileName); + $stopLoop = $isSitemapEmpty || ($currentFileHash == $lastFileHash); + + if ($stopLoop) { + @unlink(PATH_site . $sitemapFileName); + } + else { + fwrite($indexFile, '' . htmlspecialchars($this->makeSitemapUrl($sitemapFileName)) . '' . chr(10)); + $lastFileHash = $currentFileHash; + } + } while (!$stopLoop); + $eIdIndex++; + } + + fwrite($indexFile, '' . chr(10)); + fclose($indexFile); + + @unlink(PATH_site . $this->indexFilePath); + rename($indexFilePathTemp, PATH_site . $this->indexFilePath); + + return true; + } + + /** + * This method is designed to return some additional information about the task, + * that may help to set it apart from other tasks from the same class + * This additional information is used - for example - in the Scheduler's BE module + * This method should be implemented in most task classes + * + * @return string Information to display + */ + public function getAdditionalInformation() { + /** @noinspection PhpUndefinedMethodInspection */ + $format = $GLOBALS['LANG']->sL('LLL:EXT:dd_googlesitemap/locallang.xml:scheduler.extra_info'); + return sprintf($format, $this->getIndexFileUrl()); + } + + /** + * Sets the domain record for eID script. This is called from the task + * configuration inside scheduler. + * + * @return string + * @see tx_ddgooglesitemap_additionalfieldsprovider + */ + public function getDomainRecordId() { + return $this->domainRecordId; + } + + /** + * Sets the url of the eID script. This is called from the task + * configuration inside scheduler. + * + * @return string + * @see tx_ddgooglesitemap_additionalfieldsprovider + */ + public function getEIdScriptUrl() { + return $this->eIdScriptUrl; + } + + /** + * Returns the index file path. This is called from the task + * configuration inside scheduler. + * + * @return string + * @see tx_ddgooglesitemap_additionalfieldsprovider + */ + public function getIndexFilePath() { + return $this->indexFilePath; + } + + /** + * Obtains the number of urls per sitemap. This is called from the task + * configuration inside scheduler. + * + * @return int + * @see tx_ddgooglesitemap_additionalfieldsprovider + */ + public function getMaxUrlsPerSitemap() { + return $this->maxUrlsPerSitemap; + } + + /** + * Sets the domain record uid. This is called from the task + * configuration inside scheduler. + * + * @param $uid + * @see tx_ddgooglesitemap_additionalfieldsprovider + */ + public function setDomainRecordId($uid) { + $this->domainRecordId = $uid; + } + + /** + * Sets the URl of the eID script. This is called from the task + * configuration inside scheduler. + * + * @param $url + * @see tx_ddgooglesitemap_additionalfieldsprovider + */ + public function setEIdScriptUrl($url) { + $this->eIdScriptUrl = $url; + } + + /** + * Sets the URL of the eID script. This is called from the task + * configuration inside scheduler. + * + * @param string $path + * @see tx_ddgooglesitemap_additionalfieldsprovider + */ + public function setIndexFilePath($path) { + $this->indexFilePath = $path; + } + + /** + * Sets the number of URLs per sitemap. This is called from the task + * configuration inside scheduler. + * + * @param int $maxUrlsPerSitemap + * @see tx_ddgooglesitemap_additionalfieldsprovider + */ + public function setMaxUrlsPerSitemap($maxUrlsPerSitemap) { + $this->maxUrlsPerSitemap = $maxUrlsPerSitemap; + } + + /** + * Creates a base url for sitemaps. + * + * @return void + */ + protected function buildBaseUrl() { + // Sure there are better solutions :) + if(NULL !== $row = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('domainName', 'sys_domain', 'uid ='. intval($this->domainRecordId) )) { + $this->baseUrl = $this->urlScheme . $row['domainName'] .'/'; + } + } + + /** + * Builds the sitemap. + * + * @param string $eIdScriptUrl + * @param string $sitemapFileName + * @see tx_ddgooglesitemap_additionalfieldsprovider + */ + protected function buildSitemap($eIdScriptUrl, $sitemapFileName) { + $url = $this->baseUrl . $eIdScriptUrl . sprintf('&offset=%d&limit=%d', $this->offset, $this->maxUrlsPerSitemap); + + $content = GeneralUtility::getURL($url); + if ($content) { + file_put_contents(PATH_site . $sitemapFileName, $content); + $this->offset += $this->maxUrlsPerSitemap; + } + } + + /** + * Creates the format string for the sitemap files. + * + * @return void + */ + protected function buildSitemapFileFormat() { + $fileParts = pathinfo($this->indexFilePath); + $this->sitemapFileFormat = $fileParts['dirname'] . '/' . $fileParts['filename'] . '_sitemap_%05d_%05d.xml'; + } + + /** + * Returns the index file url. + * + * @return string + */ + protected function getIndexFileUrl() { + return $this->baseUrl . $this->indexFilePath; + } + + /** + * Checks if the current sitemap has no entries. The function reads a chunk + * of the file, which is large enough to have a '' token in it and + * examines the chunk. If the token is not found, than the sitemap is either + * empty or corrupt. + * + * @param string $sitemapFileName + * @return bool + */ + protected function isSitemapEmpty($sitemapFileName) { + $result = TRUE; + + $fileDescriptor = @fopen(PATH_site . $sitemapFileName, 'rt'); + if ($fileDescriptor) { + $chunkSizeToCheck = 10240; + $testString = fread($fileDescriptor, $chunkSizeToCheck); + fclose($fileDescriptor); + $result = (strpos($testString, '') === FALSE); + } + + return $result; + } + + /** + * Creates a url to the sitemap. + * + * @param string $siteMapPath + * @return string + */ + protected function makeSitemapUrl($siteMapPath) { + return $this->baseUrl . $siteMapPath; + } +} diff --git a/locallang.xml b/locallang.xml index 8046d7f..20785cf 100644 --- a/locallang.xml +++ b/locallang.xml @@ -1,34 +1,35 @@ - - - - database - Language labels for database tables/fields belonging to extension 'dd_googlesitemap' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + database + Language labels for database tables/fields belonging to extension 'dd_googlesitemap' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +