Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
Generator.php
1<?php
2
3namespace Bitrix\Seo\Sitemap;
4
14
15Loc::loadMessages(__DIR__ . '/../../admin/seo_sitemap.php');
16
21{
25 protected const STEP_DURATION = 13;
26
31 protected int $sitemapId;
32
37 protected array $sitemapData = [];
38
43 protected int $step;
44
49 protected array $state;
50
55 protected string $statusMessage = '';
56
57 public function __construct(int $sitemapId)
58 {
59 if ($sitemapId <= 0)
60 {
61 // todo: err
62 }
63 $this->sitemapId = $sitemapId;
64
65 $this->sitemapData = (SitemapTable::getById($this->sitemapId))->fetch();
66 if (empty($this->sitemapData))
67 {
68 // todo: error
69 }
70 $this->sitemapData['SETTINGS'] = unserialize($this->sitemapData['SETTINGS'], ['allowed_classes' => false]);
71 $this->sitemapData['SITE'] = (SiteTable::getByPrimary($this->sitemapData['SITE_ID']))->fetch();
72
73 $this->init(Step::getFirstStep(), []);
74 }
75
82 public function init(int $step, array $state): void
83 {
84 // todo: check state by whitelist
85 $this->step = $step;
86 $this->state = $state;
87
88 $this->statusMessage = Loc::getMessage('SEO_SITEMAP_RUN_INIT');
89 }
90
96 public function setStep(int $step): static
97 {
98 if (
99 $step >= Step::getFirstStep()
100 && $step <= Step::getLastStep()
101 )
102 {
103 $this->step = $step;
104 }
105
106 return $this;
107 }
108
113 public function getStep(): int
114 {
115 return $this->step;
116 }
117
123 public function setState(array $state): static
124 {
125 $this->state = $state;
126
127 return $this;
128 }
129
134 public function getState(): array
135 {
136 return $this->state;
137 }
138
143 public function getStatusMessage(): string
144 {
146 }
147
151 public function run(): bool
152 {
153 $result = false;
154
155 if ($this->step === Step::STEPS[Step::STEP_INIT])
156 {
157 $result = $this->runInit();
158 }
159
160 elseif ($this->step < Step::STEPS[Step::STEP_FILES])
161 {
162 $result = $this->runFiles();
163 }
164
165 elseif ($this->step < Step::STEPS[Step::STEP_IBLOCK_INDEX])
166 {
167 $result = $this->runIblockIndex();
168 }
169
170 elseif ($this->step < Step::STEPS[Step::STEP_IBLOCK])
171 {
172 $result = $this->runIblock();
173 }
174
175 elseif ($this->step < Step::STEPS[Step::STEP_FORUM_INDEX])
176 {
177 $result = $this->runForumIndex();
178 }
179
180 elseif ($this->step < Step::STEPS[Step::STEP_FORUM])
181 {
182 $result = $this->runForum();
183 }
184
185 elseif ($this->step < Step::STEPS[Step::STEP_INDEX])
186 {
187 if ($this->runIndex())
188 {
189 $result = $this->finish();
190 }
191 }
192
193 return $result;
194 }
195
200 protected function runInit(): bool
201 {
202 RuntimeTable::clearByPid($this->sitemapId);
203
204 $isRootChecked =
205 isset($this->sitemapData['SETTINGS']['DIR']['/'])
206 && $this->sitemapData['SETTINGS']['DIR']['/'] == 'Y';
207
208 $runtimeData = [
209 'PID' => $this->sitemapId,
210 'ITEM_TYPE' => RuntimeTable::ITEM_TYPE_DIR,
211 'ITEM_PATH' => '/',
212 'PROCESSED' => RuntimeTable::UNPROCESSED,
213 'ACTIVE' => $isRootChecked ? RuntimeTable::ACTIVE : RuntimeTable::INACTIVE,
214 ];
215
216 try
217 {
218 $resAdd = RuntimeTable::add($runtimeData);
219 }
220 catch (\Exception $e)
221 {
222 return false;
223 }
224
225 if ($resAdd->isSuccess())
226 {
227 $this->step++;
228 $this->statusMessage = Loc::getMessage('SITEMAP_RUN_FILES', ['#PATH#' => '/']);
229 }
230
231 return $resAdd->isSuccess();
232 }
233
234 protected function runFiles(): bool
235 {
236 $sitemapFile =
237 new File\Runtime(
238 $this->sitemapId,
239 $this->sitemapData['SETTINGS']['FILENAME_FILES'],
240 $this->getSitemapSettings()
241 );
242
243 $timeFinish = self::getTimeFinish();
244 $isFinished = false;
245 $isCheckFinished = false;
246 $dbRes = null;
247
248 while (!$isFinished && microtime(true) <= $timeFinish)
249 {
250 if (!$dbRes)
251 {
252 $dbRes = RuntimeTable::getList([
253 'order' => ['ITEM_PATH' => 'ASC'],
254 'filter' => [
255 'PID' => $this->sitemapId,
256 'ITEM_TYPE' => RuntimeTable::ITEM_TYPE_DIR,
257 'PROCESSED' => RuntimeTable::UNPROCESSED,
258 ],
259 'limit' => 1000,
260 ]);
261 }
262
263 if ($dirData = $dbRes->Fetch())
264 {
265 $this->processDirectory($dirData, $sitemapFile);
266 $this->statusMessage = Loc::getMessage('SITEMAP_RUN_FILES', ['#PATH#' => $dirData['ITEM_PATH']]);
267 $isCheckFinished = false;
268 }
269 elseif (!$isCheckFinished)
270 {
271 $dbRes = null;
272 $isCheckFinished = true;
273 }
274 else
275 {
276 $isFinished = true;
277 }
278 }
279
280 if (!$isFinished)
281 {
282 if ($this->step < Step::STEPS[Step::STEP_FILES] - 1)
283 {
284 $this->step++;
285 }
286 }
287 else
288 {
289 // todo: check state by whitelist
290 if (!is_array($this->state['XML_FILES']))
291 {
292 $this->state['XML_FILES'] = [];
293 }
294
295 if ($sitemapFile->isNotEmpty())
296 {
297 if ($sitemapFile->isCurrentPartNotEmpty())
298 {
299 $sitemapFile->finish();
300 }
301 else
302 {
303 $sitemapFile->delete();
304 }
305
306 $xmlFiles = $sitemapFile->getNameList();
307 $directory = $sitemapFile->getPathDirectory();
308 foreach ($xmlFiles as &$xmlFile)
309 {
310 $xmlFile = $directory . $xmlFile;
311 }
312 $this->state['XML_FILES'] = array_unique(array_merge($this->state['XML_FILES'], $xmlFiles));
313 }
314 else
315 {
316 $sitemapFile->delete();
317 }
318
319 $this->step = Step::STEPS[Step::STEP_FILES];
320 $this->statusMessage = Loc::getMessage(
321 'SITEMAP_RUN_FILE_COMPLETE',
322 ['#FILE#' => $this->sitemapData['SETTINGS']['FILENAME_FILES']]
323 );
324 }
325
326 return true;
327 }
328
335 protected function processDirectory($dirData, File\Base $sitemapFile): void
336 {
337 $processedDirs = [];
338
339 if ($dirData['ACTIVE'] == RuntimeTable::ACTIVE)
340 {
341 $directories = \CSeoUtils::getDirStructure(
342 $this->sitemapData['SETTINGS']['logical'] == 'Y',
343 $this->sitemapData['SITE_ID'],
344 $dirData['ITEM_PATH']
345 );
346
347 foreach ($directories as $dir)
348 {
349 $dirKey = "/" . ltrim($dir['DATA']['ABS_PATH'], "/");
350
351 if ($dir['TYPE'] == 'F')
352 {
353 if (
354 !isset($this->sitemapData['SETTINGS']['FILE'][$dirKey])
355 || $this->sitemapData['SETTINGS']['FILE'][$dirKey] == 'Y'
356 )
357 {
358 if (preg_match($this->sitemapData['SETTINGS']['FILE_MASK_REGEXP'], $dir['FILE']))
359 {
360 $f = new IO\File($dir['DATA']['PATH'], $this->sitemapData['SITE_ID']);
361 $sitemapFile->addFileEntry($f);
362 }
363 }
364 }
365 else
366 {
367 if (!isset($this->sitemapData['SETTINGS']['DIR'][$dirKey])
368 || $this->sitemapData['SETTINGS']['DIR'][$dirKey] == 'Y')
369 {
370 $processedDirs[] = $dirKey;
371 }
372 }
373 }
374 }
375 else
376 {
377 $len = mb_strlen($dirData['ITEM_PATH']);
378 if (!empty($this->sitemapData['SETTINGS']['DIR']))
379 {
380 foreach ($this->sitemapData['SETTINGS']['DIR'] as $dirKey => $checked)
381 {
382 if ($checked == 'Y')
383 {
384 if (strncmp($dirData['ITEM_PATH'], $dirKey, $len) === 0)
385 {
386 $processedDirs[] = $dirKey;
387 }
388 }
389 }
390 }
391
392 if (!empty($this->sitemapData['SETTINGS']['FILE']))
393 {
394 foreach ($this->sitemapData['SETTINGS']['FILE'] as $dirKey => $checked)
395 {
396 if ($checked == 'Y')
397 {
398 if (strncmp($dirData['ITEM_PATH'], $dirKey, $len) === 0)
399 {
400 $fileName = IO\Path::combine(
401 SiteTable::getDocumentRoot($this->sitemapData['SITE_ID']),
402 $dirKey
403 );
404
405 if (!is_dir($fileName))
406 {
407 $f = new IO\File($fileName, $this->sitemapData['SITE_ID']);
408 if (
409 $f->isExists()
410 && !$f->isSystem()
411 && preg_match($this->sitemapData['SETTINGS']['FILE_MASK_REGEXP'], $f->getName())
412 )
413 {
414 $sitemapFile->addFileEntry($f);
415 }
416 }
417 }
418 }
419 }
420 }
421 }
422
423 if (count($processedDirs) > 0)
424 {
425 foreach ($processedDirs as $dirKey)
426 {
427 $runtimeData = [
428 'PID' => $this->sitemapId,
429 'ITEM_PATH' => $dirKey,
430 'PROCESSED' => RuntimeTable::UNPROCESSED,
431 'ACTIVE' => RuntimeTable::ACTIVE,
432 'ITEM_TYPE' => RuntimeTable::ITEM_TYPE_DIR,
433 ];
434 RuntimeTable::add($runtimeData);
435 }
436 }
437
438 RuntimeTable::update($dirData['ID'], [
439 'PROCESSED' => RuntimeTable::PROCESSED,
440 ]);
441 }
442
443 protected function runIblockIndex(): bool
444 {
445 $result = true;
446
447 $arIBlockList = [];
448 if (Loader::includeModule('iblock'))
449 {
450 $arIBlockList = $this->sitemapData['SETTINGS']['IBLOCK_ACTIVE'];
451 if (is_array($arIBlockList) && count($arIBlockList) > 0)
452 {
453 $arIBlocks = [];
454 $dbIBlock = \CIBlock::GetList([], ['ID' => array_keys($arIBlockList)]);
455 while ($arIBlock = $dbIBlock->Fetch())
456 {
457 $arIBlocks[$arIBlock['ID']] = $arIBlock;
458 }
459
460 foreach ($arIBlockList as $iblockId => $iblockActive)
461 {
462 if ($iblockActive !== 'Y' || !array_key_exists($iblockId, $arIBlocks))
463 {
464 unset($arIBlockList[$iblockId]);
465 }
466 else
467 {
468 RuntimeTable::add([
469 'PID' => $this->sitemapId,
470 'PROCESSED' => RuntimeTable::UNPROCESSED,
471 'ITEM_ID' => $iblockId,
472 'ITEM_TYPE' => RuntimeTable::ITEM_TYPE_IBLOCK,
473 ]);
474 }
475 }
476 }
477 }
478
479 $this->state['LEFT_MARGIN'] = 0;
480 $this->state['IBLOCK_LASTMOD'] = 0;
481
482 $this->state['IBLOCK'] = [];
483 $this->state['IBLOCK_MAP'] = [];
484
485 if (count($arIBlockList) <= 0)
486 {
487 $this->step = Step::STEPS[Step::STEP_IBLOCK];
488 $this->statusMessage = Loc::getMessage('SITEMAP_RUN_IBLOCK_EMPTY');
489 }
490 else
491 {
492 $this->step = Step::STEPS[Step::STEP_IBLOCK_INDEX];
493 $this->statusMessage = Loc::getMessage('SITEMAP_RUN_IBLOCK');
494 }
495
496 return $result;
497 }
498
499 protected function runIblock(): bool
500 {
501 $result = true;
502
503 $timeFinish = self::getTimeFinish();
504 $isFinished = false;
505 $bCheckFinished = false;
506 $runtimeIblock = false;
507 $currentIBlock = false;
508 $sitemapFile = null;
509 $iblockId = 0;
510
511 $dbOldIblockResult = null;
512 $dbIblockResult = null;
513
514 if (isset($_SESSION["SEO_SITEMAP_" . $this->sitemapId]))
515 {
516 $this->state['IBLOCK_MAP'] = $_SESSION["SEO_SITEMAP_" . $this->sitemapId];
517 unset($_SESSION["SEO_SITEMAP_" . $this->sitemapId]);
518 }
519
520 while (!$isFinished && microtime(true) <= $timeFinish && Loader::includeModule('iblock'))
521 {
522 if (!$runtimeIblock)
523 {
524 $dbRes = RuntimeTable::getList([
525 'order' => ['ID' => 'ASC'],
526 'filter' => [
527 'PID' => $this->sitemapId,
528 'ITEM_TYPE' => RuntimeTable::ITEM_TYPE_IBLOCK,
529 'PROCESSED' => RuntimeTable::UNPROCESSED,
530 ],
531 'limit' => 1,
532 ]);
533 $runtimeIblock = $dbRes->fetch();
534
535 if ($runtimeIblock)
536 {
537 $iblockId = intval($runtimeIblock['ITEM_ID']);
538
539 $dbIBlock = \CIBlock::GetByID($iblockId);
540 $currentIBlock = $dbIBlock->Fetch();
541
542 if (!$currentIBlock)
543 {
544 RuntimeTable::update($runtimeIblock['ID'], [
545 'PROCESSED' => RuntimeTable::PROCESSED,
546 ]);
547
548 $this->state['LEFT_MARGIN'] = 0;
549 $this->state['IBLOCK_LASTMOD'] = 0;
550 $this->state['LAST_ELEMENT_ID'] = 0;
551 unset($this->state['CURRENT_SECTION']);
552
553 $this->statusMessage = Loc::getMessage(
554 'SITEMAP_RUN_IBLOCK_NAME',
555 ['#IBLOCK_NAME#' => $currentIBlock['NAME']]
556 );
557 }
558 else
559 {
560 if ($currentIBlock['LIST_PAGE_URL'] == '')
561 {
562 $this->sitemapData['SETTINGS']['IBLOCK_LIST'][$iblockId] = 'N';
563 }
564 if ($currentIBlock['SECTION_PAGE_URL'] == '')
565 {
566 $this->sitemapData['SETTINGS']['IBLOCK_SECTION'][$iblockId] = 'N';
567 }
568 if ($currentIBlock['DETAIL_PAGE_URL'] == '')
569 {
570 $this->sitemapData['SETTINGS']['IBLOCK_ELEMENT'][$iblockId] = 'N';
571 }
572
573 $this->state['IBLOCK_LASTMOD'] =
574 max($this->state['IBLOCK_LASTMOD'], MakeTimeStamp($currentIBlock['TIMESTAMP_X']));
575
576 if ($this->state['LEFT_MARGIN'] <= 0 && $this->sitemapData['SETTINGS']['IBLOCK_ELEMENT'][$iblockId] != 'N')
577 {
578 $this->state['CURRENT_SECTION'] = 0;
579 }
580
581 $fileName = str_replace(
582 ['#IBLOCK_ID#', '#IBLOCK_CODE#', '#IBLOCK_XML_ID#'],
583 [$iblockId, $currentIBlock['CODE'], $currentIBlock['XML_ID']],
584 $this->sitemapData['SETTINGS']['FILENAME_IBLOCK']
585 );
586
587 $sitemapFile =
588 new File\Runtime(
589 $this->sitemapId,
590 $fileName,
591 $this->getSitemapSettings()
592 );
593 }
594 }
595 }
596
597 if (!$runtimeIblock || !$sitemapFile)
598 {
599 $isFinished = true;
600 }
601 elseif (is_array($currentIBlock))
602 {
603 if ($dbIblockResult == null)
604 {
605 if (isset($this->state['CURRENT_SECTION']))
606 {
607 $dbIblockResult = \CIBlockElement::GetList(
608 ['ID' => 'ASC'],
609 [
610 'IBLOCK_ID' => $iblockId,
611 'ACTIVE' => 'Y',
612 'SECTION_ID' => intval($this->state['CURRENT_SECTION']),
613 '>ID' => intval($this->state['LAST_ELEMENT_ID']),
614 'SITE_ID' => $this->sitemapData['SITE_ID'],
615 "ACTIVE_DATE" => "Y",
616 ],
617 false,
618 ['nTopCount' => 1000],
619 ['ID', 'TIMESTAMP_X', 'DETAIL_PAGE_URL']
620 );
621 }
622 else
623 {
624 $this->state['LAST_ELEMENT_ID'] = 0;
625 $dbIblockResult = \CIBlockSection::GetList(
626 ['LEFT_MARGIN' => 'ASC'],
627 [
628 'IBLOCK_ID' => $iblockId,
629 'GLOBAL_ACTIVE' => 'Y',
630 '>LEFT_BORDER' => intval($this->state['LEFT_MARGIN']),
631 ],
632 false,
633 ['ID', 'TIMESTAMP_X', 'SECTION_PAGE_URL', 'LEFT_MARGIN', 'IBLOCK_SECTION_ID'],
634 ['nTopCount' => 100]
635 );
636 }
637 }
638
639 if (isset($this->state['CURRENT_SECTION']))
640 {
641 $arElement = $dbIblockResult->fetch();
642
643 if ($arElement)
644 {
645 if (!is_array($this->state['IBLOCK_MAP'][$iblockId]))
646 {
647 $this->state['IBLOCK_MAP'][$iblockId] = [];
648 }
649
650 if (!array_key_exists($arElement['ID'], $this->state['IBLOCK_MAP'][$iblockId]))
651 {
652 $arElement['LANG_DIR'] = $this->sitemapData['SITE']['DIR'];
653
654 $bCheckFinished = false;
655 $elementLastmod = MakeTimeStamp($arElement['TIMESTAMP_X']);
656 $this->state['IBLOCK_LASTMOD'] = max($this->state['IBLOCK_LASTMOD'], $elementLastmod);
657 $this->state['LAST_ELEMENT_ID'] = $arElement['ID'];
658
659 $this->state['IBLOCK'][$iblockId]['E']++;
660 $this->state['IBLOCK_MAP'][$iblockId][$arElement["ID"]] = 1;
661
662 // remove or replace SERVER_NAME
663 $url =
664 Source\Iblock::prepareUrlToReplace(
665 $arElement['DETAIL_PAGE_URL'],
666 $this->sitemapData['SITE_ID']
667 );
668 $url = \CIBlock::ReplaceDetailUrl($url, $arElement, false, "E");
669
670 $sitemapFile->addIBlockEntry($url, $elementLastmod);
671 }
672 }
673 elseif (!$bCheckFinished)
674 {
675 $bCheckFinished = true;
676 $dbIblockResult = null;
677 }
678 else
679 {
680 $bCheckFinished = false;
681 unset($this->state['CURRENT_SECTION']);
682 $this->state['LAST_ELEMENT_ID'] = 0;
683
684 $dbIblockResult = null;
685 if ($dbOldIblockResult)
686 {
687 $dbIblockResult = $dbOldIblockResult;
688 $dbOldIblockResult = null;
689 }
690 }
691 }
692 else
693 {
694 $arSection = $dbIblockResult->fetch();
695
696 if ($arSection)
697 {
698 $bCheckFinished = false;
699 $sectionLastmod = MakeTimeStamp($arSection['TIMESTAMP_X']);
700 $this->state['LEFT_MARGIN'] = $arSection['LEFT_MARGIN'];
701 $this->state['IBLOCK_LASTMOD'] = max($this->state['IBLOCK_LASTMOD'], $sectionLastmod);
702
703 $bActive = false;
704 $bActiveElement = false;
705
706 if (isset($this->sitemapData['SETTINGS']['IBLOCK_SECTION_SECTION'][$iblockId][$arSection['ID']]))
707 {
708 $bActive =
709 $this->sitemapData['SETTINGS']['IBLOCK_SECTION_SECTION'][$iblockId][$arSection['ID']] == 'Y';
710 $bActiveElement =
711 $this->sitemapData['SETTINGS']['IBLOCK_SECTION_ELEMENT'][$iblockId][$arSection['ID']] == 'Y';
712 }
713 elseif ($arSection['IBLOCK_SECTION_ID'] > 0)
714 {
715 $dbRes = RuntimeTable::getList([
716 'filter' => [
717 'PID' => $this->sitemapId,
718 'ITEM_TYPE' => RuntimeTable::ITEM_TYPE_SECTION,
719 'ITEM_ID' => $arSection['IBLOCK_SECTION_ID'],
720 'PROCESSED' => RuntimeTable::PROCESSED,
721 ],
722 'select' => ['ACTIVE', 'ACTIVE_ELEMENT'],
723 'limit' => 1,
724 ]);
725
726 $parentSection = $dbRes->fetch();
727 if ($parentSection)
728 {
729 $bActive = $parentSection['ACTIVE'] == RuntimeTable::ACTIVE;
730 $bActiveElement = $parentSection['ACTIVE_ELEMENT'] == RuntimeTable::ACTIVE;
731 }
732 }
733 else
734 {
735 $bActive = $this->sitemapData['SETTINGS']['IBLOCK_SECTION'][$iblockId] == 'Y';
736 $bActiveElement = $this->sitemapData['SETTINGS']['IBLOCK_ELEMENT'][$iblockId] == 'Y';
737 }
738
739 $arRuntimeData = [
740 'PID' => $this->sitemapId,
741 'ITEM_ID' => $arSection['ID'],
742 'ITEM_TYPE' => RuntimeTable::ITEM_TYPE_SECTION,
743 'ACTIVE' => $bActive ? RuntimeTable::ACTIVE : RuntimeTable::INACTIVE,
744 'ACTIVE_ELEMENT' => $bActiveElement ? RuntimeTable::ACTIVE : RuntimeTable::INACTIVE,
745 'PROCESSED' => RuntimeTable::PROCESSED,
746 ];
747
748 if ($bActive)
749 {
750 $this->state['IBLOCK'][$iblockId]['S']++;
751
752 $arSection['LANG_DIR'] = $this->sitemapData['SITE']['DIR'];
753
754 // remove or replace SERVER_NAME
755 $url =
756 Source\Iblock::prepareUrlToReplace(
757 $arSection['SECTION_PAGE_URL'],
758 $this->sitemapData['SITE_ID']
759 );
760 $url = \CIBlock::ReplaceDetailUrl($url, $arSection, false, "S");
761
762 $sitemapFile->addIBlockEntry($url, $sectionLastmod);
763 }
764
765 RuntimeTable::add($arRuntimeData);
766
767 if ($bActiveElement)
768 {
769 $this->state['CURRENT_SECTION'] = $arSection['ID'];
770 $this->state['LAST_ELEMENT_ID'] = 0;
771
772 $dbOldIblockResult = $dbIblockResult;
773 $dbIblockResult = null;
774 }
775 }
776 elseif (!$bCheckFinished)
777 {
778 unset($this->state['CURRENT_SECTION']);
779 $bCheckFinished = true;
780 $dbIblockResult = null;
781 }
782 else
783 {
784 $bCheckFinished = false;
785 // we have finished current iblock
786
787 RuntimeTable::update($runtimeIblock['ID'], [
788 'PROCESSED' => RuntimeTable::PROCESSED,
789 ]);
790
791 if ($this->sitemapData['SETTINGS']['IBLOCK_LIST'][$iblockId] == 'Y'
792 && $currentIBlock['LIST_PAGE_URL']
793 <> '')
794 {
795 $this->state['IBLOCK'][$iblockId]['I']++;
796
797 $currentIBlock['IBLOCK_ID'] = $currentIBlock['ID'];
798 $currentIBlock['LANG_DIR'] = $this->sitemapData['SITE']['DIR'];
799
800 // remove or replace SERVER_NAME
801 $url =
802 Source\Iblock::prepareUrlToReplace(
803 $currentIBlock['LIST_PAGE_URL'],
804 $this->sitemapData['SITE_ID']
805 );
806 $url = \CIBlock::ReplaceDetailUrl($url, $currentIBlock, false, "");
807
808 $sitemapFile->addIBlockEntry($url, $this->state['IBLOCK_LASTMOD']);
809 }
810
811 if ($sitemapFile->isNotEmpty())
812 {
813 if ($sitemapFile->isCurrentPartNotEmpty())
814 {
815 $sitemapFile->finish();
816 }
817 else
818 {
819 $sitemapFile->delete();
820 }
821
822 if (!is_array($this->state['XML_FILES']))
823 {
824 $this->state['XML_FILES'] = [];
825 }
826
827 $xmlFiles = $sitemapFile->getNameList();
828 $directory = $sitemapFile->getPathDirectory();
829 foreach ($xmlFiles as &$xmlFile)
830 $xmlFile = $directory . $xmlFile;
831 $this->state['XML_FILES'] = array_unique(array_merge($this->state['XML_FILES'], $xmlFiles));
832 }
833 else
834 {
835 $sitemapFile->delete();
836 }
837
838 $runtimeIblock = false;
839 $this->state['LEFT_MARGIN'] = 0;
840 $this->state['IBLOCK_LASTMOD'] = 0;
841 unset($this->state['CURRENT_SECTION']);
842 $this->state['LAST_ELEMENT_ID'] = 0;
843 }
844 }
845 }
846 }
847 if ($this->step < Step::STEPS[Step::STEP_IBLOCK] - 1)
848 {
849 $this->step++;
850 }
851
852 if ($isFinished)
853 {
854 $this->step = Step::STEPS[Step::STEP_IBLOCK];
855 $this->statusMessage = Loc::getMessage('SITEMAP_RUN_FINALIZE');
856 }
857
858 return $result;
859 }
860
861 protected function runForumIndex(): bool
862 {
863 $result = true;
864
865 $forumList = [];
866 if (!empty($this->sitemapData['SETTINGS']['FORUM_ACTIVE']))
867 {
868 foreach ($this->sitemapData['SETTINGS']['FORUM_ACTIVE'] as $forumId => $active)
869 {
870 if ($active == "Y")
871 {
872 $forumList[$forumId] = "Y";
873 }
874 }
875 }
876 if (count($forumList) > 0 && Loader::includeModule('forum'))
877 {
878 $arForums = [];
879 $db_res = \CForumNew::GetListEx(
880 [],
881 [
882 '@ID' => array_keys($forumList),
883 "ACTIVE" => "Y",
884 "SITE_ID" => $this->sitemapData['SITE_ID'],
885 "!TOPICS" => 0,
886 ]
887 );
888 while ($res = $db_res->Fetch())
889 {
890 $arForums[$res['ID']] = $res;
891 }
892 $forumList = array_intersect_key($arForums, $forumList);
893
894 foreach ($forumList as $id => $forum)
895 {
896 RuntimeTable::add([
897 'PID' => $this->sitemapId,
898 'PROCESSED' => RuntimeTable::UNPROCESSED,
899 'ITEM_ID' => $id,
900 'ITEM_TYPE' => RuntimeTable::ITEM_TYPE_FORUM,
901 ]
902 );
903
904 // $fileName = str_replace('#FORUM_ID#', $forumId, $this->sitemapData['SETTINGS']['FILENAME_FORUM']);
905 // $sitemapFile = new File\Runtime($this->sitemapId, $fileName, $this->sitemapDataSettings);
906 }
907 }
908
909 $this->state['FORUM_CURRENT_TOPIC'] = 0;
910
911 if (count($forumList) <= 0)
912 {
913 $this->step = Step::STEPS[Step::STEP_FORUM];
914 $this->statusMessage = Loc::getMessage('SITEMAP_RUN_FORUM_EMPTY');
915 }
916 else
917 {
918 $this->step = Step::STEPS[Step::STEP_FORUM_INDEX];
919 $this->statusMessage = Loc::getMessage('SITEMAP_RUN_FORUM');
920 }
921
922 return $result;
923 }
924
925 protected function runForum(): bool
926 {
927 $result = true;
928
929 $timeFinish = self::getTimeFinish();
930 $isFinished = false;
931 $runtimeForum = false;
932 $currentForum = null;
933 $forumId = 0;
934 $sitemapFile = null;
935 $dbTopicResult = null;
936 $arTopic = null;
937
938 while (!$isFinished && microtime(true) <= $timeFinish && \CModule::IncludeModule("forum"))
939 {
940 if (!$runtimeForum)
941 {
942 $dbRes = RuntimeTable::getList([
943 'order' => ['ID' => 'ASC'],
944 'filter' => [
945 'PID' => $this->sitemapId,
946 'ITEM_TYPE' => RuntimeTable::ITEM_TYPE_FORUM,
947 'PROCESSED' => RuntimeTable::UNPROCESSED,
948 ],
949 'limit' => 1,
950 ]);
951 $runtimeForum = $dbRes->fetch();
952
953 if ($runtimeForum)
954 {
955 $forumId = intval($runtimeForum['ITEM_ID']);
956
957 $db_res = \CForumNew::GetListEx(
958 [],
959 [
960 'ID' => $forumId,
961 "ACTIVE" => "Y",
962 "SITE_ID" => $this->sitemapData['SITE_ID'],
963 "!TOPICS" => 0,
964 ]
965 );
966 $currentForum = $db_res->Fetch();
967 if (!$currentForum)
968 {
969 RuntimeTable::update($runtimeForum['ID'], [
970 'PROCESSED' => RuntimeTable::PROCESSED,
971 ]);
972 $this->statusMessage = Loc::getMessage(
973 'SITEMAP_RUN_FORUM_NAME',
974 ['#FORUM_NAME#' => $currentForum['NAME']]
975 );
976 }
977 else
978 {
979 $fileName = str_replace('#FORUM_ID#', $forumId, $this->sitemapData['SETTINGS']['FILENAME_FORUM']);
980 $sitemapFile = new File\Runtime($this->sitemapId, $fileName, $this->getSitemapSettings());
981 }
982 }
983 }
984
985 if (!$runtimeForum || !$sitemapFile)
986 {
987 $isFinished = true;
988 }
989 elseif (is_array($currentForum))
990 {
991 $isActive =
992 array_key_exists($forumId, $this->sitemapData['SETTINGS']['FORUM_TOPIC'])
993 && $this->sitemapData['SETTINGS']['FORUM_TOPIC'][$forumId] == "Y"
994 ;
995 if ($isActive)
996 {
997 if ($dbTopicResult == null)
998 {
999 $dbTopicResult = \CForumTopic::GetList(
1000 ["LAST_POST_DATE" => "DESC"],
1001 array_merge(
1002 [
1003 "FORUM_ID" => $forumId,
1004 "APPROVED" => "Y",
1005 ],
1006 (
1007 $this->state['FORUM_CURRENT_TOPIC'] > 0
1008 ? [">ID" => $this->state["FORUM_CURRENT_TOPIC"]]
1009 : []
1010 )
1011 ),
1012 false,
1013 0,
1014 ['nTopCount' => 100]
1015 );
1016 }
1017 if (($arTopic = $dbTopicResult->fetch()) && $arTopic)
1018 {
1019 $this->state["FORUM_CURRENT_TOPIC"] = $arTopic["ID"];
1020 $url = \CForumNew::PreparePath2Message(
1021 $currentForum["PATH2FORUM_MESSAGE"],
1022 [
1023 "FORUM_ID" => $currentForum["ID"],
1024 "TOPIC_ID" => $arTopic["ID"],
1025 "TITLE_SEO" => $arTopic["TITLE_SEO"],
1026 "MESSAGE_ID" => "s",
1027 "SOCNET_GROUP_ID" => $arTopic["SOCNET_GROUP_ID"],
1028 "OWNER_ID" => $arTopic["OWNER_ID"],
1029 "PARAM1" => $arTopic["PARAM1"],
1030 "PARAM2" => $arTopic["PARAM2"],
1031 ]
1032 );
1033 $sitemapFile->addIBlockEntry($url, MakeTimeStamp($arTopic['LAST_POST_DATE']));
1034 }
1035 }
1036 else
1037 {
1038 $url = \CForumNew::PreparePath2Message(
1039 $currentForum["PATH2FORUM_MESSAGE"],
1040 [
1041 "FORUM_ID" => $currentForum["ID"],
1042 "TOPIC_ID" => $currentForum["TID"],
1043 "TITLE_SEO" => $currentForum["TITLE_SEO"],
1044 "MESSAGE_ID" => "s",
1045 "SOCNET_GROUP_ID" => $currentForum["SOCNET_GROUP_ID"],
1046 "OWNER_ID" => $currentForum["OWNER_ID"],
1047 "PARAM1" => $currentForum["PARAM1"],
1048 "PARAM2" => $currentForum["PARAM2"],
1049 ]
1050 );
1051 $sitemapFile->addIBlockEntry($url, MakeTimeStamp($currentForum['LAST_POST_DATE']));
1052 }
1053 if (empty($arTopic))
1054 {
1055 RuntimeTable::update($runtimeForum['ID'], [
1056 'PROCESSED' => RuntimeTable::PROCESSED,
1057 ]);
1058
1059 if ($sitemapFile->isNotEmpty())
1060 {
1061 if ($sitemapFile->isCurrentPartNotEmpty())
1062 {
1063 $sitemapFile->finish();
1064 }
1065 else
1066 {
1067 $sitemapFile->delete();
1068 }
1069
1070 if (!is_array($this->state['XML_FILES']))
1071 {
1072 $this->state['XML_FILES'] = [];
1073 }
1074
1075 $xmlFiles = $sitemapFile->getNameList();
1076 $directory = $sitemapFile->getPathDirectory();
1077 foreach ($xmlFiles as &$xmlFile)
1078 {
1079 $xmlFile = $directory . $xmlFile;
1080 }
1081 $this->state['XML_FILES'] = array_unique(array_merge($this->state['XML_FILES'], $xmlFiles));
1082 }
1083 else
1084 {
1085 $sitemapFile->delete();
1086 }
1087
1088 $runtimeForum = false;
1089 $dbTopicResult = null;
1090 $this->state['FORUM_CURRENT_TOPIC'] = 0;
1091 }
1092 }
1093 }
1094 if ($this->step < Step::STEPS[Step::STEP_FORUM] - 1)
1095 {
1096 $this->step++;
1097 }
1098
1099 if ($isFinished)
1100 {
1101 $this->step = Step::STEPS[Step::STEP_FORUM];
1102 $this->statusMessage = Loc::getMessage('SITEMAP_RUN_FINALIZE');
1103 }
1104
1105 return $result;
1106 }
1107
1108 protected function runIndex(): bool
1109 {
1110 $result = true;
1111
1112 RuntimeTable::clearByPid($this->sitemapId);
1113
1114 $sitemapFile = new File\Index($this->sitemapData['SETTINGS']['FILENAME_INDEX'], $this->getSitemapSettings());
1115 $xmlFiles = [];
1116 if (count($this->state['XML_FILES']) > 0)
1117 {
1118 foreach ($this->state['XML_FILES'] as $xmlFile)
1119 {
1120 $xmlFiles[] = new IO\File(
1122 $sitemapFile->getSiteRoot(),
1123 $xmlFile
1124 ), $this->sitemapData['SITE_ID']
1125 );
1126 }
1127 }
1128 $sitemapFile->createIndex($xmlFiles);
1129
1130 $existedSitemaps = [];
1131 if ($this->sitemapData['SETTINGS']['ROBOTS'] == 'Y')
1132 {
1133 $sitemapUrl = $sitemapFile->getUrl();
1134
1135 $robotsFile = new RobotsFile($this->sitemapData['SITE_ID']);
1136 $robotsFile->addRule([
1137 RobotsFile::SITEMAP_RULE, $sitemapUrl
1138 ]);
1139
1140 $sitemapLinks = $robotsFile->getRules(RobotsFile::SITEMAP_RULE);
1141 if (count($sitemapLinks) > 1) // 1 - just added rule
1142 {
1143 foreach ($sitemapLinks as $rule)
1144 {
1145 if ($rule[1] != $sitemapUrl)
1146 {
1147 $existedSitemaps[] = $rule[1];
1148 }
1149 }
1150 }
1151 }
1152 // todo: need show message about robots.txt
1153 // if (isset($arExistedSitemaps) && count($arExistedSitemaps) > 0)
1154 // {
1155 // echo BeginNote(), Loc::getMessage('SEO_SITEMAP_RUN_ROBOTS_WARNING', array(
1156 // "#SITEMAPS#" => "<li>" . implode("</li><li>", $arExistedSitemaps) . "</li>",
1157 // "#LANGUAGE_ID#" => LANGUAGE_ID,
1158 // "#SITE_ID#" => $arSitemap['SITE_ID'],
1159 // ));
1160 // }
1161
1162 $this->step = Step::STEPS[Step::STEP_INDEX];
1163 $this->statusMessage = Loc::getMessage('SITEMAP_RUN_FINISH');
1164
1165 return $result;
1166 }
1167
1168 protected function finish(): bool
1169 {
1170 $this->statusMessage = Loc::getMessage('SITEMAP_RUN_FINISH');
1171 SitemapTable::update($this->sitemapId, ['DATE_RUN' => new DateTime()]);
1172
1173 return true;
1174 }
1175
1176
1181 protected function getSitemapSettings(): array
1182 {
1183 return [
1184 'SITE_ID' => $this->sitemapData['SITE_ID'],
1185 'PROTOCOL' => $this->sitemapData['SETTINGS']['PROTO'] == 1 ? 'https' : 'http',
1186 'DOMAIN' => $this->sitemapData['SETTINGS']['DOMAIN'],
1187 ];
1188 }
1189
1194 protected static function getTimeFinish(): float
1195 {
1196 return microtime(true) + self::STEP_DURATION * 0.95;
1197 }
1198
1199
1200}
static combine()
Definition path.php:221
static loadMessages($file)
Definition loc.php:64
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
init(int $step, array $state)
Definition Generator.php:82
__construct(int $sitemapId)
Definition Generator.php:57
processDirectory($dirData, File\Base $sitemapFile)