185 Loc::loadMessages(__FILE__);
189 $this->isCloudAvailable =
193 $this->processToken = $this->request->get(
'PROCESS_TOKEN');
194 $this->exportType = $this->request->get(
'EXPORT_TYPE');
195 $this->componentName = $this->request->get(
'COMPONENT_NAME');
197 $signedParameters = $this->request->getPost(
'signedParameters');
198 if (!empty($signedParameters))
203 $initialOptions = $this->request->getPost(
'INITIAL_OPTIONS');
204 if (!empty($initialOptions))
206 $this->componentParameters[
'STEXPORT_INITIAL_OPTIONS'] = $initialOptions;
210 if (!empty($progressData))
212 $this->isNewProcess = (empty($progressData[
'processToken']) || $progressData[
'processToken'] !==
$this->processToken);
213 if (!$this->isNewProcess)
216 foreach ($this->fieldToStoreInProcess as $fieldName)
218 if (isset($progressData[$fieldName]))
220 $this->{$fieldName} = $progressData[$fieldName];
226 if ($this->isCloudAvailable)
229 if (empty($bucketList))
231 $this->isCloudAvailable =
false;
275 if ($this->isCloudAvailable && $this->useCloud ===
null)
278 ($this->bucketId < 0) &&
279 ($this->totalItems > 0) &&
280 ($this->processedItems > 0) &&
281 ($this->fileName !==
'') &&
283 (($this->
getSizeTempFile() > $this->cloudMinChunkSize) || $this->isExportCompleted)
286 if ($this->isExportCompleted)
292 $predictedFileSize = round($this->
getSizeTempFile() * ceil($this->totalItems / $this->processedItems) * 1.5);
295 if ($this->
findInitBucket(
array(
'fileSize' => $predictedFileSize,
'fileName' => $this->fileName)) ===
true)
298 $this->useCloud =
true;
303 $this->useCloud =
false;
304 $this->isCloudAvailable =
false;
309 if ($this->isNewProcess)
312 $this->stepCount = 0;
313 $this->timeStart = time();
314 $nextAction = self::ACTION_EXPORT;
316 elseif ($this->isBitrix24)
318 if ($this->isExportCompleted && !$this->isUploadFinished)
321 $nextAction = self::ACTION_UPLOAD;
323 elseif ($this->isExportCompleted && $this->isUploadFinished)
326 $nextAction = self::ACTION_PURGE;
331 $nextAction = self::ACTION_UPLOAD;
336 $nextAction = self::ACTION_EXPORT;
342 if ($this->isExportCompleted && ($this->useCloud ===
true) && !$this->isUploadFinished)
345 $nextAction = self::ACTION_UPLOAD;
347 elseif ($this->isExportCompleted && ($this->useCloud ===
true) && $this->isUploadFinished)
350 $nextAction = self::ACTION_PURGE;
352 elseif ($this->isExportCompleted && ($this->useCloud ===
false || $this->useCloud ===
null))
355 $nextAction = self::ACTION_FINISH;
360 $nextAction = self::ACTION_UPLOAD;
365 $nextAction = self::ACTION_EXPORT;
369 if ($nextAction === self::ACTION_PURGE)
373 if ($nextAction === self::ACTION_EXPORT)
378 if ($nextAction === self::ACTION_UPLOAD)
383 if ($nextAction === self::ACTION_FINISH)
430 if ($this->isNewProcess)
435 $this->processedItems = 0;
436 $this->totalItems = 0;
444 $nextPage = (int)floor($this->processedItems / $this->pageSize) + 1;
447 $this->componentParameters,
449 'STEXPORT_MODE' =>
'Y',
450 'EXPORT_TYPE' => $this->exportType,
451 'STEXPORT_PAGE_SIZE' => $this->pageSize,
452 'STEXPORT_TOTAL_ITEMS' => $this->totalItems,
453 'STEXPORT_LAST_EXPORTED_ID' => $this->lastExportedId,
454 'PAGE_NUMBER' => $nextPage,
460 $this->componentName,
464 $exportData = ob_get_contents();
467 $processedItemsOnStep = 0;
469 if (is_array($componentResult))
471 if (isset($componentResult[
'ERROR']))
478 if (isset($componentResult[
'PROCESSED_ITEMS']))
480 $processedItemsOnStep = (int)$componentResult[
'PROCESSED_ITEMS'];
484 if ($nextPage === 1 && isset($componentResult[
'TOTAL_ITEMS']))
486 $this->totalItems = (int)$componentResult[
'TOTAL_ITEMS'];
489 if (isset($componentResult[
'LAST_EXPORTED_ID']))
491 $this->lastExportedId = (int)$componentResult[
'LAST_EXPORTED_ID'];
496 if ($this->totalItems == 0)
501 if ($processedItemsOnStep > 0)
503 $this->processedItems += $processedItemsOnStep;
510 if ($this->isExportCompleted && !$this->isCloudAvailable)
516 elseif ($processedItemsOnStep == 0)
519 $this->isExportCompleted =
true;
521 if (!$this->isCloudAvailable)
527 if ($this->isExportCompleted ===
true)
540 if ($this->totalItems == 0)
542 $this->isExportCompleted =
true;
549 $result[
'STATUS'] = self::STATUS_COMPLETED;
557 $result[
'STATUS'] = self::STATUS_PROGRESS;
573 $isUploadStarted = ($this->uploadedPart > 0);
574 if (!$isUploadStarted)
576 $reservedSize = round($chunkSize * ceil($this->totalItems / $this->pageSize) * 1.5);
581 'fileSize' => $reservedSize,
582 'fileName' => $this->uploadPath,
589 if ($this->bucket->FileExists($this->uploadPath))
591 if(!$this->bucket->DeleteFile($this->uploadPath))
606 if (!file_exists($this->filePath))
613 return AjaxJson::createError($this->errorCollection);
619 if ($this->isExportCompleted && !$isUploadStarted)
623 'name' => $this->fileName,
624 'size' => $this->fileSize,
625 'type' => $this->fileType,
626 'tmp_name' => $this->filePath,
629 if ($this->bucket->SaveFile($this->uploadPath, $uploadFile))
631 $this->uploadedPart ++;
632 $this->uploadedSize += $chunkSize;
634 $this->isUploadFinished =
true;
643 $uploader = new \CCloudStorageUpload($this->uploadPath);
644 if (!$uploader->isStarted())
646 if (!$uploader->Start($this->bucketId, $reservedSize, $this->fileType))
650 return AjaxJson::createError($this->errorCollection);
656 while ($uploader->hasRetries())
658 if ($uploader->Next($part, $this->bucket))
660 $this->uploadedPart ++;
661 $this->uploadedSize += $chunkSize;
669 if ($isSuccess && $this->isExportCompleted)
671 if ($uploader->Finish())
673 $this->isUploadFinished =
true;
692 $result[
'STATUS'] = self::STATUS_PROGRESS;
764 $now = new \DateTime(
'now');
767 if (preg_match(
'/^([^_]+)_([0-9]{8})_([^_]+)_.+$/i',
$fileName, $parts))
771 $date = \DateTime::createFromFormat(
'Ymd', $parts[2]);
772 $interval = $now->diff($date);
773 if ($interval->d > self::EXPIRE_DAYS)
813 if (
$action == self::ACTION_CLEAR ||
$action == self::ACTION_CANCEL ||
$action == self::ACTION_PURGE)
820 if (!$this->isExportCompleted && $this->uploadedSize > 0)
824 elseif ($this->isExportCompleted && $this->uploadedSize > $this->fileSize)
830 'STATUS' => ($this->isExportCompleted ? self::STATUS_COMPLETED : self::STATUS_PROGRESS),
831 'PROCESSED_ITEMS' => $this->processedItems,
832 'TOTAL_ITEMS' => $this->totalItems,
833 'UPLOADED_PART' => $this->uploadedPart,
834 'UPLOADED_SIZE' => $this->uploadedSize,
835 'UPLOADED_SIZE_FORMAT' => \CFile::FormatSize($this->uploadedSize),
836 'FILE_SIZE_FORMAT' => \CFile::FormatSize(
$fileSize),
839 $messagePlaceholders =
array(
840 '#PROCESSED_ITEMS#' => $this->processedItems,
841 '#TOTAL_ITEMS#' => $this->totalItems,
842 '#UPLOADED_PART#' => $this->uploadedPart,
843 '#UPLOADED_SIZE#' => $this->uploadedSize,
844 '#UPLOADED_SIZE_FORMAT#' => \CFile::FormatSize($this->uploadedSize),
845 '#FILE_SIZE_FORMAT#' => \CFile::FormatSize(
$fileSize),
849 if (
$action == self::ACTION_VOID)
868 htmlspecialcharsbx(Loc::getMessage(
'MAIN_EXPORT_ACTION_UPLOAD', $messagePlaceholders)).
'<br>'.
874 htmlspecialcharsbx(Loc::getMessage(
'MAIN_EXPORT_ACTION_EXPORT', $messagePlaceholders)).
'<br>'.
877 elseif ($this->isExportCompleted)
881 htmlspecialcharsbx(Loc::getMessage(
'MAIN_EXPORT_ACTION_EXPORT', $messagePlaceholders));
884 if ($this->isBitrix24 || $this->useCloud ===
true)
886 if ($this->isUploadFinished)
895 if ($downloadLink !==
'')
897 $result[
'DOWNLOAD_LINK'] = $downloadLink;
906 htmlspecialcharsbx(Loc::getMessage(
'MAIN_EXPORT_ACTION_EXPORT', $messagePlaceholders)).
'<br>'.
923 $avgStepDuration = $predictedStepCount = $predictedTimeDuration = 0;
925 if ($this->stepCount > 0 && $this->timeStart > 0)
927 $avgStepDuration = ceil((time() - $this->timeStart) / $this->stepCount);
928 if ($this->processedItems > 0)
930 $avgRowsPerStep = ceil($this->processedItems / $this->stepCount);
932 if ($avgRowsPerStep < 1)
937 if ($this->totalItems > 0)
939 $predictedStepCount = ceil(($this->totalItems - $this->processedItems) / $avgRowsPerStep);
940 if ($this->useCloud ===
true)
942 $predictedStepCount *= 2;
945 if ($avgStepDuration > 0 && $predictedStepCount > 0)
947 $predictedTimeDuration = $avgStepDuration * $predictedStepCount * 1.1;
949 if ($predictedTimeDuration > 0)
951 $predictedTimeDurationHours = floor($predictedTimeDuration / 3600);
952 if ($predictedTimeDurationHours > 0)
954 $predictedTimeDurationMinutes = ceil(($predictedTimeDuration - $predictedTimeDurationHours * 3600) / 60);
956 Loc::getMessage(
'MAIN_EXPORT_EXPECTED_DURATION').
' '.
957 Loc::getMessage(
'MAIN_EXPORT_EXPECTED_DURATION_HOURS',
array(
958 '#HOURS#' => $predictedTimeDurationHours,
959 '#MINUTES#' => $predictedTimeDurationMinutes,
964 $predictedTimeDurationMinutes = ceil($predictedTimeDuration / 60);
966 Loc::getMessage(
'MAIN_EXPORT_EXPECTED_DURATION').
' '.
967 Loc::getMessage(
'MAIN_EXPORT_EXPECTED_DURATION_MINUTES',
array(
968 '#MINUTES#' => ($predictedTimeDurationMinutes < 1 ?
"< 1" : $predictedTimeDurationMinutes),
1019 if (empty($this->module))
1021 $this->
addError(
new Error(
'Module Id property is not filled.'));
1025 $this->
addError(
new Error(
'Module '.$this->module.
' is not included.'));
1028 if ($this->isBitrix24)
1030 if ($this->isCloudAvailable !==
true)
1032 $this->
addError(
new Error(Loc::getMessage(
'MAIN_EXPORT_ERROR_NO_CLOUD_BUCKET')));
1036 if (
$action->getName() === self::ACTION_PURGE)
1041 if ($this->componentName ===
'')
1043 $this->
addError(
new Error(
'Component name is not specified.'));
1045 if (!in_array($this->exportType,
array(self::EXPORT_TYPE_CSV, self::EXPORT_TYPE_EXCEL),
true))
1047 $this->
addError(
new Error(
'The export type is not supported.'));
1050 if($this->processToken ===
'')
1052 $this->
addError(
new Error(
'Process token is not specified.'));
1327 $file = fopen($this->filePath,
'ab');
1328 if(is_resource($file))
1331 if($precedeUtf8Bom ===
true && (filesize($this->filePath) === 0))
1333 fwrite($file, chr(239).chr(187).chr(191));
1336 fwrite($file,
$data);
1340 $this->fileSize = filesize($this->filePath);