$cached : $unlimitedMaxWorkerTime; } /** * Will be called, automatically, when Serialize * * @return array */ public function __serialize(): array { $data = JsonSerialize::serializeToData($this, JsonSerialize::JSON_SKIP_MAGIC_METHODS | JsonSerialize::JSON_SKIP_CLASS_NAME); return $this->encryptSerializedProperties($data); } /** * Unserialize * * @param array $data Serialized data * * @return void */ public function __unserialize(array $data): void { // Decrypt properties $data = $this->decryptSerializedProperties($data); if ($this->isDecryptError()) { $this->saveOnShutdown(); } // Convert packageMysqldumpOptions arrays to GroupOptions objects $loadedOptionNames = []; if (isset($data['packageMysqldumpOptions']) && is_array($data['packageMysqldumpOptions'])) { foreach ($data['packageMysqldumpOptions'] as $index => $optionData) { $data['packageMysqldumpOptions'][$index] = GroupOptions::getObjectFromArray($optionData); // @phpstan-ignore-line $loadedOptionNames[] = $data['packageMysqldumpOptions'][$index]->getOptionName(); } } // Merge with default options for missing mysqldump modes foreach ($this->getDefaultMysqlDumpOptions() as $defOpt) { if (in_array($defOpt->getOptionName(), $loadedOptionNames)) { continue; } $data['packageMysqldumpOptions'][] = $defOpt; } // Assign properties foreach ($data as $pName => $val) { if (!property_exists($this, $pName)) { continue; } $this->$pName = $val; } } /** * Return default options * * @return GroupOptions[] */ private function getDefaultMysqlDumpOptions(): array { return [ new GroupOptions('quick', self::INPUT_MYSQLDUMP_OPTION_PREFIX, false), new GroupOptions('extended-insert', self::INPUT_MYSQLDUMP_OPTION_PREFIX, false), new GroupOptions('routines', self::INPUT_MYSQLDUMP_OPTION_PREFIX, true), new GroupOptions('disable-keys', self::INPUT_MYSQLDUMP_OPTION_PREFIX, false), new GroupOptions('compact', self::INPUT_MYSQLDUMP_OPTION_PREFIX, false), ]; } /** * This function is called on first istance of singletion object * Can be used to set dynamic properties values * * @return void */ protected function firstIstanceInit(): void { $result = $this->reset( [], [ self::class, 'getDefaultPropInitVal', ], function (): void { $this->setBuildMode(); } ); if ($result === false) { throw new Exception('Can\'t reset the user settings'); } } /** * Return default prop val by system config * * @param string $name prop nam * @param mixed $val prop val * * @return mixed */ protected static function getDefaultPropInitVal(string $name, $val) { switch ($name) { case 'cleanup_email': return get_option('admin_email'); case 'email_summary_recipients': return EmailSummary::getDefaultRecipients(); case 'usageTracking': return (bool) apply_filters('duplicator_default_usage_tracking', $val); } return $val; } /** * Reset default values * * @return bool */ public function resetUserSettings(): bool { try { StaticGlobal::reset(); $result = $this->reset( [ 'manual_mode_storage_ids', 'last_system_check_timestamp', 'initial_activation_timestamp', ], [ self::class, 'getDefaultPropInitVal', ], function (): void { $this->setBuildMode(); } ); if ($result == false) { throw new Exception('Can\'t reset global entity values'); } if (DynamicGlobalEntity::getInstance()->resetUserSettings() == false) { throw new Exception('Can\'t save secure global'); } } catch (Exception $e) { DupLog::traceError('Reset user settings error mrg: ' . $e->getMessage()); return false; } return true; } /** * Get usage tracking * * @return bool */ public function getUsageTracking(): bool { return $this->usageTracking; } /** * Set usage tracking * * @param bool $value value * * @return void */ public function setUsageTracking($value): void { if (DUPLICATOR_USTATS_DISALLOW) { // @phpstan-ignore-line // If usagfe tracking is hardcoded disabled, don't change the setting value return; } $value = (bool) $value; $oldValue = $this->usageTracking; $this->usageTracking = $value; if ($value == false && $oldValue != $value) { CommStats::disableUsageTracking(); } } /** * Whether SSL certificate verification is enabled * * @return bool */ public function isSslVerifyEnabled(): bool { return !$this->ssl_disableverify; } /** * Set whether SSL certificate verification is disabled * * @param bool $disable true to disable verification * * @return void */ public function setSslDisableVerify(bool $disable): void { $this->ssl_disableverify = $disable; } /** * Whether to use the server's SSL certificates instead of bundled ones * * @return bool */ public function isUsingServerCerts(): bool { return $this->ssl_useservercerts; } /** * Set whether to use server's SSL certificates * * @param bool $useServerCerts true to use server certificates * * @return void */ public function setSslUseServerCerts(bool $useServerCerts): void { $this->ssl_useservercerts = $useServerCerts; } /** * Get the SSL certificate path to use * * Returns empty string to use server's default certificates, * or the bundled certificate path. * * @return string */ public function getSslCertPath(): string { return $this->ssl_useservercerts ? '' : DUPLICATOR_CERT_PATH; } /** * Update global settings after install * * @return bool true on success false on failure */ public function updateAftreInstall(): bool { if ($this->getBuildMode() !== PackageArchive::BUILD_MODE_DUP_ARCHIVE) { $this->setBuildMode(); } AsyncSetupActions::resetAndReschedule(); return $this->save(); } /** * To export data * * @return array */ public function settingsExport(): array { $skipProps = [ 'id', 'last_system_check_timestamp', 'initial_activation_timestamp', 'manual_mode_storage_ids', 'basic_auth_password', 'lkp', 'uninstall_settings', 'uninstall_packages', 'crypt', 'import_chunk_size', 'import_custom_path', 'recoveryCustomPath', ]; $data = JsonSerialize::serializeToData($this, JsonSerialize::JSON_SKIP_MAGIC_METHODS | JsonSerialize::JSON_SKIP_CLASS_NAME); foreach ($skipProps as $prop) { unset($data[$prop]); } return $data; } /** * Update object properties from import data * * @param array $data data to import * @param string $dataVersion version of data * @param array $extraData extra data, useful form id mapping etc. * * @return bool True if success, otherwise false */ public function settingsImport($data, $dataVersion, array $extraData = []): bool { $skipProps = [ 'id', 'last_system_check_timestamp', 'initial_activation_timestamp', 'manual_mode_storage_ids', 'license_key_visible', 'lkp', 'basic_auth_password', 'uninstall_settings', 'uninstall_packages', 'crypt', 'import_chunk_size', 'import_custom_path', 'recoveryCustomPath', ]; $reflect = new ReflectionClass(self::class); $props = $reflect->getProperties(); foreach ($props as $prop) { if (in_array($prop->getName(), $skipProps)) { continue; } if (!isset($data[$prop->getName()])) { continue; } if (PHP_VERSION_ID < 80100) { $prop->setAccessible(true); } $prop->setValue($this, $data[$prop->getName()]); } return true; } /** * Set from object * * @param self $global_data global data * * @return void */ public function setFromImportData(self $global_data): void { $reflect = new ReflectionClass(self::class); $props = $reflect->getProperties(); $skipProps = [ 'id', 'last_system_check_timestamp', 'initial_activation_timestamp', 'manual_mode_storage_ids', 'license_key_visible', 'lkp', ]; foreach ($props as $prop) { if (in_array($prop->getName(), $skipProps)) { continue; } if (PHP_VERSION_ID < 80100) { $prop->setAccessible(true); } $prop->setValue($this, $prop->getValue($global_data)); } } /** * Check if build mode is available * * @param int $buildMode ENUM PackageArchive::BUILD_MODE_* * * @return bool */ public static function isBuildModeAvailable(int $buildMode): bool { switch ($buildMode) { case PackageArchive::BUILD_MODE_UNCONFIGURED: return false; case PackageArchive::BUILD_MODE_SHELL_EXEC: return (ShellZipUtils::getShellExecZipPath() != null); case PackageArchive::BUILD_MODE_ZIP_ARCHIVE: return ZipArchiveExtended::isPhpZipAvailable(); case PackageArchive::BUILD_MODE_DUP_ARCHIVE: return true; default: throw new Exception('Invalid engine'); } } /** * Return Backup build mode * * @return int Return enum PackageArchive::BUILD_MODE_* */ public function getBuildMode(): int { $archive_build_mode = $this->archive_build_mode; switch ($archive_build_mode) { case PackageArchive::BUILD_MODE_UNCONFIGURED: if (self::shouldDefaultToDupArchive()) { $archive_build_mode = PackageArchive::BUILD_MODE_DUP_ARCHIVE; } elseif (self::isBuildModeAvailable(PackageArchive::BUILD_MODE_SHELL_EXEC)) { $archive_build_mode = PackageArchive::BUILD_MODE_SHELL_EXEC; } elseif (self::isBuildModeAvailable(PackageArchive::BUILD_MODE_ZIP_ARCHIVE)) { $archive_build_mode = PackageArchive::BUILD_MODE_ZIP_ARCHIVE; } else { $archive_build_mode = PackageArchive::BUILD_MODE_DUP_ARCHIVE; } break; case PackageArchive::BUILD_MODE_SHELL_EXEC: if (!self::isBuildModeAvailable(PackageArchive::BUILD_MODE_SHELL_EXEC)) { if (self::isBuildModeAvailable(PackageArchive::BUILD_MODE_ZIP_ARCHIVE)) { $archive_build_mode = PackageArchive::BUILD_MODE_ZIP_ARCHIVE; } else { $archive_build_mode = PackageArchive::BUILD_MODE_DUP_ARCHIVE; } } break; case PackageArchive::BUILD_MODE_ZIP_ARCHIVE: if (!self::isBuildModeAvailable(PackageArchive::BUILD_MODE_ZIP_ARCHIVE)) { if (self::isBuildModeAvailable(PackageArchive::BUILD_MODE_SHELL_EXEC)) { $archive_build_mode = PackageArchive::BUILD_MODE_SHELL_EXEC; } else { $archive_build_mode = PackageArchive::BUILD_MODE_DUP_ARCHIVE; } } break; case PackageArchive::BUILD_MODE_DUP_ARCHIVE: break; default: throw new Exception('Invalid engine'); } return $archive_build_mode; } /** * Return true if the environment should prefer DupArchive for an unconfigured install. * * @return bool */ protected static function shouldDefaultToDupArchive(): bool { $maxExecutionTime = SnapUtil::phpIniGet("max_execution_time", 30, 'int'); return ( $maxExecutionTime > 0 && $maxExecutionTime < Constants::DUPARCHIVE_DEFAULT_MAX_EXECUTION_TIME && !SnapUtil::isIniValChangeable('max_execution_time') ); } /** * Selt build mode and return it * * @param bool $save if true save update global entity only if build mode is changed * * @return int Return enum PackageArchive::BUILD_MODE_* */ public function setBuildMode(bool $save = false): int { $newBuildMode = apply_filters('duplicator_default_archive_build_mode', $this->getBuildMode()); if ($newBuildMode != $this->archive_build_mode) { $this->archive_build_mode = $newBuildMode; if ($save) { $this->save(); } } return $this->archive_build_mode; } /** * * @return int<0,max> microsenconds */ public function getMicrosecLoadReduction(): int { return ServerThrottle::microsecondsFromThrottle($this->server_load_reduction); } /** * set db mode ant all related params. * check mysqldump * * @param null|string $dbMode if null get INPUT_POST * @param null|int $phpDumpMode if null get INPUT_POST * @param null|int $dbPhpQueryLimit if null get INPUT_POST * @param null|string $packageMysqldumpPath if null get INPUT_POST * @param null|int $dbMysqlDumpQueryLimit if null get INPUT_POST * * @return void */ public function setDbMode( $dbMode = null, $phpDumpMode = null, $dbPhpQueryLimit = null, $packageMysqldumpPath = null, $dbMysqlDumpQueryLimit = null ): void { //DATABASE $dbMode ??= SnapUtil::sanitizeDefaultInput(INPUT_POST, '_package_dbmode'); $phpDumpMode ??= filter_input( INPUT_POST, '_phpdump_mode', FILTER_VALIDATE_INT, [ 'options' => [ 'default' => 0, 'min_range' => 0, 'max_range' => 1, ], ] ); $dbMysqlDumpQueryLimit ??= filter_input( INPUT_POST, '_package_mysqldump_qrylimit', FILTER_VALIDATE_INT, [ 'options' => [ 'default' => Constants::DEFAULT_MYSQL_DUMP_CHUNK_SIZE, 'min_range' => Constants::MYSQL_DUMP_CHUNK_SIZE_MIN_LIMIT, 'max_range' => Constants::MYSQL_DUMP_CHUNK_SIZE_MAX_LIMIT, ], ] ); $packageMysqldumpPath ??= SnapUtil::sanitizeDefaultInput(INPUT_POST, '_package_mysqldump_path'); $packageMysqldumpPath = SnapUtil::sanitizeNSCharsNewlineTabs($packageMysqldumpPath); $packageMysqldumpPath = preg_match('/^([A-Za-z]\:)?[\/\\\\]/', $packageMysqldumpPath) ? $packageMysqldumpPath : ''; $packageMysqldumpPath = preg_replace('/[\'"]/m', '', $packageMysqldumpPath); $packageMysqldumpPath = SnapIO::safePathUntrailingslashit($packageMysqldumpPath); $mysqlDumpPath = empty($packageMysqldumpPath) ? WpDbUtils::getMySqlDumpPath() : $packageMysqldumpPath; if ($dbMode == 'mysql' && empty($mysqlDumpPath)) { $dbMode = 'php'; } $this->package_mysqldump = ($dbMode == 'mysql'); $this->package_phpdump_mode = $phpDumpMode; $this->package_mysqldump_path = $packageMysqldumpPath; $this->package_mysqldump_qrylimit = $dbMysqlDumpQueryLimit; foreach ($this->getMysqldumpOptions() as $option) { $option->update(); } } /** * Sets cleanup fields and configures WP Cron accordingly * * @param int $cleanup_mode Cleanup mode to set * @param string $cleanup_email Email address to send cleanup notification to * @param int $auto_cleanup_hours Number of hours after which cleanup should be performed * * @return void */ public function setCleanupFields( $cleanup_mode = null, $cleanup_email = null, $auto_cleanup_hours = null ): void { $this->cleanup_mode = $cleanup_mode ?? filter_input( INPUT_POST, 'cleanup_mode', FILTER_VALIDATE_INT, [ 'options' => [ 'default' => self::CLEANUP_MODE_OFF, 'min_range' => 0, 'max_range' => 2, ], ] ); $email = filter_input(INPUT_POST, 'cleanup_email', FILTER_VALIDATE_EMAIL, ['options' => ['default' => '']]); $email = $email === '' ? get_option('admin_email') : $email; $this->cleanup_email = $cleanup_email ?? $email; $this->auto_cleanup_hours = $auto_cleanup_hours ?? filter_input( INPUT_POST, 'auto_cleanup_hours', FILTER_VALIDATE_INT, [ 'options' => [ 'default' => 24, 'min_range' => 1, ], ] ); self::cleanupScheduleSetup(); } /** * Schedules cron event for installer files cleanup purposes, * and unschedules it if it's not needed anymore. * * @return void */ public static function cleanupScheduleSetup(): void { DupLog::trace("CLEANUP SCHEDULE SETUP"); $global = self::getInstance(); CronUtils::unscheduleEvent(self::CLEANUP_HOOK); if ($global->cleanup_mode == self::CLEANUP_MODE_MAIL) { $nextRunTime = time() + self::CLEANUP_EMAIL_NOTICE_INTERVAL * 3600; CronUtils::scheduleEvent($nextRunTime, self::CLEANUP_INTERVAL_NAME, self::CLEANUP_HOOK); } elseif ($global->cleanup_mode == self::CLEANUP_MODE_AUTO) { $nextRunTime = time() + $global->auto_cleanup_hours * 3600; CronUtils::scheduleEvent($nextRunTime, self::CLEANUP_INTERVAL_NAME, self::CLEANUP_HOOK); } } /** * Customizes schedules according to current cleanup_mode. If necessary, it * adds a custom cron schedule that will run every N hours. * * @param array $schedules An array of non-default cron schedules. * * @return array Filtered array of non-default cron schedules. */ public static function customCleanupCronInterval(array $schedules): array { $global = self::getInstance(); switch ($global->cleanup_mode) { case self::CLEANUP_MODE_OFF: // No need to modify anything break; case self::CLEANUP_MODE_MAIL: $schedules[self::CLEANUP_INTERVAL_NAME] = [ 'interval' => self::CLEANUP_EMAIL_NOTICE_INTERVAL * 3600, // In seconds, every N hours 'display' => sprintf(esc_html__('Every %1$d hours', 'duplicator-pro'), self::CLEANUP_EMAIL_NOTICE_INTERVAL), ]; break; case self::CLEANUP_MODE_AUTO: $schedules[self::CLEANUP_INTERVAL_NAME] = [ 'interval' => $global->auto_cleanup_hours * 3600, // In seconds, every N hours 'display' => sprintf(esc_html__('Every %1$d hours', 'duplicator-pro'), $global->auto_cleanup_hours), ]; break; default: throw new Exception('Invalid cleanup mode:' . SnapLog::v2str($global->cleanup_mode)); } return $schedules; } /** * The function that gets executed by WP Cron for cleanup of installer files. * It does different tasks based on current cleanup_mode setting. * * @return void */ public static function cleanupCronJob(): void { $global = self::getInstance(); DupLog::trace("CLEANUP CRON JOB"); $websiteUrl = SnapURL::getCurrentUrl(false, false, 1); $to = $global->cleanup_email; if (empty($to)) { $to = get_option('admin_email'); } switch ($global->cleanup_mode) { case self::CLEANUP_MODE_MAIL: // Email Notice cron job routine for cleanup of installer files $listOfInstallerFiles = MigrationMng::checkInstallerFilesList(); $filesToRemove = []; foreach ($listOfInstallerFiles as $path) { if (time() - filectime($path) > self::CLEANUP_FILE_TIME_DELAY) { $filesToRemove[] = $path; } } if (count($filesToRemove) > 0 && !empty($to)) { // Send an Email Notice in the site language regardless of the sending request's locale $switchedLocale = switch_to_locale(get_locale()); $subject = __("Action required", 'duplicator-pro'); $message = sprintf( /* translators: %1$s: plugin name, %2$s: website URL */ __('This email is sent by your WordPress plugin "%1$s" from website: %2$s. ', 'duplicator-pro'), esc_html(DUPLICATOR____NAME), $websiteUrl ); $message .= __('You received this email because Cleanup mode is set to "Email Notice". ', 'duplicator-pro'); $message .= __('The cleanup routine discovered that some installer files (leftovers from migration) were not removed. ', 'duplicator-pro'); $message .= __('We strongly advise you to remove these files. ', 'duplicator-pro'); $message .= __('Here is the list of files found on your website that you should remove:', 'duplicator-pro') . "
"; foreach ($filesToRemove as $path) { $message .= "-> $path
"; } $message .= "
"; $message .= __('Note: You could enable "Auto Cleanup" mode if you go to:', 'duplicator-pro') . "
"; $message .= sprintf( /* translators: %s: plugin name */ __('WordPress Admin > %s > Settings > Backups Tab > Cleanup.', 'duplicator-pro'), esc_html(DUPLICATOR____NAME) ) . "
"; $message .= __('That mode will do cleanup of those files automatically for you.', 'duplicator-pro') . "
"; $message .= "
"; $message .= __('Best regards,', 'duplicator-pro') . "
"; $message .= esc_html(DUPLICATOR____NAME); if (wp_mail($to, $subject, $message, ['Content-Type: text/html; charset=UTF-8'])) { // OK DupLog::trace('wp_mail sent email notice regarding cleanup of installer files'); } else { DupLog::trace("Problem sending email notice regarding cleanup of installer files to {$to}"); } if ($switchedLocale) { restore_previous_locale(); } } break; case self::CLEANUP_MODE_AUTO: // Auto Cleanup cron job routine for cleanup of installer files $installerFiles = MigrationMng::cleanMigrationFiles(false, self::CLEANUP_FILE_TIME_DELAY); if (count($installerFiles) == 0) { // No installer files were found, so we do nothing else return; } $filesFailedRemoval = []; foreach ($installerFiles as $path => $success) { if (!$success) { $filesFailedRemoval[] = $path; } } if (count($filesFailedRemoval) == 0) { // All found installer files were removed successfully, // or they did not even need to be removed yet because of CLEANUP_FILE_TIME_DELAY return; } // If this is executed that means that some of installer files // could not be removed for some reason (permission issues?) if (!empty($to)) { // Send an Email Notice about files that could not be removed during auto cleanup, // in the site language regardless of the sending request's locale $switchedLocale = switch_to_locale(get_locale()); $subject = __("Action required", 'duplicator-pro'); $message = sprintf( /* translators: %1$s: plugin name, %2$s: website URL */ __('This email is sent by your WordPress plugin "%1$s" from website: %2$s. ', 'duplicator-pro'), esc_html(DUPLICATOR____NAME), $websiteUrl ); $message .= __('"Auto Cleanup" mode is ON, ', 'duplicator-pro'); $message .= __( 'however the cleanup routine discovered that some installer files (leftovers from migration) could not be removed. ', 'duplicator-pro' ); $message .= __('We strongly advise you to remove those files manually. ', 'duplicator-pro'); $message .= __('Here is the list of files found on your website that you should remove:', 'duplicator-pro') . "
"; foreach ($filesFailedRemoval as $path) { $message .= "-> $path
"; } $message .= "
"; $message .= __('Those files probably could not be removed due to permission issues. ', 'duplicator-pro'); $message .= sprintf( __('You can find more info in FAQ %1$son this link%2$s.', 'duplicator-pro'), "", "" ) . "
"; $message .= "
"; $message .= __('Note: To edit "Cleanup" settings go to:', 'duplicator-pro') . "
"; $message .= sprintf( /* translators: %s: plugin name */ __('WordPress Admin > %s > Settings > Backups Tab > Cleanup.', 'duplicator-pro'), esc_html(DUPLICATOR____NAME) ) . "
"; $message .= "
"; $message .= __('Best regards,', 'duplicator-pro') . "
"; $message .= esc_html(DUPLICATOR____NAME); if (wp_mail($to, $subject, $message, ['Content-Type: text/html; charset=UTF-8'])) { // OK DupLog::trace('wp_mail sent email notice regarding failed auto cleanup of installer files'); } else { DupLog::trace("Problem sending email notice regarding failed auto cleanup of installer files to {$to}"); } if ($switchedLocale) { restore_previous_locale(); } } break; case self::CLEANUP_MODE_OFF: default: break; } } /** * Set archive mode * * @param ?int $archiveBuildMode Archive build mode, if null get INPUT_POST * @param ?int $zipArchiveMode Zip archive mode, if null get INPUT_POST * @param ?bool $archiveCompression Archive compression, if null get INPUT_POST * @param ?bool $ziparchiveValidation Zip archive validation, if null get INPUT_POST * @param ?int $ziparchiveChunkSizeInMb Zip archive chunk size in MB, if null get INPUT_POST * * @return void */ public function setArchiveMode( $archiveBuildMode = null, $zipArchiveMode = null, $archiveCompression = null, $ziparchiveValidation = null, $ziparchiveChunkSizeInMb = null ): void { $isZipAvailable = (ShellZipUtils::getShellExecZipPath() != null); $prelimBuildMode = $archiveBuildMode ?? filter_input( INPUT_POST, 'archive_build_mode', FILTER_VALIDATE_INT, [ 'options' => [ 'min_range' => 1, 'max_range' => 3, ], ] ); // Something has changed which invalidates Shell exec so move it to ZA $this->archive_build_mode = (!$isZipAvailable && $prelimBuildMode == PackageArchive::BUILD_MODE_SHELL_EXEC) ? PackageArchive::BUILD_MODE_ZIP_ARCHIVE : $prelimBuildMode; $this->ziparchive_mode = $zipArchiveMode ?? filter_input( INPUT_POST, 'ziparchive_mode', FILTER_VALIDATE_INT, [ 'options' => [ 'default' => 0, 'min_range' => 0, 'max_range' => 1, ], ] ); $this->archive_compression = $archiveCompression ?? filter_input(INPUT_POST, 'archive_compression', FILTER_VALIDATE_BOOLEAN); $this->ziparchive_validation = $ziparchiveValidation ?? filter_input(INPUT_POST, 'ziparchive_validation', FILTER_VALIDATE_BOOLEAN); $this->ziparchive_chunk_size_in_mb = $ziparchiveChunkSizeInMb ?? filter_input( INPUT_POST, 'ziparchive_chunk_size_in_mb', FILTER_VALIDATE_INT, [ 'options' => [ 'default' => Constants::DEFAULT_ZIP_ARCHIVE_CHUNK, 'min_range' => 1, ], ] ); } /** * Get archive engine label * * @return string */ public function getArchiveEngine(): string { $mode = ''; switch ($this->archive_build_mode) { case PackageArchive::BUILD_MODE_ZIP_ARCHIVE: $mode = ($this->ziparchive_mode == PackageArchive::ZIP_MODE_MULTI_THREAD) ? __("ZipArchive: multi-thread", 'duplicator-pro') : __("ZipArchive: single-thread", 'duplicator-pro'); break; case PackageArchive::BUILD_MODE_DUP_ARCHIVE: $mode = __('DupArchive', 'duplicator-pro'); break; default: $mode = __("Shell Zip", 'duplicator-pro'); break; } return $mode; } /** * Return archive extension type * * @return string */ public function getArchiveExtensionType(): string { $mode = 'zip'; if ($this->archive_build_mode == PackageArchive::BUILD_MODE_DUP_ARCHIVE) { $mode = 'daf'; } return $mode; } /** * Return Mysqldump options * * @return GroupOptions[] */ public function getMysqldumpOptions(): array { return $this->packageMysqldumpOptions; } /** * Get manual mode storage ids. * * If none of the stored storages is valid anymore, the default storage id * is added to the returned list so the UI can preselect it. * * @return int[] */ public function getManualModeStorageIds(): array { if (count($this->manual_mode_storage_ids) == 0) { $this->manual_mode_storage_ids = [StoragesUtil::getDefaultStorageId()]; } if (StoragesUtil::hasValidStorage($this->manual_mode_storage_ids)) { return $this->manual_mode_storage_ids; } return array_values(array_unique(array_merge($this->manual_mode_storage_ids, [StoragesUtil::getDefaultStorageId()]))); } /** * Set manual mode storage ids * * @param int[] $storageIds Storage ids * * @return void */ public function setManualModeStorageIds(array $storageIds): void { $this->manual_mode_storage_ids = []; foreach ($storageIds as $id) { $id = (int) $id; if ($id <= 0) { continue; } $this->manual_mode_storage_ids[] = $id; } if (count($this->manual_mode_storage_ids) == 0) { $this->manual_mode_storage_ids = [StoragesUtil::getDefaultStorageId()]; } } /** * Get Email Summary Recipients * * @return string[] */ public function getEmailSummaryRecipients(): array { return $this->email_summary_recipients; } /** * Set Email Summary Recipients * * @param string[] $recipients List of recipient email addreses * * @return void */ public function setEmailSummaryRecipients(array $recipients): void { $recipients = filter_var($recipients, FILTER_VALIDATE_EMAIL, FILTER_REQUIRE_ARRAY); if ($recipients === false) { $recipients = []; } foreach ($recipients as $key => $recipient) { if ($recipient === false) { continue; } $recipients[$key] = sanitize_email($recipient); } $this->email_summary_recipients = array_values(array_unique($recipients)); } /** * Get email summary frequency * * @return string */ public function getEmailSummaryFrequency(): string { return $this->email_summary_frequency; } /** * Set email summary frequency * * @param string $frequency The frequency * * @return void */ public function setEmailSummaryFrequency($frequency): void { if (EmailSummaryBootstrap::updateFrequency($this->email_summary_frequency, $frequency) === false) { DupLog::trace("Invalid email summary frequency: {$frequency}"); return; } $this->email_summary_frequency = $frequency; } /** * True if AM notifications are enabled * * @return bool */ public function isAmNoticesEnabled(): bool { return $this->amNotices; } /** * Set notifications enabled * * @param bool $enable true if enabled * * @return void */ public function setAmNotices(bool $enable): void { $this->amNotices = $enable; } /** * Set purge backup records * * @param int<0,2> $value ENUM AbstractStorageEntity::BACKUP_RECORDS_* * * @return void */ public function setPurgeBackupRecords(int $value): void { switch ($value) { case AbstractStorageEntity::BACKUP_RECORDS_REMOVE_ALL: case AbstractStorageEntity::BACKUP_RECORDS_REMOVE_NEVER: case AbstractStorageEntity::BACKUP_RECORDS_REMOVE_DEFAULT: $this->purgeBackupRecords = $value; break; default: throw new Exception('Invalid value'); } } /** * Get option on how to handle the old backup records * * @return int<0,2> ENUM AbstractStorageEntity::BACKUP_RECORDS_* */ public function getPurgeBackupRecords(): int { return $this->purgeBackupRecords; } }