#!/usr/local/bin/php -nc/usr/local/directadmin/plugins/borg-restore/php.ini null, 'REPO' => null, 'BORG_SSH_KEY' => null, ]; if (!is_readable($path)) { return $vars; } $lines = file($path, FILE_IGNORE_NEW_LINES); if ($lines === false) { return $vars; } foreach ($lines as $line) { $line = trim($line); if ($line === '' || $line[0] === '#') { continue; } if (preg_match('/^(?:export\s+)?(BORG_PASSPHRASE|REPO|BORG_SSH_KEY)=(.*)$/', $line, $m)) { $key = $m[1]; $vars[$key] = parse_sh_value($m[2]); } } return $vars; } function load_settings(string $path): array { $settings = [ 'BB_PATH' => '/opt/bb', 'BORG_PATH' => '/usr/bin/borg', 'BORG_VARIABLES_FILE' => '/opt/bb/bbvars.sh', 'ADMIN_MODE_ENABLE' => 'TRUE', 'RESULTS_PER_PAGE' => '10', 'WEB_RESTORE_LOCATION' => '/home/DA_USER/domains', 'MAIL_RESTORE_LOCATION' => '/home/DA_USER/imap', 'ENABLE_WEB_RESTORE' => 'TRUE', 'ENABLE_MAILBOX_RESTORE' => 'TRUE', 'DEFAULT_RESTORE_DESTINATION' => '/home/DA_USER/bb', 'BLOCK_RESTORE_OUTSIDE_LOCATION' => 'TRUE', 'PREVENT_RESTORE_MAIN_DOMAINS_DIR' => 'TRUE', 'PREVENT_RESTORE_MAIN_IMAP_DIR' => 'TRUE', 'PREVENT_CREATE_DIRS_IN_MAIN_DOMAIN' => 'TRUE', 'PREVENT_CREATE_DIRS_IN_MAIN_IMAP' => 'TRUE', 'HASH_VISIBILITY' => 'FALSE', 'ENABLE_LOGS_OVERLAY' => 'TRUE', 'SELECTABLE_DOMAIN_RESTORE_DESTINATION' => 'TRUE', 'SELECTABLE_MAIL_RESTORE_DESTINATION' => 'TRUE', 'CLEAR_DOVECOT_INDEXES_AFTER_MERGE' => 'TRUE', 'RESTORE_PATH_MODE' => 'dir', 'ADD_DATE_TO_RESTORED_DIR' => 'FALSE', 'DEBUG_MODE' => 'FALSE', ]; if (!is_readable($path)) { return $settings; } $lines = file($path, FILE_IGNORE_NEW_LINES); if ($lines === false) { return $settings; } foreach ($lines as $line) { $line = trim($line); if ($line === '' || $line[0] === '#') { continue; } if (preg_match('/^(BB_PATH|BORG_PATH|BORG_VARIABLES_FILE|ADMIN_MODE_ENABLE|RESULTS_PER_PAGE|WEB_RESTORE_LOCATION|MAIL_RESTORE_LOCATION|ENABLE_WEB_RESTORE|ENABLE_MAILBOX_RESTORE|DEFAULT_RESTORE_DESTINATION|BLOCK_RESTORE_OUTSIDE_LOCATION|PREVENT_RESTORE_MAIN_DOMAINS_DIR|PREVENT_RESTORE_MAIN_IMAP_DIR|PREVENT_CREATE_DIRS_IN_MAIN_DOMAIN|PREVENT_CREATE_DIRS_IN_MAIN_IMAP|HASH_VISIBILITY|ENABLE_LOGS_OVERLAY|SELECTABLE_DOMAIN_RESTORE_DESTINATION|SELECTABLE_MAIL_RESTORE_DESTINATION|CLEAR_DOVECOT_INDEXES_AFTER_MERGE|RESTORE_PATH_MODE|ADD_DATE_TO_RESTORED_DIR|DEBUG_MODE)=(.*)$/', $line, $m)) { $settings[$m[1]] = parse_sh_value($m[2]); } } return $settings; } function file_owner_name(int $uid): string { if (function_exists('posix_getpwuid')) { $info = posix_getpwuid($uid); if (is_array($info) && !empty($info['name'])) { return (string)$info['name']; } } return (string)$uid; } function validate_secure_file(string $path, string $label, bool $check_writable = true): string { if ($path === '') { return $label . ' ma pustą ścieżkę.'; } if (!file_exists($path)) { return $label . ' nie istnieje: ' . $path; } if (is_link($path) || !is_file($path)) { return $label . ' nie jest zwykłym plikiem: ' . $path; } $perms = fileperms($path); if ($perms === false) { return $label . ' ma nieprawidłowe uprawnienia: ' . $path; } if ($check_writable && (($perms & 0x0010) !== 0 || ($perms & 0x0002) !== 0)) { return $label . ' nie może być zapisywalny dla grupy/innych: ' . $path; } $uid = fileowner($path); if ($uid === false) { return $label . ' ma nieprawidłowego właściciela: ' . $path; } $owner = file_owner_name((int)$uid); if ($uid !== 0 && $uid !== 500 && $owner !== 'root' && $owner !== 'diradmin') { return $label . ' ma nieprawidłowego właściciela (' . $owner . '): ' . $path; } return ''; } function validate_job_files(string $job_base): array { $errors = []; foreach (['pending' => '*.env', 'processing' => '*.env', 'done' => '*.{ok,fail,cancel,env.ok,env.fail,env.cancel}'] as $dir => $pattern) { foreach (glob($job_base . '/' . $dir . '/' . $pattern, GLOB_BRACE) ?: [] as $path) { $err = validate_secure_file($path, 'Plik zadania', false); if ($err !== '') { $errors[] = $err; } } } return $errors; } function safe_user_key(string $value): string { $key = preg_replace('/[^A-Za-z0-9_.-]/', '_', $value); return $key === '' ? 'unknown' : $key; } function get_csrf_token(string $data_dir, string $da_user): string { $dir = rtrim($data_dir, '/') . '/csrf'; if (!is_dir($dir)) { @mkdir($dir, 0700, true); } $path = $dir . '/' . safe_user_key($da_user) . '.token'; if (is_readable($path)) { $token = trim((string)file_get_contents($path)); if ($token !== '') { return $token; } } $token = bin2hex(random_bytes(32)); @file_put_contents($path, $token, LOCK_EX); @chmod($path, 0600); return $token; } function csrf_is_valid(array $params, string $token): bool { $sent = $params['csrf_token'] ?? ''; if (!is_string($sent) || $sent === '' || $token === '') { return false; } return hash_equals($token, $sent); } function read_params(): array { $params = []; if (!empty($_GET)) { $params = array_merge($params, $_GET); } if (!empty($_POST)) { $params = array_merge($params, $_POST); } $get_raw = getenv('GET') ?: getenv('get') ?: ''; if ($get_raw !== '') { parse_str($get_raw, $parsed); $params = array_merge($parsed, $params); } $qs = $_SERVER['QUERY_STRING'] ?? ''; if ($qs !== '') { parse_str($qs, $parsed); $params = array_merge($parsed, $params); } $post_raw = getenv('POST') ?: getenv('post') ?: ''; if ($post_raw !== '') { parse_str($post_raw, $parsed); $params = array_merge($parsed, $params); } return $params; } function load_job_vars(string $path): array { $vars = [ 'DA_USER' => '', 'REPONAME' => '', 'USERRESTOREPATH' => '', 'TARGETPATH' => '', 'RESTOREMODE' => '', 'RESTORETYPE' => '', 'START_TS' => '', ]; if (!is_readable($path)) { return $vars; } $lines = file($path, FILE_IGNORE_NEW_LINES); if ($lines === false) { return $vars; } foreach ($lines as $line) { $line = trim($line); if ($line === '' || $line[0] === '#') { continue; } if (preg_match('/^(DA_USER|REPONAME|USERRESTOREPATH|TARGETPATH|RESTOREMODE|RESTORETYPE|START_TS|USERLANG)=(.*)$/', $line, $m)) { $vars[$m[1]] = parse_sh_value($m[2]); } } return $vars; } function job_id_from_file(string $file): string { $base = basename($file); if (substr($base, -3) === '.ok') { $base = substr($base, 0, -3); } elseif (substr($base, -5) === '.fail') { $base = substr($base, 0, -5); } if (substr($base, -4) === '.env') { $base = substr($base, 0, -4); } return $base; } function find_job_file(string $job_base, string $file, string $job_id): string { $candidates = [ $job_base . '/processing/' . $file, $job_base . '/pending/' . $file, $job_base . '/done/' . $file, ]; if ($job_id !== '') { $candidates[] = $job_base . '/processing/' . $job_id . '.env'; $candidates[] = $job_base . '/pending/' . $job_id . '.env'; $candidates[] = $job_base . '/done/' . $job_id . '.ok'; $candidates[] = $job_base . '/done/' . $job_id . '.fail'; $candidates[] = $job_base . '/done/' . $job_id . '.cancel'; } foreach ($candidates as $path) { if (is_file($path)) { return $path; } } return ''; } function job_belongs_to_user(string $job_file_path, string $da_user): bool { if ($job_file_path === '' || !is_readable($job_file_path)) { return false; } $vars = load_job_vars($job_file_path); $owner = (string)($vars['DA_USER'] ?? ''); return $owner !== '' && $owner === $da_user; } function find_job_file_for_user(string $job_base, string $file, string $job_id, string $da_user): string { $path = find_job_file($job_base, $file, $job_id); if ($path === '') { return ''; } return job_belongs_to_user($path, $da_user) ? $path : ''; } function format_log_body_for_download(string $text): string { $text = normalize_log($text); $text = preg_replace('/[ \t]+(?=\d{1,3}(?:\.\d+)?%\s+(?:Extracting|Deleting|Pruning|Compacting|Saving|Uploading|Downloading|Processing|Restoring|Creating)\b)/i', "\n", $text); $text = preg_replace('/\n{2,}(?=\d{1,3}(?:\.\d+)?%)/', "\n", $text); $text = preg_replace('/\n{3,}/', "\n\n", $text); return rtrim($text) . "\n"; } function log_missing_include_explanation(string $log_text, string $restore_path_label = ''): string { if (stripos($log_text, 'W przywracanej kopii zapasowej nie odnaleziono wskazanej ścieżki') !== false) { return ''; } if (stripos($log_text, 'The specified restore path was not found in the backup') !== false) { return ''; } if (preg_match("/Include pattern '.*' never matched\\./i", $log_text)) { $suffix = ''; if ($restore_path_label !== '' && $restore_path_label !== '-') { $suffix = ' (' . $restore_path_label . ')'; } return 'W przywracanej kopii zapasowej nie odnaleziono wskazanej ścieżki' . $suffix . '. Prosimy spróbować przywrócić dane z innego archiwum, w którym te pliki mogły się znajdować.'; } return ''; } function format_datetime(string $value, int $fallback = 0): string { $ts = is_numeric($value) ? (int)$value : 0; if ($ts <= 0) { $ts = $fallback > 0 ? $fallback : time(); } return date('d-m-Y-H-i-s', $ts); } function build_log_download_content(string $job_id, string $job_file_path, string $log_path, string $job_base): string { $vars = load_job_vars($job_file_path); $log_meta_start = format_datetime($vars['START_TS'] ?? '', time()); $log_meta_path = display_restore_path($vars['USERRESTOREPATH'] ?? ''); $log_meta_mode = restore_mode_label($vars['RESTOREMODE'] ?? ''); $log_meta_type = restore_type_label($vars['RESTORETYPE'] ?? ''); $log_meta_target = display_restore_path($vars['TARGETPATH'] ?? ''); if ($log_meta_path === '') { $log_meta_path = '-'; } if ($log_meta_mode === '') { $log_meta_mode = '-'; } if ($log_meta_type === '') { $log_meta_type = '-'; } if ($log_meta_target === '') { $log_meta_target = '-'; } $log_text = is_file($log_path) && is_readable($log_path) ? (string)file_get_contents($log_path) : ''; $log_text = normalize_log($log_text); $last_line = last_non_empty_line($log_text); $progress = extract_progress($last_line); $base_status = get_job_status($job_id, $job_base); $display = display_status($base_status, $last_line); $status_label = status_label($display); if (in_array($display, ['done', 'failed', 'canceled'], true)) { $progress_text = $display === 'done' ? '100%' : '0%'; } else { $progress_text = $progress !== null ? ($progress . '%') : ($last_line !== '' ? $last_line : '-'); } $header = "Data rozpoczęcia: {$log_meta_start}\n"; $header .= "Rodzaj przywracanych danych: {$log_meta_type}\n"; $header .= "Ścieżka do przywrócenia: {$log_meta_path}\n"; $header .= "Tryb przywracania: {$log_meta_mode}\n"; $header .= "Lokalizacja docelowa: {$log_meta_target}\n"; $header .= "Status: {$status_label}\n"; $header .= "Postęp: {$progress_text}\n"; $header .= "----- logi Borg -----\n"; $body = $log_text !== '' ? format_log_body_for_download($log_text) : "Log nie istnieje.\n"; $explanation = log_missing_include_explanation($log_text, $log_meta_path); if ($explanation !== '') { $body = rtrim($body) . "\n\n" . $explanation . "\n"; } return $header . $body; } function ajax_output(array $payload): void { global $lang_map; header('Content-Type: text/plain; charset=utf-8'); $json = json_encode($payload, JSON_UNESCAPED_UNICODE); echo '__BORG_AJAX_JSON__'; if ($json === false) { $json = '{}'; } echo translate_text($json, $lang_map ?? []); echo '__BORG_AJAX_JSON__'; exit; } function log_text_output(string $text): void { header('Content-Type: text/plain; charset=utf-8'); echo '__BORG_LOG_TEXT__'; echo $text; echo '__BORG_LOG_TEXT__'; exit; } function status_html_output(string $html): void { header('Content-Type: text/plain; charset=utf-8'); echo '__BORG_STATUS_HTML__'; echo $html; echo '__BORG_STATUS_HTML__'; exit; } function delete_job_assets(string $file, string $job_base, string $log_dir, string $pid_dir, string $cancel_dir): bool { $file = basename($file); if ($file === '' || !preg_match('/^[-A-Za-z0-9_.]+$/', $file)) { return false; } $job_id = job_id_from_file($file); if ($job_id === '') { return false; } $deleted = false; foreach (['pending', 'processing', 'done'] as $dir) { $dir_path = $job_base . '/' . $dir; foreach (glob($dir_path . '/' . $job_id . '*') ?: [] as $path) { if (is_file($path)) { @unlink($path); $deleted = true; } } $exact = $dir_path . '/' . $file; if (is_file($exact)) { @unlink($exact); $deleted = true; } } $log_path = $log_dir . '/' . $job_id . '.log'; if (is_file($log_path)) { @unlink($log_path); } $pid_path = $pid_dir . '/' . $job_id . '.pid'; if (is_file($pid_path)) { @unlink($pid_path); } $cancel_path = $cancel_dir . '/' . $job_id . '.flag'; if (is_file($cancel_path)) { @unlink($cancel_path); } return $deleted; } function list_jobs(string $dir, string $status, string $pattern, string $log_dir, string $pid_dir, string $cancel_dir, string $da_user): array { $items = []; foreach (glob($dir . '/' . $pattern) ?: [] as $path) { $vars = load_job_vars($path); $owner = (string)($vars['DA_USER'] ?? ''); if ($owner === '' || $owner !== $da_user) { continue; } $job_id = job_id_from_file($path); $log_path = $log_dir . '/' . $job_id . '.log'; $cancel_requested = is_file($cancel_dir . '/' . $job_id . '.flag'); $pid = ''; if ($status === 'processing') { $pid_path = $pid_dir . '/' . $job_id . '.pid'; if (is_readable($pid_path)) { $pid = trim((string)file_get_contents($pid_path)); } elseif (!empty($vars['PID'])) { $pid = (string)$vars['PID']; } if ($pid !== '' && !preg_match('/^[0-9]+$/', $pid)) { $pid = ''; } if ($pid !== '' && function_exists('posix_kill')) { if (!@posix_kill((int)$pid, 0)) { $pid = ''; } } } $progress_text = '-'; $display_status = $status; if ($status === 'processing' && is_readable($log_path)) { $info = get_progress_info($log_path); $display_status = display_status($status, $info['last']); if ($cancel_requested) { $display_status = 'canceled'; $progress_text = 'Anulowane'; } elseif ($display_status === 'calculating') { $progress_text = 'Przygotowanie'; } elseif ($info['progress'] !== null) { $progress_text = $info['progress'] . '%'; } elseif ($info['last'] !== '') { $progress_text = $info['last']; } } elseif ($status === 'done') { $progress_text = '100%'; } elseif ($status === 'failed') { $progress_text = 'Błąd'; } elseif ($status === 'canceled') { $progress_text = 'Anulowane'; } $items[] = [ 'status' => $status, 'display_status' => $display_status, 'file' => basename($path), 'time' => @filemtime($path) ?: 0, 'user' => $vars['DA_USER'] ?? '', 'repo' => $vars['REPONAME'] ?? '', 'path' => $vars['USERRESTOREPATH'] ?? '', 'target' => $vars['TARGETPATH'] ?? '', 'restore_mode' => $vars['RESTOREMODE'] ?? '', 'restore_mode_label' => restore_mode_label($vars['RESTOREMODE'] ?? ''), 'restore_type' => $vars['RESTORETYPE'] ?? '', 'restore_type_label' => restore_type_label($vars['RESTORETYPE'] ?? ''), 'job_id' => $job_id, 'log_exists' => is_readable($log_path), 'progress_text' => $progress_text, 'pid' => $pid, 'cancel_requested' => $cancel_requested, ]; } return $items; } function h(string $value): string { return htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); } function status_label(string $status): string { $map = [ 'pending' => 'Oczekuje', 'processing' => 'W trakcie', 'calculating' => 'Przygotowanie', 'done' => 'Zakończone', 'failed' => 'Błąd', 'canceled' => 'Anulowane', ]; $label = $map[$status] ?? 'Nieznany'; return t($label); } function read_log_tail(string $path, int $max_bytes = 200000): string { if (!is_readable($path)) { return ''; } $size = filesize($path); if ($size === false || $size <= $max_bytes) { return (string)file_get_contents($path); } $fp = fopen($path, 'rb'); if ($fp === false) { return ''; } fseek($fp, -$max_bytes, SEEK_END); $data = fread($fp, $max_bytes); fclose($fp); return (string)$data; } function normalize_log(string $text): string { $text = str_replace("\r", "\n", $text); $lines = preg_split('/\n/', $text); if (!is_array($lines)) { return $text; } $filtered = []; foreach ($lines as $line) { $trimmed = trim($line); if ($trimmed !== '' && stripos($trimmed, 'Permanently added') !== false && stripos($trimmed, 'known host') !== false) { continue; } $filtered[] = $line; } return implode("\n", $filtered); } function last_non_empty_line(string $text): string { $lines = preg_split('/\r\n|\n|\r/', $text); if (!is_array($lines)) { return ''; } for ($i = count($lines) - 1; $i >= 0; $i--) { $line = trim((string)$lines[$i]); if ($line !== '') { return $line; } } return ''; } function is_calculating_line(string $line): bool { return (bool)preg_match('/calculat/i', $line); } function extract_progress(string $line): ?int { if (preg_match('/\b(\d{1,3})%\b/', $line, $m)) { $p = (int)$m[1]; if ($p < 0) { $p = 0; } elseif ($p > 100) { $p = 100; } return $p; } return null; } function get_job_status(string $job_id, string $job_base): string { if ($job_id === '') { return 'unknown'; } if (is_file($job_base . '/processing/' . $job_id . '.env')) { return 'processing'; } if (is_file($job_base . '/pending/' . $job_id . '.env')) { return 'pending'; } if (is_file($job_base . '/done/' . $job_id . '.ok') || is_file($job_base . '/done/' . $job_id . '.env.ok')) { return 'done'; } if (is_file($job_base . '/done/' . $job_id . '.fail') || is_file($job_base . '/done/' . $job_id . '.env.fail')) { return 'failed'; } if (is_file($job_base . '/done/' . $job_id . '.cancel') || is_file($job_base . '/done/' . $job_id . '.env.cancel')) { return 'canceled'; } return 'unknown'; } function get_progress_info(string $log_path): array { $text = normalize_log(read_log_tail($log_path, 20000)); $last = last_non_empty_line($text); $progress = extract_progress($last); $calculating = $last !== '' && is_calculating_line($last); return [ 'last' => $last, 'progress' => $progress, 'calculating' => $calculating, ]; } function display_status(string $base_status, string $last_line): string { if ($base_status === 'processing' && $last_line !== '' && is_calculating_line($last_line)) { return 'calculating'; } return $base_status; } function apply_da_user(string $value, string $da_user): string { return str_replace('DA_USER', $da_user, $value); } function restore_mode_label(string $mode): string { if ($mode === 'overwrite') { return t('Nadpisz aktualne dane'); } if ($mode === 'update') { return t('Scalenie'); } if ($mode === 'location') { return t('Przywracanie do lokalizacji'); } return t('-'); } function restore_mode_label_form(string $mode): string { if ($mode === 'overwrite') { return t('Nadpisz aktualne dane'); } if ($mode === 'update') { return t('Połączenie danych kopii zapasowej z obecnymi danymi'); } if ($mode === 'location') { return t('Przywracanie do lokalizacji'); } return t('-'); } function restore_type_label(string $type): string { if ($type === 'mail') { return t('Zawartość skrzynki pocztowej'); } if ($type === 'web') { return t('Pliki www'); } return t('-'); } function format_start_time($value, int $fallback): string { $ts = is_numeric($value) ? (int)$value : 0; if ($ts <= 0) { $ts = $fallback > 0 ? $fallback : time(); } return date('d-m-Y-H-i-s', $ts); } function parse_bool_setting(?string $value, bool $default): bool { if ($value === null) { return $default; } $value = strtolower(trim($value)); if ($value === '') { return $default; } if (in_array($value, ['1', 'true', 'yes', 'on'], true)) { return true; } if (in_array($value, ['0', 'false', 'no', 'off'], true)) { return false; } return $default; } function display_restore_path(string $value): string { $trimmed = trim($value); if ($trimmed === '') { return ''; } if ($trimmed[0] !== '/') { $trimmed = '/' . $trimmed; } return $trimmed; } function append_date_to_last_dir(string $path, string $date): string { $path = rtrim($path, '/'); if ($path === '' || $path === '/') { return $path; } $parent = dirname($path); $base = basename($path); if ($base === '' || $base === '.' || $base === '..') { return $path; } if ($parent === '/' || $parent === '.') { return '/' . $base . '_' . $date; } return $parent . '/' . $base . '_' . $date; } function describe_overwrite_backup(string $restore_path_raw): string { $restore_path = trim($restore_path_raw, "/"); if ($restore_path === '') { return 'Backup zostanie utworzony jako *_przed_przywroceniem_' . date('d-m-Y_His') . ' w katalogu nadrzędnym ścieżki do przywrócenia.'; } $full = '/' . $restore_path; $base = basename($full); $parent = dirname($full); if ($base === '' || $parent === '' || $parent === '.') { return 'Backup zostanie utworzony jako *_przed_przywroceniem_' . date('d-m-Y_His') . ' w katalogu nadrzędnym ścieżki do przywrócenia.'; } $backup = $parent . '/' . $base . '_przed_przywroceniem_' . date('d-m-Y_His'); return 'Backup zostanie utworzony jako: ' . $backup . '.'; } function render_confirm_overwrite_html(string $restore_path_raw, string $selected_archive, string $target_path_raw, string $restore_mode, string $restore_type, bool $ajax, string $csrf_token): string { $mode_label = restore_mode_label_form($restore_mode); $title = $restore_mode === 'update' ? 'Potwierdź scalenie danych' : 'Potwierdź nadpisanie danych'; $warning = $restore_mode === 'update' ? 'Wybrano tryb scalenia danych. Istniejący katalog zostanie połączony z danymi z backupu.' : 'Wybrano tryb nadpisywania danych. Istniejący katalog zostanie zastąpiony.'; $loss_warning = ''; if ($restore_mode === 'overwrite' && $restore_type === 'mail') { $path_display = $restore_path_raw !== '' ? display_restore_path($restore_path_raw) : '-'; $loss_warning = 'DANE W KATALOGU ' . $path_display . ' ZOSTANĄ UTRACONE.'; } ob_start(); ?>

Uwaga:

Tryb przywracania:

Przywracana ścieżka:

Nie

Log zadania

Podgląd na żywo (odświeżanie co 3s)

Data rozpoczęcia:
Rodzaj przywracanych danych:
Ścieżka do przywrócenia:
Tryb przywracania:
Lokalizacja docelowa:
Status:
Postęp:
false, 'error' => 'json_encode_failed'], JSON_UNESCAPED_UNICODE); } $marker = '__BORG_PICKER_JSON__'; header('Content-Type: text/plain; charset=utf-8'); echo $marker . "\n" . $json . "\n" . $marker; } function picker_base_for_scope(array $params, string $web_location, string $mail_location, bool $block_restore_outside_location, string $da_user): string { $restore_type = strtolower((string)($params['restore_type'] ?? 'web')); if ($restore_type !== 'mail') { $restore_type = 'web'; } $scope = strtolower((string)($params['scope'] ?? 'restore')); $base = $restore_type === 'mail' ? $mail_location : $web_location; if ($scope === 'target') { $home_base = '/home'; if ($da_user !== '') { $home_base .= '/' . $da_user; } return $home_base; } if ($scope !== 'restore' || !$block_restore_outside_location) { return ''; } return $base; } function file_picker_handle(array $params, string $path_prefix): void { $base = $path_prefix !== '' ? $path_prefix : '/'; $mode = strtolower((string)($params['mode'] ?? 'dir')); $mode = ($mode === 'file') ? 'file' : 'dir'; $requested = trim((string)($params['path'] ?? '')); if ($requested !== '' && $requested[0] !== '/') { $requested = '/' . $requested; } $selected = ''; if ($mode === 'file' && $requested !== '') { $real_req = @realpath($requested); if ($real_req !== false && is_file($real_req)) { $selected = $real_req; $requested = dirname($real_req); } } [$resolved, $base, $ok] = resolve_picker_path($requested, $base); if ($base !== '/' && $selected !== '') { if (strpos($selected, $base . '/') !== 0 && $selected !== $base) { $selected = ''; } } $dir_items = []; $file_items = []; if ($ok && is_dir($resolved)) { $entries = @scandir($resolved); if (is_array($entries)) { foreach ($entries as $entry) { if ($entry === '.' || $entry === '..') { continue; } $full = $resolved . '/' . $entry; if (@is_dir($full)) { $dir_items[] = $entry; } elseif ($mode === 'file' && @is_file($full)) { $file_items[] = $entry; } } } } natcasesort($dir_items); natcasesort($file_items); $items = []; foreach ($dir_items as $name) { $items[] = ['name' => $name, 'type' => 'dir']; } foreach ($file_items as $name) { $items[] = ['name' => $name, 'type' => 'file']; } picker_output([ 'ok' => $ok, 'path' => $resolved, 'base' => $base, 'items' => $items, 'selected' => $selected, ]); } function file_picker_create(array $params, string $path_prefix, string $da_user, bool $prevent_main_domains, bool $prevent_main_imap): void { $base = $path_prefix !== '' ? $path_prefix : '/'; $parent_req = trim((string)($params['path'] ?? '')); if ($parent_req !== '' && $parent_req[0] !== '/') { $parent_req = '/' . $parent_req; } [$parent, $base, $ok] = resolve_picker_path($parent_req, $base); $name = trim((string)($params['name'] ?? '')); if ($name === '' || $name === '.' || $name === '..' || strpos($name, '/') !== false || strpos($name, '\\') !== false) { picker_output(['ok' => false, 'error' => 'invalid_name']); return; } if (!$ok || !is_dir($parent)) { picker_output(['ok' => false, 'error' => 'invalid_parent']); return; } if ($da_user !== '') { $parent_real = @realpath($parent); if ($parent_real !== false) { $domains_root = '/home/' . $da_user . '/domains'; $imap_root = '/home/' . $da_user . '/imap'; if ($prevent_main_domains && $parent_real === $domains_root) { picker_output(['ok' => false, 'error' => 'main_domain_blocked']); return; } if ($prevent_main_imap && $parent_real === $imap_root) { picker_output(['ok' => false, 'error' => 'main_imap_blocked']); return; } } } $new_path = rtrim($parent, '/') . '/' . $name; if ($base !== '/' && strpos($new_path, $base . '/') !== 0 && $new_path !== $base) { picker_output(['ok' => false, 'error' => 'outside_base']); return; } if (file_exists($new_path)) { picker_output(['ok' => false, 'error' => 'exists']); return; } if (!@mkdir($new_path, 0700, true)) { picker_output(['ok' => false, 'error' => 'mkdir_failed']); return; } @chown($new_path, $da_user); @chgrp($new_path, $da_user); picker_output(['ok' => true, 'path' => $parent, 'base' => $base, 'created' => $new_path]); } function render_jobs_section(array $jobs, string $csrf_token, bool $enable_logs_overlay): string { ob_start(); if (!empty($jobs)) { ?>
' . h(t('Logi')) . ''; } else { $actions[] = '' . h(t('Logi')) . ''; } } if (in_array($job['status'], ['done', 'failed', 'canceled'], true) && $job['log_exists']) { $actions[] = '' . h(t('Zapisz log')) . ''; } if (($job['status'] === 'processing' && empty($job['cancel_requested'])) || $job['status'] === 'pending' || $job['status'] === 'calculating') { $actions[] = '' . '' . '' . '' . '' . ''; } if ($job['log_exists'] || $job['status'] === 'processing') { $actions[] = '
' . '' . '' . '' . '' . '
'; } echo !empty($actions) ? implode(' | ', $actions) : '-'; ?>

strlen($a); }); return str_replace(array_keys($map), array_values($map), $text); } function translate_html_safe(string $html, array $map): string { if (empty($map)) { return $html; } $parts = preg_split('~(]*>.*?)~is', $html, -1, PREG_SPLIT_DELIM_CAPTURE); if ($parts === false) { return translate_text($html, $map); } $out = ''; foreach ($parts as $part) { if (preg_match('~^ 1; $default_restore_type = $enabled_restore_types[0] ?? 'web'; $restore_type = $params['restore_type'] ?? $default_restore_type; if ($restore_type !== 'web' && $restore_type !== 'mail') { $restore_type = $default_restore_type; } if (!in_array($restore_type, $enabled_restore_types, true)) { $restore_type = $default_restore_type; } $params['restore_type'] = $restore_type; if (!in_array($restore_mode, ['location', 'overwrite', 'update'], true)) { $restore_mode = 'location'; } if ($restore_type === 'mail' && !in_array($restore_mode, ['location', 'update', 'overwrite'], true)) { $restore_mode = 'update'; } if ($restore_type === 'web' && !in_array($restore_mode, ['location', 'overwrite'], true)) { $restore_mode = 'location'; } $selectable_target = $restore_type === 'mail' ? $selectable_mail_restore_destination : $selectable_domain_restore_destination; $confirm_overwrite = (($params['confirm_overwrite'] ?? '') === '1'); $ajax_requested = (($params['ajax'] ?? '') === '1'); $confirm_overwrite_view = false; $toast_job = ''; $restore_path_raw = $params['restore_path'] ?? ''; $target_path_raw = $params['target_path'] ?? ''; $jobs = []; $log_message = ''; $redirect_url = ''; $queued_job = ''; $queued_message = 'Zadanie przywracania danych dodane do kolejki, zostaniesz powiadomiony przez system wiadomości po zakończeniu tego procesu.'; $confirm_view = false; $floating_errors = []; $view_log_job = ''; $log_status_value = ''; $log_last_line = ''; $log_progress = null; $log_meta_start = ''; $log_meta_path = ''; $log_meta_mode = ''; $log_meta_type = ''; $log_meta_target = ''; $confirm_replace_url = ''; $toast_message = ''; $active_restore_location = $restore_type === 'mail' ? $mail_restore_location : $web_restore_location; $job_base = '/usr/local/directadmin/plugins/borg-restore/data/jobs'; $log_dir = '/usr/local/directadmin/plugins/borg-restore/data/logs'; $pid_dir = '/usr/local/directadmin/plugins/borg-restore/data/pids'; $cancel_dir = '/usr/local/directadmin/plugins/borg-restore/data/cancel'; $security_errors = []; $security_errors[] = validate_secure_file($settings_path, 'plugin-settings.conf'); $security_errors[] = validate_secure_file($vars_path, 'bbvars.sh', false); $security_errors = array_filter($security_errors, static fn($value) => $value !== ''); $security_errors = array_merge($security_errors, validate_job_files($job_base)); $security_ok = empty($security_errors); if (!$security_ok) { $system_errors = array_merge($system_errors, $security_errors); } foreach ($settings_errors as $err) { $system_errors[] = $err; } if ($vars_path === '' || !is_readable($vars_path)) { $system_errors[] = 'Brak pliku bbvars.sh: ' . ($vars_path !== '' ? $vars_path : 'nie ustawiono BB_PATH'); } if (empty($enabled_restore_types)) { $system_errors[] = 'ENABLE_WEB_RESTORE i ENABLE_MAILBOX_RESTORE są ustawione na FALSE.'; } if (empty($repo)) { $system_errors[] = 'Brak zmiennej REPO w ' . $vars_path; } if ($borg_bin === '') { $system_errors[] = 'BORG_PATH jest puste w plugin-settings.conf.'; } elseif (!is_executable($borg_bin)) { $system_errors[] = 'BORG_PATH nie jest plikiem wykonywalnym: ' . $borg_bin; } if ($borg_ssh_key !== '' && !is_readable($borg_ssh_key)) { $system_errors[] = 'BORG_SSH_KEY nie jest plikiem: ' . $borg_ssh_key; } if (!$block_restore_outside_location) { $warnings[] = 'BLOCK_RESTORE_OUTSIDE_LOCATION jest wyłączone - ścieżka do przywrócenia nie jest ograniczona.'; } $input_prefix = $active_restore_location !== '' ? $active_restore_location : '/home/' . $da_user; if ($restore_path_raw === '') { $restore_path_raw = $input_prefix . '/'; } if ($restore_mode === 'location' && (!$selectable_target || $target_path_raw === '')) { $target_path_raw = $default_restore_destination; } $ui_config_disabled_message = 'Błąd konfiguracji - skontaktuj się z supportem w celu zgłoszenia problemu'; $ui_system_error_message = 'Wystąpił problem z konfiguracją środowiska backupowego - skontaktuj się z administratorem w celu uzyskania pomocy'; $ui_locked_by_feature_flags = empty($enabled_restore_types); $ui_locked_message = $ui_locked_by_feature_flags ? $ui_config_disabled_message : $ui_system_error_message; $ui_locked = $ui_locked_by_feature_flags || !empty($system_errors); $system_error_details_for_ui = []; if ($debug_mode) { $system_error_details_for_ui = $system_errors; } if ($ui_locked && in_array($action, ['dir_list', 'dir_create', 'log_stream'], true)) { header('HTTP/1.1 403 Forbidden'); exit; } if ($action === 'status') { if ($ui_locked) { status_html_output(render_system_error_section($ui_locked_message, $system_error_details_for_ui, $debug_mode)); } $jobs = array_merge( list_jobs($job_base . '/pending', 'pending', '*.env', $log_dir, $pid_dir, $cancel_dir, $da_user), list_jobs($job_base . '/processing', 'processing', '*.env', $log_dir, $pid_dir, $cancel_dir, $da_user), list_jobs($job_base . '/done', 'done', '*.ok', $log_dir, $pid_dir, $cancel_dir, $da_user), list_jobs($job_base . '/done', 'failed', '*.fail', $log_dir, $pid_dir, $cancel_dir, $da_user), list_jobs($job_base . '/done', 'canceled', '*.cancel', $log_dir, $pid_dir, $cancel_dir, $da_user) ); usort($jobs, function ($a, $b) { return $b['time'] <=> $a['time']; }); if (count($jobs) > 50) { $jobs = array_slice($jobs, 0, 50); } status_html_output(render_jobs_section($jobs, $csrf_token, $enable_logs_overlay)); } if ($action === 'log_stream') { $file = basename((string)($params['job'] ?? '')); if (!preg_match('/^[-A-Za-z0-9_.]+$/', $file)) { header('HTTP/1.1 400 Bad Request'); exit; } $job_id = job_id_from_file($file); $job_file_path = find_job_file_for_user($job_base, $file, $job_id, $da_user); if ($job_file_path === '') { header('HTTP/1.1 403 Forbidden'); exit; } $log_path = $log_dir . '/' . $job_id . '.log'; $log_text = normalize_log(read_log_tail($log_path)); $explanation = log_missing_include_explanation($log_text); if ($explanation !== '') { $log_text = rtrim($log_text) . "\n\n" . $explanation; } $last_line = last_non_empty_line($log_text); $progress = extract_progress($last_line); $status = get_job_status($job_id, $job_base); $display = display_status($status, $last_line); if (in_array($display, ['done', 'failed', 'canceled'], true)) { $progress = ($display === 'done') ? 100 : 0; $progress_text = status_label($display); } else { $progress_text = $progress !== null ? ($progress . '%') : ($display === 'calculating' ? 'Przygotowanie' : $last_line); } header('Content-Type: application/json; charset=utf-8'); echo json_encode([ 'status' => $status, 'display_status' => $display, 'status_label' => status_label($status), 'display_label' => status_label($display), 'log' => $log_text, 'last_line' => $last_line, 'progress' => $progress, 'progress_text' => $progress_text, ], JSON_UNESCAPED_UNICODE); exit; } if ($action === 'dir_list') { if (!$security_ok) { header('HTTP/1.1 403 Forbidden'); exit; } $picker_base = picker_base_for_scope($params, $web_restore_location, $mail_restore_location, $block_restore_outside_location, $da_user); file_picker_handle($params, $picker_base); exit; } if ($action === 'dir_create') { if (!$security_ok) { header('HTTP/1.1 403 Forbidden'); exit; } $picker_base = picker_base_for_scope($params, $web_restore_location, $mail_restore_location, $block_restore_outside_location, $da_user); file_picker_create($params, $picker_base, $da_user, $prevent_create_dirs_in_main_domain, $prevent_create_dirs_in_main_imap); exit; } if ($action === 'restore') { if ($ui_locked) { $errors[] = $ui_locked_message; } if (!$ui_locked && !$security_ok) { $errors[] = 'Nieprawidłowe uprawnienia plików konfiguracyjnych lub zadań. Przywracanie zablokowane.'; } if (!$ui_locked && !$csrf_valid) { $errors[] = 'Nieprawidłowy token CSRF.'; } if (!$ui_locked) { $selected_archive = trim($selected_archive); if ($restore_mode === 'location' && !$selectable_target) { $target_path_raw = $default_restore_destination; } $restore_path_raw = trim($restore_path_raw); $target_path_raw = trim($target_path_raw); $restore_path = trim($restore_path_raw, "/"); $target_path = trim($target_path_raw); $restore_full_path = $restore_path !== '' ? '/' . $restore_path : ''; $target_full_path = $target_path !== '' && $target_path[0] !== '/' ? '/' . $target_path : $target_path; if ($restore_mode === 'overwrite' || $restore_mode === 'update') { $target_full_path = $restore_full_path; } if ($restore_mode === 'location' && $add_date_to_restored_dir && $target_full_path !== '') { $date_suffix = date('d-m-Y-His'); $target_full_path = append_date_to_last_dir($target_full_path, $date_suffix); $target_path_raw = $target_full_path; $target_path = $target_full_path; } if ($selected_archive === '') { $errors[] = 'Nie wybrano backupu.'; } if ($restore_path === '') { $errors[] = 'Nie podano ścieżki do przywrócenia.'; } if ($restore_mode === 'location') { if ($target_path === '') { $errors[] = 'Nie podano lokalizacji docelowej.'; } if ($target_path !== '' && $target_path[0] !== '/') { $errors[] = 'Lokalizacja docelowa musi zaczynać się od /.'; } } if ($restore_path !== '' && strpos($restore_path, '..') !== false) { $errors[] = 'Ścieżka nie może zawierać "..".'; } if ($restore_mode === 'location') { if ($target_path !== '' && strpos($target_path, '..') !== false) { $errors[] = 'Lokalizacja docelowa nie może zawierać "..".'; } } if ($restore_mode === 'location' && $target_full_path !== '') { $home_base = '/home/' . $da_user; if (strpos($target_full_path, $home_base . '/') !== 0 && $target_full_path !== $home_base) { $errors[] = 'Lokalizacja docelowa musi być w katalogu: ' . $home_base; } } if ($restore_mode === 'location' && $target_full_path !== '') { $domains_root = '/home/' . $da_user . '/domains'; $imap_root = '/home/' . $da_user . '/imap'; $parent_dir = rtrim(dirname($target_full_path), '/'); if ($prevent_create_dirs_in_main_domain && $parent_dir === $domains_root && !file_exists($target_full_path)) { $errors[] = 'Nie można utworzyć katalogu bezpośrednio w ' . $domains_root . '.'; } if ($prevent_create_dirs_in_main_imap && $parent_dir === $imap_root && !file_exists($target_full_path)) { $errors[] = 'Nie można utworzyć katalogu bezpośrednio w ' . $imap_root . '.'; } } if ($block_restore_outside_location && $active_restore_location !== '' && $restore_full_path !== '') { $base = rtrim($active_restore_location, '/'); if (strpos($restore_full_path, $base . '/') !== 0 && $restore_full_path !== $base) { $errors[] = 'Ścieżka musi być w katalogu: ' . $base; } } if ($restore_type === 'web' && $prevent_restore_main_domains_dir && $restore_mode === 'overwrite' && $active_restore_location !== '') { $base = rtrim($active_restore_location, '/'); if ($restore_full_path === $base) { $errors[] = 'Nie można przywrócić całego ' . $base . ' w trybie nadpisywania danych. Podaj podkatalog w ramach ' . $base . ' lub wybierz tryb przywracania do lokalizacji.'; } } if ($restore_type === 'mail' && $prevent_restore_main_imap_dir && ($restore_mode === 'overwrite' || $restore_mode === 'update') && $active_restore_location !== '') { $base = rtrim($active_restore_location, '/'); if ($restore_full_path === $base) { $errors[] = 'Nie można przywrócić całego ' . $base . ' w trybie nadpisywania lub scalania danych. Podaj podkatalog w ramach ' . $base . ' lub wybierz tryb przywracania do lokalizacji.'; } } if ($restore_mode === 'location' && $target_full_path !== '') { if (@file_exists($target_full_path) && !@is_dir($target_full_path)) { $errors[] = 'Lokalizacja docelowa istnieje, ale nie jest katalogiem.'; } elseif (@is_dir($target_full_path)) { $entries = @scandir($target_full_path); if ($entries === false) { $errors[] = 'Nie można odczytać katalogu docelowego.'; } elseif (count($entries) > 2) { $errors[] = 'Lokalizacja docelowa nie jest pusta.'; } } } if (empty($errors)) { if (($restore_mode === 'overwrite' || $restore_mode === 'update') && !$confirm_overwrite) { $confirm_overwrite_view = true; } else { $job_dir = '/usr/local/directadmin/plugins/borg-restore/data/jobs/pending'; if (!is_dir($job_dir) && !@mkdir($job_dir, 0700, true) && !is_dir($job_dir)) { $errors[] = 'Nie udało się utworzyć katalogu zadań.'; } else { $job_id = date('YmdHis') . '-' . bin2hex(random_bytes(4)); $job_file = $job_dir . '/restore-' . $job_id . '.env'; $job_content = "DA_USER=" . escapeshellarg($da_user) . "\n"; $job_content .= "START_TS=" . escapeshellarg((string)time()) . "\n"; $job_content .= "REPONAME=" . escapeshellarg($selected_archive) . "\n"; $job_content .= "USERRESTOREPATH=" . escapeshellarg($restore_path) . "\n"; $job_content .= "TARGETPATH=" . escapeshellarg($target_full_path) . "\n"; $job_content .= "RESTOREMODE=" . escapeshellarg($restore_mode) . "\n"; $job_content .= "RESTORETYPE=" . escapeshellarg($restore_type) . "\n"; $job_content .= "RESTOREPATHMODE=" . escapeshellarg($restore_path_mode) . "\n"; $job_content .= "USERLANG=" . escapeshellarg($lang_code) . "\n"; $old_umask = umask(0077); $write_ok = @file_put_contents($job_file, $job_content, LOCK_EX); if ($old_umask !== false) { umask($old_umask); } if ($write_ok === false) { $errors[] = 'Nie udało się zapisać pliku zadania.'; } else { @chmod($job_file, 0600); $queued_job = 'restore-' . $job_id; $confirm_replace_url = '/CMD_PLUGINS/borg-restore?queued=1&view=queued&job=' . rawurlencode($queued_job); if ($ajax_requested) { $toast_message = $queued_message; $toast_job = $queued_job; } elseif ($skin === 'evolution') { $toast_message = $queued_message; $toast_job = $queued_job; } else { $confirm_view = true; } } } } } } } if (!empty($errors)) { $remaining = []; foreach ($errors as $err) { if ($err === 'Nie wybrano backupu.' || strpos($err, 'Nie można przywrócić całego') === 0) { $floating_errors[] = $err; } else { $remaining[] = $err; } } $errors = $remaining; } if ($action === 'restore' && $ajax_requested) { $payload = [ 'ok' => empty($errors) && !$confirm_overwrite_view, 'errors' => $errors, 'floating_errors' => $floating_errors, ]; if ($confirm_overwrite_view) { $payload['confirm_html'] = render_confirm_overwrite_html($restore_path_raw, $selected_archive, $target_path_raw, $restore_mode, $restore_type, true, $csrf_token); } elseif (empty($errors)) { $payload['toast_message'] = $toast_message; $payload['toast_job'] = $toast_job; } ajax_output($payload); } if (!$ui_locked && empty($errors) && $security_ok) { $env = $_ENV; if (!empty($passphrase)) { $env['BORG_PASSPHRASE'] = $passphrase; } if ($borg_ssh_key !== '' && is_readable($borg_ssh_key)) { $env['BORG_RSH'] = 'ssh -i ' . escapeshellarg($borg_ssh_key); } $command = $borg_bin . ' list ' . escapeshellarg((string)$repo); $descriptors = [ 1 => ['pipe', 'w'], 2 => ['pipe', 'w'], ]; $process = @proc_open($command, $descriptors, $pipes, null, $env); if (!is_resource($process)) { $system_errors[] = 'Nie udało się uruchomić borg.'; } else { $stdout = stream_get_contents($pipes[1]); $stderr = stream_get_contents($pipes[2]); fclose($pipes[1]); fclose($pipes[2]); $exit_code = proc_close($process); if ($debug_mode) { $system_debug_lines[] = '[borg list command] ' . $command; $system_debug_lines[] = '[exit_code] ' . $exit_code; $system_debug_lines[] = '[stdout]'; $system_debug_lines[] = trim((string)$stdout) !== '' ? trim((string)$stdout) : '(pusty)'; $system_debug_lines[] = '[stderr]'; $system_debug_lines[] = trim((string)$stderr) !== '' ? trim((string)$stderr) : '(pusty)'; } if ($exit_code !== 0) { $msg = trim((string)$stderr); if ($msg === '') { $msg = 'Kod bledu: ' . $exit_code; } $system_errors[] = 'Błąd borg list: ' . $msg; } else { $lines = preg_split('/\r?\n/', trim((string)$stdout)); foreach ($lines as $line) { $line = trim($line); if ($line === '') { continue; } if (preg_match('/^(\\S+)\\s+(.+?)\\s+\\[([0-9a-fA-F]+)\\]\\s*$/', $line, $m)) { $entries[] = [ 'name' => $m[1], 'date' => $m[2], 'hash' => $m[3], ]; } else { $entries[] = [ 'name' => $line, 'date' => '', 'hash' => '', ]; } } } } } if ($debug_mode) { $system_error_details_for_ui = array_values(array_unique(array_merge($system_errors, $system_debug_lines))); } if (!empty($system_errors)) { $ui_locked = true; if (!$ui_locked_by_feature_flags) { $ui_locked_message = $ui_system_error_message; } } if ($action === 'clear_jobs' && $method === 'POST') { $deleted = 0; $owned_jobs = array_merge( list_jobs($job_base . '/pending', 'pending', '*.env', $log_dir, $pid_dir, $cancel_dir, $da_user), list_jobs($job_base . '/processing', 'processing', '*.env', $log_dir, $pid_dir, $cancel_dir, $da_user), list_jobs($job_base . '/done', 'done', '*.ok', $log_dir, $pid_dir, $cancel_dir, $da_user), list_jobs($job_base . '/done', 'failed', '*.fail', $log_dir, $pid_dir, $cancel_dir, $da_user), list_jobs($job_base . '/done', 'canceled', '*.cancel', $log_dir, $pid_dir, $cancel_dir, $da_user) ); foreach ($owned_jobs as $job) { if (delete_job_assets($job['file'], $job_base, $log_dir, $pid_dir, $cancel_dir)) { $deleted++; } } $message_status = $deleted > 0 ? 'Zadania zostały wyczyszczone.' : 'Brak zadań do wyczyszczenia.'; } if ($action === 'delete_selected' && $method === 'POST') { $to_delete = $params['jobs'] ?? []; if (!is_array($to_delete)) { $to_delete = [$to_delete]; } $deleted = 0; foreach ($to_delete as $file) { $file = basename((string)$file); $job_id = job_id_from_file($file); $job_file_path = find_job_file_for_user($job_base, $file, $job_id, $da_user); if ($job_file_path === '') { continue; } if (delete_job_assets($file, $job_base, $log_dir, $pid_dir, $cancel_dir)) { $deleted++; } } $log_message = $deleted > 0 ? 'Wybrane zadania zostały usunięte.' : 'Nie wybrano żadnych zadań.'; } if ($action === 'delete_job') { $file = basename((string)($params['job'] ?? '')); $job_id = job_id_from_file($file); $job_file_path = find_job_file_for_user($job_base, $file, $job_id, $da_user); if ($job_file_path === '') { $log_message = 'Brak dostępu do zadania.'; } elseif (delete_job_assets($file, $job_base, $log_dir, $pid_dir, $cancel_dir)) { $log_message = 'Zadanie zostało usunięte.'; } else { $log_message = 'Nie znaleziono zadania.'; } } if ($action === 'cancel_job') { $file = basename((string)($params['job'] ?? '')); $job_id = job_id_from_file($file); $job_file_path = find_job_file_for_user($job_base, $file, $job_id, $da_user); $pending_file = $job_base . '/pending/' . $file; $processing_file = $job_base . '/processing/' . $file; $cancel_file = $cancel_dir . '/' . $job_id . '.flag'; if ($job_id === '' || !preg_match('/^[-A-Za-z0-9_.]+$/', $file)) { $log_message = 'Nieprawidłowe zadanie.'; } elseif ($job_file_path === '') { $log_message = 'Brak dostępu do zadania.'; } elseif (is_file($pending_file)) { $target = $job_base . '/done/' . $job_id . '.cancel'; if (@rename($pending_file, $target)) { $log_message = 'Zadanie zostało anulowane.'; } else { if (delete_job_assets($file, $job_base, $log_dir, $pid_dir, $cancel_dir)) { $log_message = 'Zadanie zostało anulowane.'; } else { $log_message = 'Nie udało się anulować zadania.'; } } } elseif (!is_file($processing_file)) { $log_message = 'Zadanie nie jest w trakcie.'; } else { $pid = ''; $pid_path = $pid_dir . '/' . $job_id . '.pid'; if (is_readable($pid_path)) { $pid = trim((string)file_get_contents($pid_path)); } else { $vars = load_job_vars($processing_file); if (!empty($vars['PID'])) { $pid = (string)$vars['PID']; } } if ($pid === '' || !preg_match('/^[0-9]+$/', $pid)) { $log_message = 'Nie znaleziono procesu do anulowania.'; } elseif (!function_exists('posix_kill')) { $log_message = 'Brak obsługi posix_kill na serwerze.'; } else { $ok = @posix_kill((int)$pid, SIGTERM); usleep(300000); if (@posix_kill((int)$pid, 0)) { @posix_kill((int)$pid, SIGKILL); usleep(300000); } if ($ok && !@posix_kill((int)$pid, 0)) { @file_put_contents($cancel_file, "1"); $log_message = 'Zadanie zostało anulowane.'; } else { $log_message = 'Nie udało się anulować zadania.'; } } } } if ($action === 'download_log') { $file = basename((string)($params['job'] ?? '')); $raw_download = (($params['raw'] ?? '') === '1'); if (preg_match('/^[-A-Za-z0-9_.]+$/', $file)) { $job_id = job_id_from_file($file); $log_path = $log_dir . '/' . $job_id . '.log'; $job_file_path = find_job_file_for_user($job_base, $file, $job_id, $da_user); $filename = $job_id . '.log'; if ($job_file_path === '') { header('HTTP/1.1 403 Forbidden'); echo t("Brak dostępu do logu.\n"); exit; } $content = build_log_download_content($job_id, $job_file_path, $log_path, $job_base); if (!empty($lang_map)) { $content = translate_text($content, $lang_map); } if ($raw_download) { log_text_output($content); } header('Content-Type: text/plain; charset=utf-8'); header('Content-Disposition: attachment; filename="' . $filename . '"'); echo $content; } else { header('Content-Type: text/plain; charset=utf-8'); echo t("Nieprawidłowy identyfikator logu.\n"); } exit; } if ($action === 'view_log') { $file = basename((string)($params['job'] ?? '')); if (preg_match('/^[-A-Za-z0-9_.]+$/', $file)) { $job_id = job_id_from_file($file); $job_file_path = find_job_file_for_user($job_base, $file, $job_id, $da_user); $log_path = $log_dir . '/' . $job_id . '.log'; if ($job_file_path === '') { $log_message = 'Brak dostępu do zadania.'; $log_status_value = 'Brak dostępu'; $log_meta_start = '-'; $log_meta_path = '-'; $log_meta_mode = '-'; $log_meta_type = '-'; $log_meta_target = '-'; $view_log_job = ''; } else { $view_log_job = $file; $status = get_job_status($job_id, $job_base); $log_status_value = status_label($status); $vars = load_job_vars($job_file_path); $start_ts = $vars['START_TS'] ?? ''; $log_meta_start = format_start_time($start_ts, @filemtime($job_file_path) ?: 0); $log_meta_path = display_restore_path($vars['USERRESTOREPATH'] ?? ''); $log_meta_mode = restore_mode_label($vars['RESTOREMODE'] ?? ''); $log_meta_type = restore_type_label($vars['RESTORETYPE'] ?? ''); $log_meta_target = display_restore_path($vars['TARGETPATH'] ?? ''); if ($log_meta_path === '') { $log_meta_path = '-'; } if ($log_meta_type === '') { $log_meta_type = '-'; } if ($log_meta_target === '') { $log_meta_target = '-'; } if (is_file($log_path) && is_readable($log_path)) { $log_message = normalize_log((string)file_get_contents($log_path)); } else { $log_message = 'Log nie istnieje.'; } $explanation = log_missing_include_explanation($log_message, $log_meta_path); if ($explanation !== '') { $log_message = rtrim($log_message) . "\n\n" . $explanation; } $log_last_line = last_non_empty_line($log_message); $log_progress = extract_progress($log_last_line); $display = display_status($status, $log_last_line); $log_status_value = status_label($display); if (in_array($display, ['done', 'failed', 'canceled'], true)) { $log_progress = $display === 'done' ? 100 : null; $log_last_line = status_label($display); } } } else { $log_message = 'Nieprawidłowy identyfikator logu.'; } $view_log_overlay = $enable_logs_overlay && (($params['overlay'] ?? '') === '1'); if ($view_log_overlay) { $overlay_html = render_log_view_html($view_log_job, $log_meta_start ?? '-', $log_meta_type ?? '-', $log_meta_path ?? '-', $log_meta_mode ?? '-', $log_meta_target ?? '-', $log_status_value ?? '-', $log_progress ?? null, $log_last_line ?? '', $log_message ?? '', $status ?? '', true); echo translate_html_safe($overlay_html, $lang_map ?? []); exit; } } if (($params['queued'] ?? '') === '1') { $queued_job = isset($params['job']) ? trim((string)$params['job']) : ''; $queued_label = $queued_message; if ($queued_job !== '' && preg_match('/^restore-[A-Za-z0-9-]+$/', $queued_job)) { $queued_label = $queued_message . ' ID: ' . $queued_job . '.'; } if ($skin === 'evolution') { $toast_message = $queued_label; $toast_job = $queued_job; $confirm_view = false; } elseif (($params['view'] ?? '') === 'queued') { $confirm_view = true; } else { $message_status = $queued_label; } } $confirm_view = false; $jobs = array_merge( list_jobs($job_base . '/pending', 'pending', '*.env', $log_dir, $pid_dir, $cancel_dir, $da_user), list_jobs($job_base . '/processing', 'processing', '*.env', $log_dir, $pid_dir, $cancel_dir, $da_user), list_jobs($job_base . '/done', 'done', '*.ok', $log_dir, $pid_dir, $cancel_dir, $da_user), list_jobs($job_base . '/done', 'failed', '*.fail', $log_dir, $pid_dir, $cancel_dir, $da_user), list_jobs($job_base . '/done', 'canceled', '*.cancel', $log_dir, $pid_dir, $cancel_dir, $da_user) ); usort($jobs, function ($a, $b) { return $b['time'] <=> $a['time']; }); if (count($jobs) > 50) { $jobs = array_slice($jobs, 0, 50); } ?> borg-restore
BorgBackup - Przywracanie Plików

Lista backupow

Problem z konfiguracją środowiska backupowego - skontaktuj się z administratorem w celu uzyskania pomocy

Nazwa Data Hash

Rodzaj przywracanych danych

Tryb przywracanych danych

Rodzaj przywracanych danych:

Domyślna lokalizacja docelowa:

Przykłady użycia

/home/uzytkownik/domains/uzytkownik.pl/public_html/

home/uzytkownik/domains/uzytkownik.pl/public_html

home/uzytkownik/domains/uzytkownik.pl/public_html/

Uwaga! Znaki / z początku i końca linii zostaną usunięte.

Brak wpisów do wyświetlenia.

Status zadań