From: Tim Düsterhus Date: Fri, 23 Apr 2021 13:30:22 +0000 (+0200) Subject: Merge branch '5.3' X-Git-Tag: 5.4.0_Alpha_1~51 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=4f5bc16f8b78ae25fa8853f1d765a45e34e1f4f7;p=GitHub%2FWoltLab%2FWCF.git Merge branch '5.3' --- 4f5bc16f8b78ae25fa8853f1d765a45e34e1f4f7 diff --cc wcfsetup/install/files/lib/system/worker/SitemapRebuildWorker.class.php index 1b7419b13e,f6d6d5eed4..021440181a --- a/wcfsetup/install/files/lib/system/worker/SitemapRebuildWorker.class.php +++ b/wcfsetup/install/files/lib/system/worker/SitemapRebuildWorker.class.php @@@ -21,509 -19,440 +21,514 @@@ use wcf\util\MessageUtil /** * Worker implementation for rebuilding all sitemaps. * - * @author Joshua Ruesweg - * @copyright 2001-2019 WoltLab GmbH - * @license GNU Lesser General Public License - * @package WoltLabSuite\Core\System\Worker - * @since 3.1 + * @author Joshua Ruesweg + * @copyright 2001-2019 WoltLab GmbH + * @license GNU Lesser General Public License + * @package WoltLabSuite\Core\System\Worker + * @since 3.1 */ -class SitemapRebuildWorker extends AbstractRebuildDataWorker { - /** - * The limit of objects in one sitemap file. - */ - const SITEMAP_OBJECT_LIMIT = 50000; - - /** - * Prefix for stored data in the registry. - * @since 5.3 - */ - const REGISTRY_PREFIX = 'sitemapData_'; - - /** - * @inheritDoc - */ - public $limit = 250; - - /** - * All object types for the site maps. - * @var ObjectType[] - */ - public $sitemapObjects = []; - - /** - * The current worker data. - * @var mixed[] - */ - public $workerData = []; - - /** - * The current temporary file as File object. - * @var File - */ - public $file; - - /** - * The user profile of the actual user. - * @var User - */ - private $actualUser; - - /** - * @inheritDoc - */ - public function initObjectList() { - // This rebuild worker has no database object list - // therefore we do nothing in this method an overwrite - // the parent method, that it does not throw an exception. - } - - /** - * @inheritDoc - */ - public function countObjects() { - // changes session owner to 'System' during the building of sitemaps - $this->changeUserToGuest(); - - try { - if ($this->count === null) { - // reset count - $this->count = 0; - - // read sitemaps - $sitemapObjects = ObjectTypeCache::getInstance()->getObjectTypes('com.woltlab.wcf.sitemap.object'); - foreach ($sitemapObjects as $sitemapObject) { - self::prepareSitemapObject($sitemapObject); - $processor = $sitemapObject->getProcessor(); - - if ($processor->isAvailableType() && ($sitemapObject->isDisabled === null || !$sitemapObject->isDisabled)) { - $this->sitemapObjects[] = $sitemapObject; - - $list = $processor->getObjectList(); - - if (!($list instanceof DatabaseObjectList)) { - throw new ParentClassException(get_class($list), DatabaseObjectList::class); - } - - if (SITEMAP_INDEX_TIME_FRAME > 0 && $processor->getLastModifiedColumn() !== null) { - $list->getConditionBuilder()->add($processor->getLastModifiedColumn() . " > ?", [ - TIME_NOW - SITEMAP_INDEX_TIME_FRAME * 86400 // one day (60 * 60 * 24) - ]); - } - - $objectCount = $list->countObjects(); - $iterations = ceil($objectCount / $this->limit); - if (($objectCount % $this->limit) === 0) { - // We need an additional iteration to finalize the sitemap. - $iterations++; - } - $this->count += $iterations * $this->limit; - } - else { - $this->deleteSitemaps($sitemapObject->objectType); - } - } - } - } - finally { - // change session owner back to the actual user - $this->changeToActualUser(); - } - } - - /** - * @inheritDoc - */ - public function execute() { - // changes session owner to 'System' during the building of sitemaps - $this->changeUserToGuest(); - - try { - $this->loadWorkerData(); - - if (!isset($this->sitemapObjects[$this->workerData['sitemap']])) { - $this->workerData['finished'] = true; - $this->storeWorkerData(); - } - - // write sitemap index file if we have no active sitemap objects to prevent an outdated index file - if (empty($this->sitemapObjects) && $this->loopCount == 0) { - $this->writeIndexFile(); - } - - // check whether we should rebuild it - if (!isset($this->parameters['forceRebuild']) || !$this->parameters['forceRebuild'] && !$this->workerData['finished']) { - $this->checkCache(); - } - - if ($this->workerData['finished']) { - return; - } - - $this->openFile(); - - $sitemapObject = $this->sitemapObjects[$this->workerData['sitemap']]->getProcessor(); - $sitemapLoopCount = $this->workerData['sitemapLoopCount']; - - // delete all previously created sitemap files so that no more relics remain in the system - if ($sitemapLoopCount === 0) { - $this->deleteSitemaps($this->sitemapObjects[$this->workerData['sitemap']]->objectType); - } - - /** @var DatabaseObjectList $objectList */ - $objectList = $sitemapObject->getObjectList(); - - if (SITEMAP_INDEX_TIME_FRAME > 0 && $sitemapObject->getLastModifiedColumn() !== null) { - $objectList->getConditionBuilder()->add($sitemapObject->getLastModifiedColumn() . " > ?", [ - TIME_NOW - SITEMAP_INDEX_TIME_FRAME * 86400 // one day (60 * 60 * 24) - ]); - } - - $objectList->sqlLimit = $this->limit; - $objectList->sqlOffset = $this->limit * $sitemapLoopCount; - $objectList->readObjects(); - - foreach ($objectList->getObjects() as $object) { - if (!($object instanceof ILinkableObject)) { - throw new ImplementationException(get_class($object), ILinkableObject::class); - } - - $link = $object->getLink(); - $lastModifiedTime = ($sitemapObject->getLastModifiedColumn() === null) ? null : date('c', $object->{$sitemapObject->getLastModifiedColumn()}); - - if ($sitemapObject->canView($object)) { - $this->file->write(WCF::getTPL()->fetch('sitemapEntry', 'wcf', [ - // strip session links - 'link' => MessageUtil::stripCrap($link), - 'lastModifiedTime' => $lastModifiedTime, - 'priority' => $this->sitemapObjects[$this->workerData['sitemap']]->priority, - 'changeFreq' => $this->sitemapObjects[$this->workerData['sitemap']]->changeFreq - ])); - - $this->workerData['dataCount']++; - } - } - - if ($this->workerData['dataCount'] + $this->limit > self::SITEMAP_OBJECT_LIMIT) { - $this->finishSitemap($this->sitemapObjects[$this->workerData['sitemap']]->objectType . '_' . $this->workerData['sitemapLoopCount'] . '.xml'); - - $this->generateTmpFile(false); - - $this->workerData['dataCount'] = 0; - } - - $closeFile = true; - // finish sitemap - if (count($objectList) < $this->limit) { - if ($this->workerData['dataCount'] > 0) { - $this->finishSitemap($this->sitemapObjects[$this->workerData['sitemap']]->objectType . '.xml'); - $this->generateTmpFile(false); - } - - // increment data - $this->workerData['dataCount'] = 0; - $this->workerData['sitemapLoopCount'] = -1; - $this->workerData['sitemap']++; - - if (count($this->sitemapObjects) <= $this->workerData['sitemap']) { - $this->writeIndexFile(); - $closeFile = false; - } - } - - $this->workerData['sitemapLoopCount']++; - $this->storeWorkerData(); - if ($closeFile) $this->closeFile(); - } - finally { - // change session owner back to the actual user - $this->changeToActualUser(); - } - } - - /** - * Checks if the sitemap has to be rebuilt. If not, this method marks the sitemap as built. - */ - protected function checkCache() { - $object = (isset($this->sitemapObjects[$this->workerData['sitemap']])) ? $this->sitemapObjects[$this->workerData['sitemap']] : false; - while ($object && file_exists(self::getSitemapPath() . $object->objectType . '.xml') && filectime(self::getSitemapPath() . $object->objectType . '.xml') > TIME_NOW - (($object->rebuildTime !== null) ? $object->rebuildTime : 60 * 60 * 24 * 7)) { - foreach (array_merge(glob(self::getSitemapPath() . $object->objectType . '_*'), [self::getSitemapPath() . $object->objectType . '.xml']) as $filename) { - $this->workerData['sitemaps'][] = self::getSitemapURL() . basename($filename); - } - - $this->workerData['sitemap']++; - - if (!isset($this->sitemapObjects[$this->workerData['sitemap']])) { - $this->writeIndexFile(false); - - // if we don't have to refresh any data, we set loopCount to one - // so that we no init a new $workerData session - if ($this->loopCount == 0) { - $this->loopCount = 1; - } - $this->storeWorkerData(); - break; - } - else { - $object = $this->sitemapObjects[$this->workerData['sitemap']]; - } - } - } - - /** - * Writes the sitemap.xml index file and links all sitemaps. - * - * @param boolean $closeFile Close a previously opened handle. - */ - protected function writeIndexFile($closeFile = true) { - $file = new AtomicWriter(self::getSitemapPath() . 'sitemap.xml'); - $file->write(WCF::getTPL()->fetch('sitemapIndex', 'wcf', [ - 'sitemaps' => $this->workerData['sitemaps'] - ])); - $file->flush(); - $file->close(); - - $this->workerData['finished'] = true; - - if ($closeFile) $this->closeFile(); - - if ($this->workerData['tmpFile'] && file_exists($this->workerData['tmpFile'])) { - unlink($this->workerData['tmpFile']); - } - } - - /** - * Generates a new temporary file and appends the sitemap start. - * - * @param boolean $closeFile Close a previously opened handle. - */ - protected function generateTmpFile($closeFile = true) { - if ($closeFile) $this->closeFile(); - - $this->workerData['tmpFile'] = FileUtil::getTemporaryFilename('sitemap_' . $this->workerData['sitemap'] . '_'); - - $this->openFile(); - - $this->file->write(WCF::getTPL()->fetch('sitemapStart')); - } - - /** - * Open the current temporary file. - */ - protected function openFile() { - if (!file_exists($this->workerData['tmpFile'])) { - touch($this->workerData['tmpFile']); - } - - $this->file = new File($this->workerData['tmpFile'], 'ab'); - } - - /** - * Closes the current temporary file, iff a File is opened. - */ - protected function closeFile() { - if ($this->file instanceof File) { - $this->file->close(); - } - } - - /** - * Writes the current temporary file in a finished sitemap file. The param - * $filename defines the sitemap filename. - * - * @param string $filename - */ - protected function finishSitemap($filename) { - $this->file->write(WCF::getTPL()->fetch('sitemapEnd')); - $this->file->close(); - - rename($this->workerData['tmpFile'], self::getSitemapPath() . $filename); - - // add sitemap to the successfully built sitemaps - $this->workerData['sitemaps'][] = self::getSitemapURL() . $filename; - } - - /** - * Stores the current worker data in a session. - */ - protected function storeWorkerData() { - WCF::getSession()->register('sitemapRebuildWorkerData', $this->workerData); - } - - /** - * Load the current worker data and set the default values, if isn't any data stored. - */ - protected function loadWorkerData() { - $this->workerData = WCF::getSession()->getVar('sitemapRebuildWorkerData'); - - if ($this->loopCount == 0) { - $this->workerData = [ - 'sitemap' => 0, - 'sitemapLoopCount' => 0, - 'dataCount' => 0, - 'tmpFile' => '', - 'sitemaps' => [], - 'finished' => false - ]; - - $this->generateTmpFile(); - } - } - - /** - * @inheritDoc - */ - public function validate() { - WCF::getSession()->checkPermissions(['admin.management.canRebuildData']); - } - - /** - * @inheritDoc - */ - public function getProceedURL() { - return LinkHandler::getInstance()->getLink('SitemapList', [ - 'isACP' => true - ]); - } - - /** - * Returns the relative sitemap folder path. - * - * @return string - */ - public static function getSitemapPath() { - return WCF_DIR . 'sitemaps/'; - } - - /** - * Returns the full sitemap folder path. - * - * @return string - */ - public static function getSitemapURL() { - return WCF::getPath() . 'sitemaps/'; - } - - /** - * Unlink the sitemap files for a given object type name. - * - * @param string $objectTypeName - */ - private function deleteSitemaps($objectTypeName) { - $files = @glob(self::getSitemapPath().$objectTypeName.'*.xml'); - if (is_array($files)) { - $regex = new Regex(preg_quote($objectTypeName).'(_[0-9]*|).xml'); - foreach ($files as $filename) { - if ($regex->match(basename($filename))) { - unlink($filename); - } - } - } - } - - /** - * Saves the actual user and changes the session owner to a guest. - */ - private function changeUserToGuest() { - $this->actualUser = WCF::getUser(); - - // login as system user - WCF::getSession()->changeUser(new User(null, ['username' => 'System', 'userID' => 0]), true); - } - - /** - * Changes the session back to the actual user. - */ - private function changeToActualUser() { - WCF::getSession()->changeUser($this->actualUser, true); - } - - /** - * Reads the columns changed by the user for this sitemap object from the registry and modifies the object accordingly. - * - * @param ObjectType $object - * @since 5.3 - */ - public static function prepareSitemapObject(ObjectType $object) { - $sitemapData = RegistryHandler::getInstance()->get('com.woltlab.wcf', self::REGISTRY_PREFIX . $object->objectType); - - if ($sitemapData !== null) { - $sitemapData = @unserialize($sitemapData); - - if (is_array($sitemapData)) { - $object->priority = $sitemapData['priority']; - $object->changeFreq = $sitemapData['changeFreq']; - $object->rebuildTime = $sitemapData['rebuildTime']; - $object->isDisabled = $sitemapData['isDisabled']; - } - } - } +class SitemapRebuildWorker extends AbstractRebuildDataWorker +{ + /** + * The limit of objects in one sitemap file. + */ + const SITEMAP_OBJECT_LIMIT = 50000; + + /** + * Prefix for stored data in the registry. + * @since 5.3 + */ + const REGISTRY_PREFIX = 'sitemapData_'; + + /** + * @inheritDoc + */ + public $limit = 250; + + /** + * All object types for the site maps. + * @var ObjectType[] + */ + public $sitemapObjects = []; + + /** + * The current worker data. + * @var mixed[] + */ + public $workerData = []; + + /** + * The current temporary file as File object. + * @var File + */ + public $file; + + /** + * The user profile of the actual user. + * @var User + */ + private $actualUser; + + /** + * @inheritDoc + */ + public function initObjectList() + { + // This rebuild worker has no database object list + // therefore we do nothing in this method an overwrite + // the parent method, that it does not throw an exception. + } + + /** + * @inheritDoc + */ + public function countObjects() + { + // changes session owner to 'System' during the building of sitemaps + $this->changeUserToGuest(); + + try { + if ($this->count === null) { + // reset count + $this->count = 0; + + // read sitemaps + $sitemapObjects = ObjectTypeCache::getInstance()->getObjectTypes('com.woltlab.wcf.sitemap.object'); + foreach ($sitemapObjects as $sitemapObject) { + self::prepareSitemapObject($sitemapObject); + $processor = $sitemapObject->getProcessor(); + + if ( + $processor->isAvailableType() + && ($sitemapObject->isDisabled === null || !$sitemapObject->isDisabled) + ) { + $this->sitemapObjects[] = $sitemapObject; + + $list = $processor->getObjectList(); + + if (!($list instanceof DatabaseObjectList)) { + throw new ParentClassException(\get_class($list), DatabaseObjectList::class); + } + + if (SITEMAP_INDEX_TIME_FRAME > 0 && $processor->getLastModifiedColumn() !== null) { + $list->getConditionBuilder()->add($processor->getLastModifiedColumn() . " > ?", [ + TIME_NOW - SITEMAP_INDEX_TIME_FRAME * 86400, // one day (60 * 60 * 24) + ]); + } + - // modify count, because we handle only one sitemap object per call - $this->count += \max(1, \ceil($list->countObjects() / $this->limit)) * $this->limit; ++ $objectCount = $list->countObjects(); ++ $iterations = \ceil($objectCount / $this->limit); ++ if (($objectCount % $this->limit) === 0) { ++ // We need an additional iteration to finalize the sitemap. ++ $iterations++; ++ } ++ $this->count += $iterations * $this->limit; + } else { + $this->deleteSitemaps($sitemapObject->objectType); + } + } + } + } finally { + // change session owner back to the actual user + $this->changeToActualUser(); + } + } + + /** + * @inheritDoc + */ + public function execute() + { + // changes session owner to 'System' during the building of sitemaps + $this->changeUserToGuest(); + + try { + $this->loadWorkerData(); + + if (!isset($this->sitemapObjects[$this->workerData['sitemap']])) { + $this->workerData['finished'] = true; + $this->storeWorkerData(); + } + + // write sitemap index file if we have no active sitemap objects to prevent an outdated index file + if (empty($this->sitemapObjects) && $this->loopCount == 0) { + $this->writeIndexFile(); + } + + // check whether we should rebuild it + if ((!isset($this->parameters['forceRebuild']) || !$this->parameters['forceRebuild']) && !$this->workerData['finished']) { + $this->checkCache(); + } + + if ($this->workerData['finished']) { + return; + } + + $this->openFile(); + + $sitemapObject = $this->sitemapObjects[$this->workerData['sitemap']]->getProcessor(); + $sitemapLoopCount = $this->workerData['sitemapLoopCount']; + + // delete all previously created sitemap files so that no more relics remain in the system + if ($sitemapLoopCount === 0) { + $this->deleteSitemaps($this->sitemapObjects[$this->workerData['sitemap']]->objectType); + } + + /** @var DatabaseObjectList $objectList */ + $objectList = $sitemapObject->getObjectList(); + + if (SITEMAP_INDEX_TIME_FRAME > 0 && $sitemapObject->getLastModifiedColumn() !== null) { + $objectList->getConditionBuilder()->add($sitemapObject->getLastModifiedColumn() . " > ?", [ + TIME_NOW - SITEMAP_INDEX_TIME_FRAME * 86400, // one day (60 * 60 * 24) + ]); + } + + $objectList->sqlLimit = $this->limit; + $objectList->sqlOffset = $this->limit * $sitemapLoopCount; + $objectList->readObjects(); + + foreach ($objectList->getObjects() as $object) { + if (!($object instanceof ILinkableObject)) { + throw new ImplementationException(\get_class($object), ILinkableObject::class); + } + + $link = $object->getLink(); + $lastModifiedTime = ($sitemapObject->getLastModifiedColumn() === null) ? null : \date( + 'c', + $object->{$sitemapObject->getLastModifiedColumn()} + ); + + if ($sitemapObject->canView($object)) { + $this->file->write(WCF::getTPL()->fetch('sitemapEntry', 'wcf', [ + // strip session links + 'link' => MessageUtil::stripCrap($link), + 'lastModifiedTime' => $lastModifiedTime, + 'priority' => $this->sitemapObjects[$this->workerData['sitemap']]->priority, + 'changeFreq' => $this->sitemapObjects[$this->workerData['sitemap']]->changeFreq, + ])); + + $this->workerData['dataCount']++; + } + } + + if ($this->workerData['dataCount'] + $this->limit > self::SITEMAP_OBJECT_LIMIT) { + $packageID = $this->sitemapObjects[$this->workerData['sitemap']]->packageID; + $filename = $this->sitemapObjects[$this->workerData['sitemap']]->objectType . '.xml'; + $this->finishSitemap($filename, $packageID); + + $this->generateTmpFile(false); + + $this->workerData['dataCount'] = 0; + } + + $closeFile = true; + // finish sitemap + if (\count($objectList) < $this->limit) { + if ($this->workerData['dataCount'] > 0) { + $packageID = $this->sitemapObjects[$this->workerData['sitemap']]->packageID; + $filename = $this->sitemapObjects[$this->workerData['sitemap']]->objectType . '.xml'; + $this->finishSitemap($filename, $packageID); + $this->generateTmpFile(false); + } + + // increment data + $this->workerData['dataCount'] = 0; + $this->workerData['sitemapLoopCount'] = -1; + $this->workerData['sitemap']++; + + if (\count($this->sitemapObjects) <= $this->workerData['sitemap']) { + $this->writeIndexFile(); + $closeFile = false; + } + } + + $this->workerData['sitemapLoopCount']++; + $this->storeWorkerData(); + if ($closeFile) { + $this->closeFile(); + } + } finally { + // change session owner back to the actual user + $this->changeToActualUser(); + } + } + + /** + * Checks if the sitemap has to be rebuilt. If not, this method marks the sitemap as built. + */ + protected function checkCache() + { + $object = (isset($this->sitemapObjects[$this->workerData['sitemap']])) ? $this->sitemapObjects[$this->workerData['sitemap']] : false; + while ( + $object + && \file_exists(self::getSitemapPath() . $object->objectType . '.xml') + && \filectime(self::getSitemapPath() . $object->objectType . '.xml') > TIME_NOW - (($object->rebuildTime !== null) ? $object->rebuildTime : 60 * 60 * 24 * 7) + ) { + $filenames = \array_merge( + \glob(self::getSitemapPath() . $object->objectType . '_*'), + [self::getSitemapPath() . $object->objectType . '.xml'] + ); + foreach ($filenames as $filename) { + $this->workerData['sitemaps'][] = self::getSitemapURL() . \basename($filename); + } + + $this->workerData['sitemap']++; + + if (!isset($this->sitemapObjects[$this->workerData['sitemap']])) { + $this->writeIndexFile(false); + + // if we don't have to refresh any data, we set loopCount to one + // so that we no init a new $workerData session + if ($this->loopCount == 0) { + $this->loopCount = 1; + } + $this->storeWorkerData(); + break; + } else { + $object = $this->sitemapObjects[$this->workerData['sitemap']]; + } + } + } + + /** + * Writes the sitemap.xml index file and links all sitemaps. + * + * @param bool $closeFile Close a previously opened handle. + */ + protected function writeIndexFile($closeFile = true) + { + $file = new AtomicWriter(self::getSitemapPath() . 'sitemap.xml'); + $file->write(WCF::getTPL()->fetch('sitemapIndex', 'wcf', [ + 'sitemaps' => $this->workerData['sitemaps'], + ])); + $file->flush(); + $file->close(); + + $this->workerData['finished'] = true; + + if ($closeFile) { + $this->closeFile(); + } + + if ($this->workerData['tmpFile'] && \file_exists($this->workerData['tmpFile'])) { + \unlink($this->workerData['tmpFile']); + } + + $this->registerSitemapFiles(); + } + + /** + * Generates a new temporary file and appends the sitemap start. + * + * @param bool $closeFile Close a previously opened handle. + */ + protected function generateTmpFile($closeFile = true) + { + if ($closeFile) { + $this->closeFile(); + } + + $this->workerData['tmpFile'] = FileUtil::getTemporaryFilename('sitemap_' . $this->workerData['sitemap'] . '_'); + + $this->openFile(); + + $this->file->write(WCF::getTPL()->fetch('sitemapStart')); + } + + /** + * Open the current temporary file. + */ + protected function openFile() + { + if (!\file_exists($this->workerData['tmpFile'])) { + \touch($this->workerData['tmpFile']); + } + + $this->file = new File($this->workerData['tmpFile'], 'ab'); + } + + /** + * Closes the current temporary file, iff a File is opened. + */ + protected function closeFile() + { + if ($this->file instanceof File) { + $this->file->close(); + } + } + + /** + * Writes the current temporary file in a finished sitemap file. The param + * $filename defines the sitemap filename. + * + * @param string $filename + * @param int $packageID + */ + protected function finishSitemap($filename, $packageID) + { + $this->file->write(WCF::getTPL()->fetch('sitemapEnd')); + $this->file->close(); + + \rename($this->workerData['tmpFile'], self::getSitemapPath() . $filename); + + // add sitemap to the successfully built sitemaps + $this->workerData['sitemaps'][] = self::getSitemapURL() . $filename; + + // Register sitemap for the package installation file log. + if (!isset($this->workerData['filesToPackage'][$packageID])) { + $this->workerData['filesToPackage'][$packageID] = []; + } + $this->workerData['filesToPackage'][$packageID][] = 'sitemaps/' . $filename; + } + + private function registerSitemapFiles() + { + $sql = "INSERT IGNORE INTO wcf" . WCF_N . "_package_installation_file_log + (packageID, filename, application) + VALUES (?, ?, ?)"; + $statement = WCF::getDB()->prepareStatement($sql); + + WCF::getDB()->beginTransaction(); + foreach ($this->workerData['filesToPackage'] as $packageID => $files) { + foreach ($files as $file) { + $statement->execute([ + $packageID, + $file, + 'wcf', + ]); + } + } + WCF::getDB()->commitTransaction(); + } + + /** + * Stores the current worker data in a session. + */ + protected function storeWorkerData() + { + WCF::getSession()->register('sitemapRebuildWorkerData', $this->workerData); + } + + /** + * Load the current worker data and set the default values, if isn't any data stored. + */ + protected function loadWorkerData() + { + $this->workerData = WCF::getSession()->getVar('sitemapRebuildWorkerData'); + + if ($this->loopCount == 0) { + $this->workerData = [ + 'sitemap' => 0, + 'sitemapLoopCount' => 0, + 'dataCount' => 0, + 'tmpFile' => '', + 'sitemaps' => [], + 'finished' => false, + 'filesToPackage' => [], + ]; + + $this->generateTmpFile(); + } + } + + /** + * @inheritDoc + */ + public function validate() + { + WCF::getSession()->checkPermissions(['admin.management.canRebuildData']); + } + + /** + * @inheritDoc + */ + public function getProceedURL() + { + return LinkHandler::getInstance()->getLink('SitemapList', [ + 'isACP' => true, + ]); + } + + /** + * Returns the relative sitemap folder path. + * + * @return string + */ + public static function getSitemapPath() + { + return WCF_DIR . 'sitemaps/'; + } + + /** + * Returns the full sitemap folder path. + * + * @return string + */ + public static function getSitemapURL() + { + return WCF::getPath() . 'sitemaps/'; + } + + /** + * Unlink the sitemap files for a given object type name. + * + * @param string $objectTypeName + */ + private function deleteSitemaps($objectTypeName) + { + $files = @\glob(self::getSitemapPath() . $objectTypeName . '*.xml'); + if (\is_array($files)) { + $regex = new Regex(\preg_quote($objectTypeName) . '(_[0-9]*|).xml'); + foreach ($files as $filename) { + if ($regex->match(\basename($filename))) { + \unlink($filename); + } + } + } + } + + /** + * Saves the actual user and changes the session owner to a guest. + */ + private function changeUserToGuest() + { + $this->actualUser = WCF::getUser(); + + // login as system user + WCF::getSession()->changeUser(new User(null, ['username' => 'System', 'userID' => 0]), true); + } + + /** + * Changes the session back to the actual user. + */ + private function changeToActualUser() + { + WCF::getSession()->changeUser($this->actualUser, true); + } + + /** + * Reads the columns changed by the user for this sitemap object from the registry and + * modifies the object accordingly. + * + * @param ObjectType $object + * @since 5.3 + */ + public static function prepareSitemapObject(ObjectType $object) + { + $sitemapData = RegistryHandler::getInstance()->get( + 'com.woltlab.wcf', + self::REGISTRY_PREFIX . $object->objectType + ); + + if ($sitemapData !== null) { + $sitemapData = @\unserialize($sitemapData); + + if (\is_array($sitemapData)) { + $object->priority = $sitemapData['priority']; + $object->changeFreq = $sitemapData['changeFreq']; + $object->rebuildTime = $sitemapData['rebuildTime']; + $object->isDisabled = $sitemapData['isDisabled']; + } + } + } }