#!/usr/local/bin/php -nc/usr/local/directadmin/plugins/db-manager/php.ini [], 'present' => [], ]; if (!is_readable($path)) { return $result; } $lines = file($path, FILE_IGNORE_NEW_LINES); if ($lines === false) { return $result; } foreach ($lines as $line) { $line = trim($line); if ($line === '' || $line[0] === '#') { continue; } if (!preg_match('/^([A-Za-z0-9_]+)=(.*)$/', $line, $m)) { continue; } $key = trim((string)$m[1]); if ($key === '') { continue; } $result['values'][$key] = parse_sh_value((string)$m[2]); $result['present'][$key] = true; } return $result; } function parse_plugins_list(string $value): array { $value = trim($value); if ($value === '') { return []; } $out = []; foreach (explode(':', $value) as $part) { $part = strtolower(trim($part)); if ($part === '') { continue; } $out[] = $part; } return array_values(array_unique($out)); } function conf_explicit_bool(array $conf, array $keys, ?bool &$out): bool { $values = $conf['values'] ?? []; $present = $conf['present'] ?? []; $keys_lc = array_map('strtolower', $keys); foreach ($present as $conf_key => $is_present) { if (!$is_present) { continue; } $conf_key_lc = strtolower((string)$conf_key); if (!in_array($conf_key_lc, $keys_lc, true)) { continue; } $out = parse_bool((string)($values[$conf_key] ?? ''), false); return true; } return false; } function is_custom_package_item_enabled(array $conf): bool { $enabled = null; if (conf_explicit_bool($conf, ['db_manager'], $enabled)) { return (bool)$enabled; } return false; } function is_plugin_allowed_by_conf(array $conf, string $plugin_id): bool { $values = $conf['values'] ?? []; $present = $conf['present'] ?? []; $plugin_id = strtolower(trim($plugin_id)); if ($plugin_id === '') { return false; } if (!empty($present['plugins_allow'])) { $allow = parse_plugins_list((string)($values['plugins_allow'] ?? '')); return in_array($plugin_id, $allow, true); } if (!empty($present['plugins_deny'])) { $deny = parse_plugins_list((string)($values['plugins_deny'] ?? '')); return !in_array($plugin_id, $deny, true); } return true; } function resolve_package_conf_path(array $user_conf, string $da_user): string { $values = $user_conf['values'] ?? []; $package_name = trim((string)($values['package'] ?? $values['user_package'] ?? '')); if ($package_name === '' || !preg_match('/^[A-Za-z0-9._-]+$/', $package_name)) { return ''; } $owners = []; foreach (['creator', 'owner', 'reseller', 'username'] as $key) { $owner = trim((string)($values[$key] ?? '')); if ($owner !== '' && preg_match('/^[A-Za-z0-9._-]+$/', $owner)) { $owners[] = $owner; } } if (preg_match('/^[A-Za-z0-9._-]+$/', $da_user)) { $owners[] = $da_user; } $owners[] = 'admin'; $owners = array_values(array_unique($owners)); foreach ($owners as $owner) { foreach (['', '.conf'] as $ext) { $candidate = '/usr/local/directadmin/data/users/' . $owner . '/packages/' . $package_name . $ext; if (is_readable($candidate)) { return $candidate; } } } return ''; } function is_plugin_enabled_for_user(string $da_user, string $plugin_id, array $settings = []): bool { $base = '/usr/local/directadmin/data/users/' . $da_user; if (parse_bool((string)($settings['Always_enable'] ?? '0'), false)) { return true; } $user_conf_path = $base . '/user.conf'; $user_conf = load_conf_with_presence($user_conf_path); if (!is_custom_package_item_enabled($user_conf)) { return false; } if (!is_plugin_allowed_by_conf($user_conf, $plugin_id)) { return false; } $package_conf_path = resolve_package_conf_path($user_conf, $da_user); if ($package_conf_path === '') { return true; } $package_conf = load_conf_with_presence($package_conf_path); if (!is_custom_package_item_enabled($package_conf)) { return false; } return is_plugin_allowed_by_conf($package_conf, $plugin_id); } function load_lang_map(string $lang, string $plugin_dir): array { $lang = normalize_lang_code($lang); $lang_dir = $plugin_dir . '/lang'; $fallback_path = $lang_dir . '/en.php'; $lang_path = $lang_dir . '/' . $lang . '.php'; $fallback = []; if (is_readable($fallback_path)) { $fallback_map = include $fallback_path; if (is_array($fallback_map)) { $fallback = $fallback_map; } } if ($lang === 'en') { return $fallback; } if (!is_readable($lang_path)) { return $fallback; } $selected = include $lang_path; if (!is_array($selected)) { return $fallback; } return array_merge($fallback, $selected); } function translate_text(string $text, array $map): string { if (empty($map)) { return $text; } uksort($map, function ($a, $b) { return strlen((string)$b) <=> strlen((string)$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('~^ '/home/admin/mysql_backups', 'USER_SQL_BACKUP_DIR' => '/home/da_user/mysql_backups/user_backups', 'ALLOW_DOWNLOAD_HITME_SQL_BACKUP' => 'true', 'ENABLE_USER_BACKUPS' => 'true', 'PRE_RESTORE_BACKUP_DIR' => '/home/da_user/mysql_backups/pre_restore_backups', 'PRE_RESTORE_USER_BACKUP_DIR' => '/home/da_user/mysql_backups/pre_restore_user_backups', 'ENABLE_PRE_RESTORE_BACKUP' => 'true', 'ENABLE_USER_PRE_RESTORE_BACKUP' => 'true', 'SECURE_BACKUP' => 'true', 'SECURE_RESTORE' => 'true', 'PREVENT_LOG_DELETION' => 'true', 'OWN_BACKUP_USER_RESTORE' => 'true', 'CHECK_DATABASE_COLLISIONS' => 'true', 'ENABLE_OPERATION_LIMITS' => 'true', 'RESTORE_LIMIT_5MIN' => '10', 'RESTORE_LIMIT_HOUR' => '30', 'RESTORE_LIMIT_DAY' => '100', 'BACKUP_LIMIT_5MIN' => '10', 'BACKUP_LIMIT_HOUR' => '30', 'BACKUP_LIMIT_DAY' => '100', 'ENABLE_LOGS_OVERLAY' => 'true', 'Always_enable' => '0', ]; 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('/^(HITME_SQL_BACKUP_DIR|USER_SQL_BACKUP_DIR|ALLOW_DOWNLOAD_HITME_SQL_BACKUP|ENABLE_USER_BACKUPS|PRE_RESTORE_BACKUP_DIR|PRE_RESTORE_USER_BACKUP_DIR|ENABLE_PRE_RESTORE_BACKUP|ENABLE_USER_PRE_RESTORE_BACKUP|SECURE_BACKUP|SECURE_RESTORE|PREVENT_LOG_DELETION|OWN_BACKUP_USER_RESTORE|CHECK_DATABASE_COLLISIONS|ENABLE_OPERATION_LIMITS|RESTORE_LIMIT_5MIN|RESTORE_LIMIT_HOUR|RESTORE_LIMIT_DAY|BACKUP_LIMIT_5MIN|BACKUP_LIMIT_HOUR|BACKUP_LIMIT_DAY|ENABLE_LOGS_OVERLAY|Always_enable)=(.*)$/', $line, $m)) { $key = (string)$m[1]; $value = parse_sh_value($m[2]); $settings[$key] = $value; } } return $settings; } function apply_da_user(string $value, string $da_user): string { $value = str_replace('DA_USER', $da_user, $value); $value = str_replace('da_user', $da_user, $value); return $value; } 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' => '', 'DB_NAME' => '', 'SOURCE_DB_NAME' => '', 'JOB_TYPE' => '', 'BACKUP_SOURCE' => '', 'RESTORE_MODE' => '', 'SANITIZATION_REQUIRED' => '', 'DATE_DIR' => '', 'DUMP_FILE' => '', 'PRE_BACKUP_PATH' => '', 'START_TS' => '', 'PID' => '', ]; 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|DB_NAME|SOURCE_DB_NAME|JOB_TYPE|BACKUP_SOURCE|RESTORE_MODE|SANITIZATION_REQUIRED|DATE_DIR|DUMP_FILE|PRE_BACKUP_PATH|START_TS|PID)=(.*)$/', $line, $m)) { $vars[$m[1]] = parse_sh_value($m[2]); } } return $vars; } function normalize_backup_source(array $vars): string { $source = strtolower(trim((string)($vars['BACKUP_SOURCE'] ?? ''))); return $source === 'user' ? 'user' : 'hosting'; } function normalize_job_type(array $vars): string { $job_type = strtolower(trim((string)($vars['JOB_TYPE'] ?? ''))); return $job_type === 'backup' ? 'backup' : 'restore'; } function normalize_restore_mode(array $vars): string { $mode = strtolower(trim((string)($vars['RESTORE_MODE'] ?? ''))); if ($mode === 'new_db' || $mode === 'overwrite') { return $mode; } $db = trim((string)($vars['DB_NAME'] ?? '')); $source_db = trim((string)($vars['SOURCE_DB_NAME'] ?? '')); if ($db !== '' && $source_db !== '' && $db !== $source_db) { return 'new_db'; } return 'overwrite'; } function sanitize_required_label(array $vars): string { $raw = strtolower(trim((string)($vars['SANITIZATION_REQUIRED'] ?? ''))); if (in_array($raw, ['tak', 'true', '1', 'yes', 'y', 'on'], true)) { return 'Tak'; } if (in_array($raw, ['nie', 'false', '0', 'no', 'n', 'off'], true)) { return 'Nie'; } $source = trim((string)($vars['SOURCE_DB_NAME'] ?? '')); $target = trim((string)($vars['DB_NAME'] ?? '')); if ($source !== '' && $target !== '' && $source !== $target) { return 'Tak'; } return 'Nie'; } function backup_source_label(string $source): string { if ($source === 'user') { return t('Kopia bazy uzytkownika'); } return t('Kopia bazy udostepnianej przez HITME.PL'); } function restore_mode_label(string $mode, string $job_type): string { if ($job_type === 'backup') { return t('Tworzenie Kopii bazy danych'); } if ($mode === 'new_db') { return t('Przywracanie bazy danych - Do nowej bazy danych'); } return t('Przywracanie bazy danych - Nadpisanie oryginalnej bazy danych'); } 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); } elseif (substr($base, -7) === '.cancel') { $base = substr($base, 0, -7); } 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_id, string $job_base, string $da_user): bool { if ($job_id === '') { return false; } $file = find_job_file($job_base, $job_id . '.env', $job_id); if ($file === '') { return false; } $vars = load_job_vars($file); return ($vars['DA_USER'] ?? '') === $da_user; } function h(string $value): string { return htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); } 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 normalize_log(string $text): string { $text = str_replace("\r", "", $text); return rtrim($text); } function log_text_output(string $text): void { header('Content-Type: text/plain; charset=utf-8'); echo '__DB_RESTORE_LOG_TEXT__'; echo $text; echo '__DB_RESTORE_LOG_TEXT__'; exit; } function read_log_tail(string $path, int $max_lines = 200): string { if (!is_readable($path)) { return ''; } $lines = file($path, FILE_IGNORE_NEW_LINES); if ($lines === false) { return ''; } if (count($lines) > $max_lines) { $lines = array_slice($lines, -$max_lines); } return implode("\n", $lines); } function last_non_empty_line(string $text): string { $lines = preg_split('/\r?\n/', $text); if ($lines === false) { return ''; } for ($i = count($lines) - 1; $i >= 0; $i--) { $line = trim((string)$lines[$i]); if ($line !== '') { return $line; } } return ''; } function extract_progress(string $line): ?int { if (preg_match('/\b(\d{1,3})%\b/', $line, $m)) { $progress = (int)$m[1]; if ($progress < 0) { $progress = 0; } if ($progress > 100) { $progress = 100; } return $progress; } return null; } function display_status(string $base_status, string $last_line): string { if ($base_status !== 'processing') { return $base_status; } $line = strtolower(trim($last_line)); if ($line === '') { return $base_status; } if (strpos($line, 'preparing') !== false || strpos($line, 'przygotow') !== false) { return 'processing'; } return $base_status; } function status_label(string $status): string { $map = [ 'pending' => 'Oczekuje', 'processing' => 'W trakcie', 'done' => 'Zakonczone', 'failed' => 'Blad', 'canceled' => 'Anulowane', 'unknown' => 'Nieznany', ]; return t($map[$status] ?? 'Nieznany'); } function get_job_status(string $job_id, string $job_base): string { 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')) { return 'done'; } if (is_file($job_base . '/done/' . $job_id . '.fail')) { return 'failed'; } if (is_file($job_base . '/done/' . $job_id . '.cancel')) { return 'canceled'; } return 'unknown'; } 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_db = $vars['DB_NAME'] ?? '-'; $log_meta_date = format_backup_label((string)($vars['DATE_DIR'] ?? '-')); $job_type = normalize_job_type($vars); $backup_source = normalize_backup_source($vars); $restore_mode = normalize_restore_mode($vars); $log_meta_backup_kind = backup_source_label($backup_source); $log_meta_restore_mode = restore_mode_label($restore_mode, $job_type); $log_meta_sanitization = sanitize_required_label($vars); $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); $display = display_status(get_job_status($job_id, $job_base), $last_line); $status = status_label($display); if (in_array($display, ['done', 'failed', 'canceled'], true)) { $progress_text = $display === 'done' ? '100%' : status_label($display); } else { $progress_text = $progress !== null ? ($progress . '%') : ($last_line !== '' ? $last_line : '-'); } $header = "Data rozpoczecia: {$log_meta_start}\n"; $header .= "Baza danych: {$log_meta_db}\n"; $header .= "Backup (data katalogu): {$log_meta_date}\n"; $header .= "Rodzaj przywracanej bazy: {$log_meta_backup_kind}\n"; $header .= "Tryb przywracania: {$log_meta_restore_mode}\n"; $header .= "Koniecznosc Sanityzacji: {$log_meta_sanitization}\n"; $header .= "Status: {$status}\n"; $header .= "Postep: {$progress_text}\n"; $header .= "----- log -----\n"; $body = $log_text !== '' ? ($log_text . "\n") : "Log nie istnieje.\n"; return $header . $body; } function load_user_skin(string $user): string { $path = '/usr/local/directadmin/data/users/' . $user . '/user.conf'; if (!is_readable($path)) { return 'enhanced'; } $lines = file($path, FILE_IGNORE_NEW_LINES); if ($lines === false) { return 'enhanced'; } foreach ($lines as $line) { $line = trim($line); if ($line === '' || $line[0] === '#') { continue; } if (preg_match('/^skin=(.+)$/', $line, $m)) { $skin = strtolower(trim($m[1])); if (strpos($skin, 'evolution') !== false) { return 'evolution'; } if (strpos($skin, 'enhanced') !== false) { return 'enhanced'; } return $skin; } } return 'enhanced'; } function list_backup_dates(string $base_dir): array { if (!is_dir($base_dir) || !is_readable($base_dir)) { return []; } $base_real = realpath($base_dir); if ($base_real === false) { return []; } $items = []; foreach (scandir($base_dir) ?: [] as $entry) { if ($entry === '.' || $entry === '..') { continue; } if (!preg_match('/^[A-Za-z0-9._-]+$/', $entry)) { continue; } $path = $base_dir . '/' . $entry; if (!is_dir($path) || is_link($path)) { continue; } $path_real = realpath($path); if ($path_real === false || strpos($path_real, $base_real . '/') !== 0) { continue; } $items[] = [ 'name' => $entry, 'mtime' => @filemtime($path) ?: 0, ]; } usort($items, function ($a, $b) { return $b['mtime'] <=> $a['mtime']; }); return array_map(function ($item) { return $item['name']; }, $items); } function parse_backup_dir_timestamp(string $dir_name, int $fallback = 0): int { if (preg_match('/^(\d{2})[_-](\d{2})[_-](\d{2,4})(?:[-_](\d{2})[_-](\d{2})(?:[_-](\d{2}))?)?$/', $dir_name, $m)) { $day = (int)$m[1]; $month = (int)$m[2]; $year = (int)$m[3]; if ($year < 100) { $year += 2000; } $hour = isset($m[4]) ? (int)$m[4] : 0; $minute = isset($m[5]) ? (int)$m[5] : 0; $second = isset($m[6]) ? (int)$m[6] : 0; if (checkdate($month, $day, $year)) { return mktime($hour, $minute, $second, $month, $day, $year); } } return $fallback > 0 ? $fallback : 0; } function format_backup_label(string $date_dir): string { $ts = parse_backup_dir_timestamp($date_dir, 0); if ($ts > 0) { return date('d-m-Y H:i:s', $ts); } return $date_dir; } function build_restore_confirmation_message( string $source_type, string $source_db, string $target_db, string $restore_mode, string $backup_label = '' ): string { $source_db = trim($source_db); $target_db = trim($target_db); if ($source_db === '') { $source_db = '(nieznana baza)'; } if ($target_db === '') { $target_db = $source_db; } if ($source_type === 'user') { $message = 'Czy na pewno chcesz przywrócić backup bazy danych z kopii zapasowej użytkownika'; if ($backup_label !== '') { $message .= ' z dn. ' . $backup_label; } } else { $message = 'Czy na pewno chcesz przywrócić backup bazy danych z kopii zapasowych HITME.PL'; } if ($restore_mode === 'new_db') { $message .= ' Nazwa bazy: ' . $source_db . ' i przywrócić kopię do nowej bazy danych - ' . $target_db . '.'; $message .= "\n" . 'Wskazana nowa baza danych ' . $target_db . ' musi istnieć. Utwórz ją ręcznie w DirectAdmin przed kontynuowaniem.'; $message .= "\n" . 'Docelowa baza danych ' . $target_db . ' nie może zawierać żadnych danych przed kontynuowaniem operacji.'; return $message; } $message .= ' Nazwa bazy: ' . $source_db . ' i nadpisać istniejącą bazę danych - ' . $target_db . '.'; return $message; } function format_month_label(string $month_value, string $lang_code): string { if (!preg_match('/^(\d{4})-(\d{2})$/', $month_value, $m)) { return $month_value; } $year = $m[1]; $month = (int)$m[2]; $months_pl = [ 1 => 'styczen', 2 => 'luty', 3 => 'marzec', 4 => 'kwiecien', 5 => 'maj', 6 => 'czerwiec', 7 => 'lipiec', 8 => 'sierpien', 9 => 'wrzesien', 10 => 'pazdziernik', 11 => 'listopad', 12 => 'grudzien', ]; $months_en = [ 1 => 'January', 2 => 'February', 3 => 'March', 4 => 'April', 5 => 'May', 6 => 'June', 7 => 'July', 8 => 'August', 9 => 'September', 10 => 'October', 11 => 'November', 12 => 'December', ]; $list = $lang_code === 'pl' ? $months_pl : $months_en; $name = $list[$month] ?? $month_value; return $name . ' ' . $year; } function month_nav_targets(array $available_months, string $selected_month): array { $prev = ''; $next = ''; $idx = array_search($selected_month, $available_months, true); if ($idx !== false) { if ($idx < count($available_months) - 1) { $prev = $available_months[$idx + 1]; } if ($idx > 0) { $next = $available_months[$idx - 1]; } } return ['prev' => $prev, 'next' => $next]; } function calendar_weekdays(string $lang_code): array { if ($lang_code === 'pl') { return ['Pn', 'Wt', 'Sr', 'Cz', 'Pt', 'So', 'Nd']; } return ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; } function render_hidden_inputs_from_params(array $params, array $exclude = []): string { $exclude_map = array_fill_keys($exclude, true); $out = ''; foreach ($params as $key => $value) { if (!is_string($key) || isset($exclude_map[$key])) { continue; } $safe_key = htmlspecialchars($key, ENT_QUOTES, 'UTF-8'); if (is_array($value)) { foreach ($value as $item) { if (is_array($item) || is_object($item)) { continue; } $safe_value = htmlspecialchars((string)$item, ENT_QUOTES, 'UTF-8'); $out .= '' . "\n"; } continue; } if (is_object($value)) { continue; } $safe_value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'); $out .= '' . "\n"; } return $out; } function render_warning_overlay(string $title, string $message, array $params, string $base_url): string { $hidden = render_hidden_inputs_from_params($params, ['confirm_action']); $lines = preg_split('/\r?\n/', $message) ?: [$message]; $printed = 0; ob_start(); ?>

Uwaga:

Nie
DB-Manager

Manager kopii zapasowych baz danych

0 ? date('Y-m-d', $ts) : $dir_name; $slot = [ 'dir' => $dir_name, 'ts' => $ts, 'day_key' => $day_key, 'day_label' => $ts > 0 ? date('d-m-Y', $ts) : $day_key, 'time_label' => $ts > 0 ? date('H:i:s', $ts) : '-', ]; $slots[] = $slot; if (!isset($days[$day_key])) { $days[$day_key] = [ 'day_key' => $day_key, 'day_label' => $slot['day_label'], 'ts' => $ts, 'slots' => [], ]; } $days[$day_key]['slots'][] = $slot; if ($ts > $days[$day_key]['ts']) { $days[$day_key]['ts'] = $ts; } } usort($slots, function ($a, $b) { return $b['ts'] <=> $a['ts']; }); foreach ($days as &$day_info) { usort($day_info['slots'], function ($a, $b) { return $b['ts'] <=> $a['ts']; }); } unset($day_info); uasort($days, function ($a, $b) { return $b['ts'] <=> $a['ts']; }); return [ 'slots' => $slots, 'days' => $days, ]; } function is_trusted_user_backup_dir(string $path_real, string $da_user): bool { $marker = rtrim($path_real, '/') . '/.db-manager-owned'; if (is_readable($marker) && is_file($marker) && !is_link($marker)) { $owner = ''; $user = ''; foreach (file($marker, FILE_IGNORE_NEW_LINES) ?: [] as $line) { $line = trim((string)$line); if ($line === '' || strpos($line, '=') === false) { continue; } [$k, $v] = explode('=', $line, 2); $k = trim((string)$k); $v = trim((string)$v); if ($k === 'OWNER') { $owner = $v; } elseif ($k === 'DA_USER') { $user = $v; } } if ($owner === 'db-manager' && $user === $da_user) { return true; } } $uid = @fileowner($path_real); if ($uid === 0) { return true; } return false; } function list_user_databases(string $base_dir, string $date_dir, string $da_user, bool $trusted_only = false): array { if ($date_dir === '' || !preg_match('/^[A-Za-z0-9._-]+$/', $date_dir)) { return []; } $base_real = realpath($base_dir); $path = $base_dir . '/' . $date_dir; $path_real = realpath($path); if ($base_real === false || $path_real === false || strpos($path_real, $base_real . '/') !== 0) { return []; } if (!is_dir($path_real) || !is_readable($path_real) || is_link($path_real)) { return []; } if ($trusted_only && !is_trusted_user_backup_dir($path_real, $da_user)) { return []; } $items = []; foreach (scandir($path_real) ?: [] as $base) { if ($base === '.' || $base === '..') { continue; } $file = $path_real . '/' . $base; if (!is_file($file) || is_link($file)) { continue; } $file_real = realpath($file); if ($file_real === false || strpos($file_real, $path_real . '/') !== 0) { continue; } $db_name = db_name_from_dump_filename($base); if ($db_name === '') { continue; } if ($db_name !== $da_user && strpos($db_name, $da_user . '_') !== 0) { continue; } $items[] = [ 'name' => $db_name, 'file' => $file_real, 'size' => @filesize($file_real) ?: 0, 'mtime' => @filemtime($file_real) ?: 0, ]; } usort($items, function ($a, $b) { return strcmp($a['name'], $b['name']); }); return $items; } function collect_backup_slots_filtered(string $base_dir, string $da_user, bool $trusted_only = false): array { $slots = []; $days = []; foreach (list_backup_dates($base_dir) as $dir_name) { $dbs = list_user_databases($base_dir, $dir_name, $da_user, $trusted_only); if (empty($dbs)) { continue; } $path = $base_dir . '/' . $dir_name; $mtime = @filemtime($path) ?: 0; $ts = parse_backup_dir_timestamp($dir_name, $mtime); $day_key = $ts > 0 ? date('Y-m-d', $ts) : $dir_name; $slot = [ 'dir' => $dir_name, 'ts' => $ts, 'day_key' => $day_key, 'day_label' => $ts > 0 ? date('d-m-Y', $ts) : $day_key, 'time_label' => $ts > 0 ? date('H:i:s', $ts) : '-', ]; $slots[] = $slot; if (!isset($days[$day_key])) { $days[$day_key] = [ 'day_key' => $day_key, 'day_label' => $slot['day_label'], 'ts' => $ts, 'slots' => [], ]; } $days[$day_key]['slots'][] = $slot; if ($ts > $days[$day_key]['ts']) { $days[$day_key]['ts'] = $ts; } } usort($slots, function ($a, $b) { return $b['ts'] <=> $a['ts']; }); foreach ($days as &$day_info) { usort($day_info['slots'], function ($a, $b) { return $b['ts'] <=> $a['ts']; }); } unset($day_info); uasort($days, function ($a, $b) { return $b['ts'] <=> $a['ts']; }); return [ 'slots' => $slots, 'days' => $days, ]; } function find_user_backup_entry(array $items, string $backup_file): array { if ($backup_file === '' || !preg_match('/^[A-Za-z0-9._-]+$/', $backup_file)) { return []; } foreach ($items as $item) { $item_file = basename((string)($item['file'] ?? '')); if ($item_file === $backup_file) { return $item; } } return []; } function csrf_token_path(string $data_dir, string $user): string { $safe = preg_replace('/[^A-Za-z0-9_.-]/', '_', $user); return $data_dir . '/csrf/' . $safe . '.token'; } function get_csrf_token(string $data_dir, string $user): string { $path = csrf_token_path($data_dir, $user); $dir = dirname($path); if (!is_dir($dir)) { @mkdir($dir, 0700, true); } if (is_readable($path)) { $mtime = @filemtime($path) ?: 0; if ($mtime > 0 && $mtime > (time() - 12 * 3600)) { $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 check_csrf(string $token, string $data_dir, string $user): bool { $path = csrf_token_path($data_dir, $user); if (!is_readable($path)) { return false; } $stored = trim((string)file_get_contents($path)); if ($stored === '' || $token === '') { return false; } return hash_equals($stored, $token); } function is_path_within_dir(string $path, string $dir): bool { $real_path = realpath($path); $real_dir = realpath($dir); if ($real_path === false || $real_dir === false) { return false; } if ($real_path === $real_dir) { return true; } return strpos($real_path, $real_dir . '/') === 0; } function is_path_within_any_dir(string $path, array $dirs): bool { foreach ($dirs as $dir) { if ($dir !== '' && is_path_within_dir($path, $dir)) { return true; } } return false; } function read_mysql_conf_values(string $path): array { $values = [ 'user' => '', 'passwd' => '', 'host' => '', 'port' => '', 'socket' => '', ]; if (!is_readable($path)) { return $values; } $lines = file($path, FILE_IGNORE_NEW_LINES); if ($lines === false) { return $values; } foreach ($lines as $line) { $line = trim($line); if ($line === '' || $line[0] === '#') { continue; } if (strpos($line, '=') === false) { continue; } [$key, $val] = explode('=', $line, 2); $key = trim($key); $val = trim($val); if (array_key_exists($key, $values)) { $values[$key] = $val; } } return $values; } function resolve_bin_path(array $names): string { $dirs = [ '/usr/local/mysql/bin', '/usr/local/mariadb/bin', '/usr/local/bin', '/usr/bin', '/bin', ]; $env_path = getenv('PATH'); if (is_string($env_path) && $env_path !== '') { foreach (explode(':', $env_path) as $part) { if ($part !== '') { $dirs[] = $part; } } } $dirs = array_values(array_unique($dirs)); foreach ($names as $name) { foreach ($dirs as $dir) { $candidate = rtrim($dir, '/') . '/' . $name; if (is_file($candidate) && is_executable($candidate)) { return $candidate; } } } return ''; } function list_owned_databases_via_mysql(string $da_user): array { $mysql_conf = read_mysql_conf_values('/usr/local/directadmin/conf/mysql.conf'); $mysql_bin = resolve_bin_path(['mysql', 'mariadb']); if ($mysql_bin === '') { return []; } $args = [$mysql_bin, '-N', '-B', '-e', 'SHOW DATABASES']; if ($mysql_conf['user'] !== '') { $args[] = '-u'; $args[] = $mysql_conf['user']; } if ($mysql_conf['passwd'] !== '') { $args[] = '--password=' . $mysql_conf['passwd']; } if ($mysql_conf['host'] !== '') { $args[] = '-h'; $args[] = $mysql_conf['host']; } if ($mysql_conf['port'] !== '' && $mysql_conf['port'] !== '0') { $args[] = '-P'; $args[] = $mysql_conf['port']; } if ($mysql_conf['socket'] !== '') { $args[] = '--socket=' . $mysql_conf['socket']; } $cmd = implode(' ', array_map('escapeshellarg', $args)); $stdout = []; $exit_code = 1; @exec($cmd, $stdout, $exit_code); if ($exit_code !== 0) { return []; } $dbs = []; foreach ($stdout as $line) { $db = trim((string)$line); if ($db === '') { continue; } if ($db === $da_user || strpos($db, $da_user . '_') === 0) { $dbs[] = $db; } } sort($dbs, SORT_STRING); return array_values(array_unique($dbs)); } function is_valid_target_db_name(string $db_name, string $da_user): bool { if (!preg_match('/^[A-Za-z0-9_]+$/', $db_name)) { return false; } return strpos($db_name, $da_user . '_') === 0; } function database_has_tables(string $db_name): ?bool { $mysql_conf = read_mysql_conf_values('/usr/local/directadmin/conf/mysql.conf'); $mysql_bin = resolve_bin_path(['mysql', 'mariadb']); if ($mysql_bin === '') { @error_log('db-manager: database_has_tables: mysql client not found'); return null; } $db_sql = str_replace(['\\', "'"], ['\\\\', "\\'"], $db_name); $query = "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='{$db_sql}'"; $args = [$mysql_bin, '-N', '-B', '-e', $query]; if ($mysql_conf['user'] !== '') { $args[] = '-u'; $args[] = $mysql_conf['user']; } if ($mysql_conf['passwd'] !== '') { $args[] = '--password=' . $mysql_conf['passwd']; } if ($mysql_conf['host'] !== '') { $args[] = '-h'; $args[] = $mysql_conf['host']; } if ($mysql_conf['port'] !== '' && $mysql_conf['port'] !== '0') { $args[] = '-P'; $args[] = $mysql_conf['port']; } if ($mysql_conf['socket'] !== '') { $args[] = '--socket=' . $mysql_conf['socket']; } $cmd = implode(' ', array_map('escapeshellarg', $args)); $stdout = []; $exit_code = 1; @exec($cmd, $stdout, $exit_code); if ($exit_code !== 0) { @error_log('db-manager: database_has_tables: mysql query failed for db=' . $db_name . ' exit=' . $exit_code); return null; } $count = isset($stdout[0]) ? (int)trim((string)$stdout[0]) : 0; if ($count < 0) { $count = 0; } return $count > 0; } function render_restore_mode_hidden_fields(string $restore_mode, string $target_db, string $main_tab = ''): string { $html = '' . ''; if ($main_tab === 'hitme' || $main_tab === 'user') { $html .= ''; } return $html; } function trigger_worker(string $plugin_dir): void { $worker = $plugin_dir . '/scripts/worker.sh'; if (!is_file($worker) || !is_executable($worker)) { return; } $cmd = escapeshellarg($worker) . ' >/dev/null 2>&1 &'; if (function_exists('exec')) { @exec($cmd); return; } if (function_exists('shell_exec')) { @shell_exec($cmd); } } function parse_non_negative_int($value, int $default): int { $value = trim((string)$value); if ($value === '' || !preg_match('/^\d+$/', $value)) { return $default; } $num = (int)$value; return $num >= 0 ? $num : $default; } function format_wait_time_pl(int $seconds): string { if ($seconds < 1) { return '1 s'; } $seconds = (int)ceil($seconds); $days = intdiv($seconds, 86400); $seconds %= 86400; $hours = intdiv($seconds, 3600); $seconds %= 3600; $minutes = intdiv($seconds, 60); $seconds %= 60; $parts = []; if ($days > 0) { $parts[] = $days . ' d'; } if ($hours > 0) { $parts[] = $hours . ' h'; } if ($minutes > 0) { $parts[] = $minutes . ' min'; } if ($seconds > 0 || empty($parts)) { $parts[] = $seconds . ' s'; } return implode(' ', $parts); } function get_operation_limit_windows(array $settings, string $op_type): array { if ($op_type === 'backup') { return [ ['seconds' => 300, 'limit' => parse_non_negative_int($settings['BACKUP_LIMIT_5MIN'] ?? '10', 10), 'label' => '5 min'], ['seconds' => 3600, 'limit' => parse_non_negative_int($settings['BACKUP_LIMIT_HOUR'] ?? '30', 30), 'label' => '1 godzina'], ['seconds' => 86400, 'limit' => parse_non_negative_int($settings['BACKUP_LIMIT_DAY'] ?? '100', 100), 'label' => '24 godziny'], ]; } return [ ['seconds' => 300, 'limit' => parse_non_negative_int($settings['RESTORE_LIMIT_5MIN'] ?? '10', 10), 'label' => '5 min'], ['seconds' => 3600, 'limit' => parse_non_negative_int($settings['RESTORE_LIMIT_HOUR'] ?? '30', 30), 'label' => '1 godzina'], ['seconds' => 86400, 'limit' => parse_non_negative_int($settings['RESTORE_LIMIT_DAY'] ?? '100', 100), 'label' => '24 godziny'], ]; } function reserve_operation_limit( string $plugin_data_dir, string $da_user, string $op_type, int $count, array $settings, string &$error_message ): bool { if ($count < 1) { return true; } $limits_enabled = parse_bool((string)($settings['ENABLE_OPERATION_LIMITS'] ?? 'true'), true); if (!$limits_enabled) { return true; } $windows = get_operation_limit_windows($settings, $op_type); $has_any_limit = false; foreach ($windows as $window) { if (($window['limit'] ?? 0) > 0) { $has_any_limit = true; break; } } if (!$has_any_limit) { return true; } $rate_dir = $plugin_data_dir . '/rate_limits'; if (!is_dir($rate_dir) && !@mkdir($rate_dir, 0700, true) && !is_dir($rate_dir)) { return true; } $rate_file = $rate_dir . '/' . preg_replace('/[^A-Za-z0-9_.-]/', '_', $da_user) . '.' . $op_type . '.log'; $fh = @fopen($rate_file, 'c+'); if ($fh === false) { return true; } if (!@flock($fh, LOCK_EX)) { @fclose($fh); return true; } $now = time(); $max_window = 86400; $timestamps = []; rewind($fh); while (($line = fgets($fh)) !== false) { $line = trim($line); if ($line === '' || !preg_match('/^\d+$/', $line)) { continue; } $ts = (int)$line; if ($ts >= ($now - $max_window)) { $timestamps[] = $ts; } } sort($timestamps, SORT_NUMERIC); $max_wait = 0; $limit_label = ''; foreach ($windows as $window) { $limit = (int)$window['limit']; $seconds = (int)$window['seconds']; if ($limit <= 0) { continue; } $recent = []; foreach ($timestamps as $ts) { if ($ts > ($now - $seconds)) { $recent[] = $ts; } } $current_count = count($recent); if (($current_count + $count) > $limit) { $needed = ($current_count + $count) - $limit; $idx = $needed - 1; $candidate_wait = $seconds; if (isset($recent[$idx])) { $candidate_wait = max(1, ($recent[$idx] + $seconds) - $now); } if ($candidate_wait > $max_wait) { $max_wait = $candidate_wait; $limit_label = (string)$window['label']; } } } if ($max_wait > 0) { $op_label = $op_type === 'backup' ? 'tworzenia backupów' : 'przywracania'; $error_message = 'Przekroczono limit operacji ' . $op_label . ' (' . $limit_label . '). Możesz ponowić próbę za ' . format_wait_time_pl($max_wait) . '.'; @flock($fh, LOCK_UN); @fclose($fh); return false; } for ($i = 0; $i < $count; $i++) { $timestamps[] = $now; } sort($timestamps, SORT_NUMERIC); ftruncate($fh, 0); rewind($fh); foreach ($timestamps as $ts) { fwrite($fh, (string)$ts . "\n"); } @fflush($fh); @flock($fh, LOCK_UN); @fclose($fh); return true; } function list_active_jobs_for_user(string $job_base, string $da_user): array { $items = []; $maps = [ 'pending' => 'pending', 'processing' => 'processing', ]; foreach ($maps as $subdir => $status) { foreach (glob($job_base . '/' . $subdir . '/*.env') ?: [] as $path) { if (!is_file($path)) { continue; } $vars = load_job_vars($path); if (($vars['DA_USER'] ?? '') !== $da_user) { continue; } $items[] = [ 'status' => $status, 'job_type' => normalize_job_type($vars), 'db_name' => trim((string)($vars['DB_NAME'] ?? '')), 'start_ts' => (int)trim((string)($vars['START_TS'] ?? '0')), ]; } } usort($items, function ($a, $b) { return ($a['start_ts'] ?? 0) <=> ($b['start_ts'] ?? 0); }); return $items; } function db_lock_dir(string $plugin_dir): string { return rtrim($plugin_dir, '/') . '/data/lock'; } function db_lock_path(string $plugin_dir, string $db_name): string { $safe = preg_replace('/[^A-Za-z0-9_.-]/', '_', trim($db_name)); if ($safe === null || $safe === '') { $safe = 'unknown_db'; } return db_lock_dir($plugin_dir) . '/' . $safe . '.lock'; } function acquire_db_lock(string $plugin_dir, string $db_name, string $job_id, string $job_type, string &$error_message): string { $error_message = ''; $db_name = trim($db_name); if ($db_name === '') { $error_message = t('Nie wybrano poprawnej bazy danych.'); return ''; } $lock_dir = db_lock_dir($plugin_dir); if (!is_dir($lock_dir) && !@mkdir($lock_dir, 0700, true) && !is_dir($lock_dir)) { $error_message = t('Nie mozna zablokowac kolejki zadan. Sprobuj ponownie.'); return ''; } $lock_path = db_lock_path($plugin_dir, $db_name); $fh = @fopen($lock_path, 'x'); if ($fh === false) { $existing_job_type = 'restore'; if (is_readable($lock_path)) { foreach (file($lock_path, FILE_IGNORE_NEW_LINES) ?: [] as $line) { $line = trim((string)$line); if (strpos($line, 'JOB_TYPE=') === 0) { $existing_job_type = strtolower(trim(substr($line, 9))); break; } } } $existing_job_type = $existing_job_type === 'backup' ? 'backup' : 'restore'; $error_message = sprintf( t('Dla bazy %s istnieje juz aktywne zadanie (%s, %s). Zaczekaj na jego zakonczenie i ponow probe.'), $db_name, active_job_type_label($existing_job_type), active_job_status_label('pending') ); return ''; } $job_type = strtolower(trim($job_type)) === 'backup' ? 'backup' : 'restore'; $content = "DB_NAME={$db_name}\nJOB_ID={$job_id}\nJOB_TYPE={$job_type}\nCREATED_TS=" . (string)time() . "\n"; @fwrite($fh, $content); @fflush($fh); @fclose($fh); @chmod($lock_path, 0600); return $lock_path; } function release_db_lock_file(string $path): void { if ($path !== '' && is_file($path)) { @unlink($path); } } function release_db_lock_for_job_path(string $job_path, string $plugin_dir): void { if (!is_file($job_path)) { return; } $vars = load_job_vars($job_path); $db_name = trim((string)($vars['DB_NAME'] ?? '')); if ($db_name === '') { return; } release_db_lock_file(db_lock_path($plugin_dir, $db_name)); } function check_db_lock_present(string $plugin_dir, string $db_name, string &$error_message): bool { $error_message = ''; $db_name = trim($db_name); if ($db_name === '') { return true; } $lock_path = db_lock_path($plugin_dir, $db_name); clearstatcache(true, $lock_path); if (!is_file($lock_path)) { return true; } $existing_job_type = 'restore'; if (is_readable($lock_path)) { foreach (file($lock_path, FILE_IGNORE_NEW_LINES) ?: [] as $line) { $line = trim((string)$line); if (strpos($line, 'JOB_TYPE=') === 0) { $existing_job_type = strtolower(trim(substr($line, 9))); break; } } } $existing_job_type = $existing_job_type === 'backup' ? 'backup' : 'restore'; $error_message = sprintf( t('Dla bazy %s istnieje juz aktywne zadanie (%s, %s). Zaczekaj na jego zakonczenie i ponow probe.'), $db_name, active_job_type_label($existing_job_type), active_job_status_label('pending') ); return false; } function acquire_jobs_queue_lock(string $job_base, string &$error_message) { $error_message = ''; if (!is_dir($job_base) && !@mkdir($job_base, 0700, true) && !is_dir($job_base)) { $error_message = t('Nie mozna zablokowac kolejki zadan. Sprobuj ponownie.'); return null; } $lock_path = rtrim($job_base, '/') . '/.queue.lock'; $fh = @fopen($lock_path, 'c+'); if ($fh === false) { $error_message = t('Nie mozna zablokowac kolejki zadan. Sprobuj ponownie.'); return null; } @chmod($lock_path, 0600); if (!@flock($fh, LOCK_EX)) { @fclose($fh); $error_message = t('Nie mozna zablokowac kolejki zadan. Sprobuj ponownie.'); return null; } return $fh; } function release_jobs_queue_lock($fh): void { if (is_resource($fh)) { @flock($fh, LOCK_UN); @fclose($fh); } } function active_job_type_label(string $job_type): string { return $job_type === 'backup' ? t('Tworzenie kopii zapasowej') : t('Przywracanie kopii zapasowej'); } function active_job_status_label(string $status): string { return $status === 'processing' ? t('jest w trakcie') : t('oczekuje w kolejce'); } function check_database_collisions( array $settings, string $plugin_dir, string $job_base, string $da_user, string &$error_message, string $db_name = '' ): bool { $collisions_enabled = parse_bool((string)($settings['CHECK_DATABASE_COLLISIONS'] ?? 'true'), true); if (!$collisions_enabled) { return true; } $db_name = trim($db_name); if ($db_name === '') { return true; } if (!check_db_lock_present($plugin_dir, $db_name, $error_message)) { return false; } $active_jobs = list_active_jobs_for_user($job_base, $da_user); foreach ($active_jobs as $job) { $active_db_name = trim((string)($job['db_name'] ?? '')); if ($active_db_name === '' || $active_db_name !== $db_name) { continue; } $active_job_type = strtolower(trim((string)($job['job_type'] ?? ''))); $active_job_type = $active_job_type === 'backup' ? 'backup' : 'restore'; $job_type = active_job_type_label($active_job_type); $status = active_job_status_label((string)($job['status'] ?? 'pending')); $error_message = sprintf( t('Dla bazy %s istnieje juz aktywne zadanie (%s, %s). Zaczekaj na jego zakonczenie i ponow probe.'), $db_name, $job_type, $status ); return false; } return true; } function list_jobs(string $dir, string $status, string $pattern, string $log_dir, string $pid_dir, string $cancel_dir, string $da_user, array $pre_restore_dirs): array { $items = []; foreach (glob($dir . '/' . $pattern) ?: [] as $path) { $vars = load_job_vars($path); if (($vars['DA_USER'] ?? '') !== $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)) { $last = last_non_empty_line(read_log_tail($log_path, 2000)); $display_status = display_status($status, $last); $progress = extract_progress($last); if ($cancel_requested) { $display_status = 'canceled'; $progress_text = 'Anulowane'; } elseif ($progress !== null) { $progress_text = $progress . '%'; } elseif ($last !== '') { $progress_text = $last; } else { $progress_text = 'W trakcie'; } } elseif ($status === 'done') { $progress_text = '100%'; } elseif ($status === 'failed') { $progress_text = 'Blad'; } elseif ($status === 'canceled') { $progress_text = 'Anulowane'; } $pre_backup_path = trim((string)($vars['PRE_BACKUP_PATH'] ?? '')); $pre_backup_exists = $pre_backup_path !== '' && is_file($pre_backup_path) && is_path_within_any_dir($pre_backup_path, $pre_restore_dirs); $job_type = normalize_job_type($vars); $backup_source = normalize_backup_source($vars); $restore_mode = normalize_restore_mode($vars); $items[] = [ 'status' => $status, 'display_status' => $display_status, 'file' => basename($path), 'time' => @filemtime($path) ?: 0, 'job_id' => $job_id, 'log_exists' => is_readable($log_path), 'progress_text' => $progress_text, 'cancel_requested' => $cancel_requested, 'db_name' => $vars['DB_NAME'] ?? '', 'date_dir' => $vars['DATE_DIR'] ?? '', 'start_ts' => $vars['START_TS'] ?? '', 'pid' => $pid, 'pre_backup_path' => $pre_backup_path, 'pre_backup_exists' => $pre_backup_exists, 'backup_source' => $backup_source, 'job_type' => $job_type, 'restore_mode' => $restore_mode, 'backup_kind_label' => backup_source_label($backup_source), 'restore_mode_label' => restore_mode_label($restore_mode, $job_type), ]; } return $items; } function render_jobs_section(array $jobs, string $csrf_token, string $base_url, bool $enable_logs_overlay, bool $prevent_log_deletion): string { if (empty($jobs)) { return '

Brak zadan do wyswietlenia.

'; } ob_start(); ?>
Data Rozpoczecia Nazwa Bazy Data Backupu Rodzaj przywracanej bazy Tryb Pracy Status Akcje
Pokaż logi'; } else { $actions[] = 'Pokaż logi'; } } ?> ' . '' . '' . '' . '' . ''; ?> Zapisz log'; ?> ' . '' . '' . '' . '' . ''; $actions[] = '
' . '' . '' . '' . '' . '
'; ?> ' . '' . '' . '' . '' . ''; ?>

Log zadania

X

Podglad na zywo (odswiezanie co 3s)

Data rozpoczecia:
Baza danych:
Backup (data katalogu):
Rodzaj przywracanej bazy:
Tryb przywracania:
Koniecznosc sanityzacji:
Status:
Postep:
Brak baz danych uzytkownika do backupu.

'; } ob_start(); ?>
Nazwa Bazy Akcja
' . h($empty_state_message) . '

'; } ob_start(); ?>

Kalendarz backupow uzytkownika

'; for ($col = 1; $col <= 7; $col++) { if (($row === 0 && $col < $calendar_offset) || $day_num > $calendar_days) { echo ''; continue; } $day_key = date('Y-m-', $month_ts) . str_pad((string)$day_num, 2, '0', STR_PAD_LEFT); $is_active = isset($days[$day_key]); $is_selected = $day_key === $selected_day; echo ''; $day_num++; } echo ''; if ($day_num > $calendar_days) { break; } } ?>
'; if ($is_active) { echo ''; } else { echo '' . h((string)$day_num) . ''; } echo '

Wybierz backup i baze

Wybierz aktywna date w kalendarzu.

1) { ?>

Data rozpoczecia generowania backupow

Baza danych Rozmiar Data i godzina backupu Akcje
required />

Brak baz dla wybranego backupu.

Wybierz godzine backupu, aby zobaczyc liste baz.

$day_info) { if (substr($day_key, 0, 7) === $selected_month) { $selected_day = $day_key; break; } } if ($selected_day === '' && !empty($days)) { $selected_day = (string)array_key_first($days); } } $day_slots = ($selected_day !== '' && isset($days[$selected_day])) ? $days[$selected_day]['slots'] : []; $slot_names = array_map(function ($slot) { return $slot['dir']; }, $day_slots); if ($selected_slot === '' && count($slot_names) === 1) { $selected_slot = $slot_names[0]; } if ($selected_slot !== '' && !in_array($selected_slot, $slot_names, true)) { $selected_slot = ''; } $databases = $selected_slot !== '' ? list_user_databases($hitme_dir, $selected_slot, $da_user, false) : []; $active_user_tab = (string)($params['user_tab'] ?? 'backup_create'); if ($active_user_tab !== 'backup_create' && $active_user_tab !== 'restore_user') { $active_user_tab = 'backup_create'; } $main_tab_raw = trim((string)($params['main_tab'] ?? '')); $main_tab_from_request = $main_tab_raw === 'hitme' || ($enable_user_backups && $main_tab_raw === 'user'); $main_tab = $main_tab_raw; if (!$main_tab_from_request) { $user_main_actions = ['user_tab', 'queue_user_backup', 'restore_user', 'download_user_backup', 'delete_user_backup']; $main_tab = ($enable_user_backups && in_array((string)$action, $user_main_actions, true)) ? 'user' : 'hitme'; } if (!$enable_user_backups) { $main_tab = 'hitme'; $active_user_tab = 'restore_user'; } $owned_user_dbs = list_owned_databases_via_mysql($da_user); $u_selected_day = trim((string)($params['u_day'] ?? '')); $u_selected_slot = trim((string)($params['u_slot'] ?? '')); $u_selected_month = trim((string)($params['u_month'] ?? '')); $u_selected_db = trim((string)($params['u_db'] ?? '')); $u_slot_index = collect_backup_slots_filtered($user_backup_runtime_dir, $da_user, $own_backup_user_restore); $u_days = $u_slot_index['days']; $user_restore_empty_message = 'Brak kopii zapasowych użytkownika dostępnych do przywrócenia - najpierw utwórz kopię zapasową na zakładce Wykonaj Backup Baz danych'; $u_available_months = []; foreach ($u_days as $day_info) { $u_available_months[substr($day_info['day_key'], 0, 7)] = true; } $u_available_months = array_keys($u_available_months); rsort($u_available_months, SORT_STRING); if ($u_selected_month === '') { $u_selected_month = !empty($u_available_months) ? $u_available_months[0] : date('Y-m'); } if (!in_array($u_selected_month, $u_available_months, true) && !empty($u_available_months)) { $u_selected_month = $u_available_months[0]; } if ($u_selected_day === '' || !isset($u_days[$u_selected_day]) || substr($u_selected_day, 0, 7) !== $u_selected_month) { $u_selected_day = ''; foreach ($u_days as $day_key => $day_info) { if (substr($day_key, 0, 7) === $u_selected_month) { $u_selected_day = $day_key; break; } } if ($u_selected_day === '' && !empty($u_days)) { $u_selected_day = (string)array_key_first($u_days); } } $u_day_slots = ($u_selected_day !== '' && isset($u_days[$u_selected_day])) ? $u_days[$u_selected_day]['slots'] : []; $u_slot_names = array_map(function ($slot) { return $slot['dir']; }, $u_day_slots); if ($u_selected_slot === '' && count($u_slot_names) === 1) { $u_selected_slot = $u_slot_names[0]; } if ($u_selected_slot !== '' && !in_array($u_selected_slot, $u_slot_names, true)) { $u_selected_slot = ''; } $u_databases = $u_selected_slot !== '' ? list_user_databases($user_backup_runtime_dir, $u_selected_slot, $da_user, $own_backup_user_restore) : []; function require_csrf(string $token, string $data_dir, string $user, array &$errors): bool { if (!check_csrf($token, $data_dir, $user)) { $errors[] = 'Nieprawidlowy token CSRF.'; return false; } return true; } $confirm_overlay_html = ''; if (!$enable_user_backups && in_array((string)$action, ['user_tab', 'queue_user_backup', 'restore_user', 'download_user_backup', 'delete_user_backup'], true)) { $errors[] = 'Sekcja backupow uzytkownika jest wylaczona.'; $action = ''; } if ($method === 'POST') { $confirm_required_actions = ['restore', 'restore_user', 'restore_pre_backup', 'delete_pre_backup', 'delete_user_backup']; if (!$prevent_log_deletion) { $confirm_required_actions[] = 'delete_job'; } $confirm_flag = (string)($params['confirm_action'] ?? ''); if ($confirm_flag !== '1' && in_array($action, ['restore', 'restore_user', 'restore_pre_backup'], true)) { $target_for_lock_check = $target_restore_db !== '' ? $target_restore_db : ($da_user . '_'); $db_for_lock_check = ''; if ($action === 'restore') { $restore_source_db = trim((string)($params['db'] ?? $selected_db)); $db_for_lock_check = $restore_mode === 'new_db' ? $target_for_lock_check : ($restore_source_db !== '' ? $restore_source_db : $target_for_lock_check); } elseif ($action === 'restore_user') { $restore_user_source_db = trim((string)($params['u_db'] ?? $u_selected_db)); $db_for_lock_check = $restore_mode === 'new_db' ? $target_for_lock_check : ($restore_user_source_db !== '' ? $restore_user_source_db : $target_for_lock_check); } elseif ($action === 'restore_pre_backup') { $job_file = basename((string)($params['job'] ?? '')); $job_id = job_id_from_file($job_file); if ($job_id !== '' && job_belongs_to_user($job_id, $job_base, $da_user)) { $job_file_path = find_job_file($job_base, $job_file, $job_id); $vars = $job_file_path !== '' ? load_job_vars($job_file_path) : []; $db_for_lock_check = trim((string)($vars['DB_NAME'] ?? '')); } } if ($db_for_lock_check !== '') { $lock_error = ''; if (!check_database_collisions($settings, $plugin_dir, $job_base, $da_user, $lock_error, $db_for_lock_check)) { $errors[] = $lock_error; $action = ''; } } } if (in_array($action, $confirm_required_actions, true) && $confirm_flag !== '1') { $target_for_warning = $target_restore_db !== '' ? $target_restore_db : ($da_user . '_'); $restore_source_db = trim((string)($params['db'] ?? $selected_db)); $restore_user_source_db = trim((string)($params['u_db'] ?? $u_selected_db)); $restore_slot_user = trim((string)($params['u_slot'] ?? $u_selected_slot)); $restore_user_label = $restore_slot_user !== '' ? format_backup_label($restore_slot_user) : ''; $restore_target_db = $restore_mode === 'new_db' ? $target_for_warning : ($restore_source_db !== '' ? $restore_source_db : $target_for_warning); $restore_user_target_db = $restore_mode === 'new_db' ? $target_for_warning : ($restore_user_source_db !== '' ? $restore_user_source_db : $target_for_warning); $confirm_messages = [ 'restore' => build_restore_confirmation_message('hitme', $restore_source_db, $restore_target_db, $restore_mode), 'restore_user' => build_restore_confirmation_message('user', $restore_user_source_db, $restore_user_target_db, $restore_mode, $restore_user_label), 'restore_pre_backup' => 'Przywrócenie backupu sprzed przywrócenia może nadpisać obecne dane. Czy kontynuować?', 'delete_pre_backup' => 'Usunięcie backupu sprzed przywrócenia jest nieodwracalne. Czy kontynuować?', 'delete_job' => 'Usuniesz log i wpis zadania. Tej operacji nie można cofnąć. Czy kontynuować?', 'delete_user_backup' => 'Usuniesz backup użytkownika. Tej operacji nie można cofnąć. Czy kontynuować?', ]; $confirm_overlay_html = render_warning_overlay( 'Potwierdzenie operacji', $confirm_messages[$action] ?? 'Czy kontynuować operację?', $params, $base_url ); $action = ''; } } if ($action === 'user_tab') { header('Content-Type: text/html; charset=utf-8'); $html = render_user_tabs( $active_user_tab, $owned_user_dbs, $base_url, $csrf_token, $u_selected_month, $u_selected_day, $u_selected_slot, $u_selected_db, $u_available_months, $u_days, $u_day_slots, $u_databases, $lang_code, $restore_mode, $target_restore_db, $main_tab, $user_restore_empty_message ); echo translate_html_safe($html, $lang_map ?? []); exit; } if ($action === 'restore' && $method === 'POST') { $token = (string)($params['csrf_token'] ?? ''); require_csrf($token, $plugin_data_dir, $da_user, $errors); if ($selected_day === '' || !isset($days[$selected_day])) { $errors[] = 'Nie wybrano poprawnej daty backupu.'; } if ($selected_slot === '' || !in_array($selected_slot, $slot_names, true)) { $errors[] = 'Nie wybrano poprawnej godziny backupu.'; } $db_map = []; foreach ($databases as $db) { $db_map[$db['name']] = $db; } if ($selected_db === '' || !isset($db_map[$selected_db])) { $errors[] = 'Nie wybrano poprawnej bazy danych.'; } $target_db_for_restore = $selected_db; if ($restore_mode === 'new_db') { if ($target_restore_db === '' || !is_valid_target_db_name($target_restore_db, $da_user)) { $errors[] = 'Nazwa docelowej bazy danych musi zaczynać się od prefiksu ' . $da_user . '_ (DA_USER_).'; } elseif ($target_restore_db === $selected_db) { $errors[] = 'Docelowa baza danych musi byc inna niz zrodlowa baza z backupu.'; } elseif (!in_array($target_restore_db, $owned_user_dbs, true)) { $errors[] = 'Wskazana docelowa baza danych nie istnieje. Utworz ja recznie w DirectAdmin.'; } else { $has_tables = database_has_tables($target_restore_db); if ($has_tables === null) { $errors[] = 'Nie udalo sie sprawdzic, czy docelowa baza danych jest pusta.'; } elseif ($has_tables === true) { $errors[] = 'Docelowa baza danych nie jest pusta. Usun dane przed kontynuowaniem.'; } } if (empty($errors)) { $target_db_for_restore = $target_restore_db; } } $queue_lock = null; if (empty($errors)) { $lock_error = ''; $queue_lock = acquire_jobs_queue_lock($job_base, $lock_error); if ($queue_lock === null) { $errors[] = $lock_error; } } if (empty($errors)) { $sim_error = ''; if (!check_database_collisions($settings, $plugin_dir, $job_base, $da_user, $sim_error, $target_db_for_restore)) { $errors[] = $sim_error; } } if (empty($errors)) { $limit_error = ''; if (!reserve_operation_limit($plugin_data_dir, $da_user, 'restore', 1, $settings, $limit_error)) { $errors[] = $limit_error; } } if (empty($errors)) { $job_dir = $job_base . '/pending'; if (!is_dir($job_dir) && !@mkdir($job_dir, 0700, true) && !is_dir($job_dir)) { $errors[] = 'Nie mozna utworzyc katalogu zadan.'; } else { $job_id = date('YmdHis') . '-' . bin2hex(random_bytes(4)); $job_file = $job_dir . '/restore-' . $job_id . '.env'; $dump_path = (string)($db_map[$selected_db]['file'] ?? ''); if ($dump_path === '' || !is_file($dump_path)) { $errors[] = 'Nie znaleziono pliku dump dla wybranej bazy.'; } } $db_lock_path = ''; if (empty($errors)) { $db_lock_error = ''; $db_lock_path = acquire_db_lock($plugin_dir, $target_db_for_restore, $job_id, 'restore', $db_lock_error); if ($db_lock_path === '') { $errors[] = $db_lock_error; } } if (empty($errors)) { $job_content = "DA_USER=" . escapeshellarg($da_user) . "\n"; $job_content .= "START_TS=" . escapeshellarg((string)time()) . "\n"; $job_content .= "DATE_DIR=" . escapeshellarg($selected_slot) . "\n"; $job_content .= "DB_NAME=" . escapeshellarg($target_db_for_restore) . "\n"; $job_content .= "SOURCE_DB_NAME=" . escapeshellarg($selected_db) . "\n"; $job_content .= "DUMP_FILE=" . escapeshellarg($dump_path) . "\n"; $job_content .= "DB_LOCK_FILE=" . escapeshellarg($db_lock_path) . "\n"; $job_content .= "BACKUP_SOURCE=" . escapeshellarg('hosting') . "\n"; $job_content .= "RESTORE_MODE=" . escapeshellarg($restore_mode) . "\n"; if (@file_put_contents($job_file, $job_content, LOCK_EX) === false) { release_db_lock_file($db_lock_path); $errors[] = 'Nie udalo sie zapisac pliku zadania.'; } else { @chmod($job_file, 0600); trigger_worker($plugin_dir); $message_status = 'Zadanie przywracania bazy dodane do kolejki. Otrzymasz powiadomienie po zakonczeniu.'; } } } release_jobs_queue_lock($queue_lock); } if ($action === 'queue_user_backup' && $method === 'POST') { $token = (string)($params['csrf_token'] ?? ''); require_csrf($token, $plugin_data_dir, $da_user, $errors); if ($restore_mode === 'new_db') { $errors[] = 'W trybie przywracania do nowej bazy tworzenie backupow uzytkownika jest ukryte.'; } $selected_dbs = []; $single_db = trim((string)($params['single_db'] ?? '')); if ($single_db !== '') { $selected_dbs[] = $single_db; } else { $raw = $params['dbs'] ?? []; if (!is_array($raw)) { $raw = [$raw]; } foreach ($raw as $db) { $db = trim((string)$db); if ($db !== '') { $selected_dbs[] = $db; } } $selected_dbs = array_values(array_unique($selected_dbs)); if (!empty($params['bulk_backup']) && count($selected_dbs) < 2) { $errors[] = 'Aby wykonac backup zbiorczy zaznacz co najmniej dwie bazy.'; } } if (empty($selected_dbs)) { $errors[] = 'Nie wybrano baz do backupu.'; } $allowed = array_fill_keys($owned_user_dbs, true); foreach ($selected_dbs as $db) { if (!isset($allowed[$db])) { $errors[] = 'Nieprawidlowa baza danych: ' . $db; break; } } $queue_lock = null; if (empty($errors)) { $lock_error = ''; $queue_lock = acquire_jobs_queue_lock($job_base, $lock_error); if ($queue_lock === null) { $errors[] = $lock_error; } } if (empty($errors)) { $sim_error = ''; foreach ($selected_dbs as $db_name_to_backup) { if (!check_database_collisions($settings, $plugin_dir, $job_base, $da_user, $sim_error, $db_name_to_backup)) { $errors[] = $sim_error; break; } } } if (empty($errors)) { $limit_error = ''; if (!reserve_operation_limit($plugin_data_dir, $da_user, 'backup', count($selected_dbs), $settings, $limit_error)) { $errors[] = $limit_error; } } if (empty($errors)) { $job_dir = $job_base . '/pending'; if (!is_dir($job_dir) && !@mkdir($job_dir, 0700, true) && !is_dir($job_dir)) { $errors[] = 'Nie mozna utworzyc katalogu zadan.'; } else { $date_dir = date('d-m-Y_H_i'); $target_dir = rtrim($user_backup_runtime_dir, '/') . '/' . $date_dir; if (is_dir($target_dir)) { do { $date_dir = date('d-m-Y_H_i_s'); $target_dir = rtrim($user_backup_runtime_dir, '/') . '/' . $date_dir; if (!is_dir($target_dir)) { break; } usleep(250000); } while (true); } while (is_dir($target_dir)) { usleep(250000); $date_dir = date('d-m-Y_H_i_s'); $target_dir = rtrim($user_backup_runtime_dir, '/') . '/' . $date_dir; } if (!is_dir($target_dir) && !@mkdir($target_dir, 0700, true) && !is_dir($target_dir)) { $errors[] = 'Nie mozna utworzyc katalogu backupu uzytkownika.'; } else { $queued = 0; foreach ($selected_dbs as $db) { $job_id = date('YmdHis') . '-' . bin2hex(random_bytes(4)); $job_file = $job_dir . '/backup-' . $job_id . '.env'; $db_lock_error = ''; $db_lock_path = acquire_db_lock($plugin_dir, $db, $job_id, 'backup', $db_lock_error); if ($db_lock_path === '') { $errors[] = $db_lock_error; continue; } $job_content = "JOB_TYPE=" . escapeshellarg('backup') . "\n"; $job_content .= "DA_USER=" . escapeshellarg($da_user) . "\n"; $job_content .= "START_TS=" . escapeshellarg((string)time()) . "\n"; $job_content .= "DATE_DIR=" . escapeshellarg($date_dir) . "\n"; $job_content .= "DB_NAME=" . escapeshellarg($db) . "\n"; $job_content .= "DB_LOCK_FILE=" . escapeshellarg($db_lock_path) . "\n"; $job_content .= "BACKUP_SOURCE=" . escapeshellarg('user') . "\n"; $job_content .= "RESTORE_MODE=" . escapeshellarg('backup') . "\n"; if (@file_put_contents($job_file, $job_content, LOCK_EX) === false) { release_db_lock_file($db_lock_path); $errors[] = 'Nie udalo sie zapisac pliku zadania backupu dla bazy ' . $db . '.'; continue; } @chmod($job_file, 0600); $queued++; } if ($queued > 0) { trigger_worker($plugin_dir); $message_status = $queued === 1 ? 'Dodano zadanie backupu bazy danych.' : sprintf('Dodano zadania backupu %d baz danych.', $queued); } } } } release_jobs_queue_lock($queue_lock); } if ($action === 'download_hitme_backup' && $method === 'POST') { $token = (string)($params['csrf_token'] ?? ''); require_csrf($token, $plugin_data_dir, $da_user, $errors); if (!$allow_download_hitme_sql_backup) { $errors[] = 'Pobieranie backupow HITME.SQL jest wylaczone.'; } $backup_file = basename((string)($params['backup_file'] ?? '')); $download_slot = trim((string)($params['slot'] ?? '')); if (empty($errors) && !preg_match('/^[A-Za-z0-9._-]+$/', $download_slot)) { $errors[] = 'Nie wybrano poprawnej godziny backupu.'; } if (empty($errors) && !preg_match('/^[A-Za-z0-9._-]+$/', $backup_file)) { $errors[] = 'Nieprawidlowa nazwa pliku backupu.'; } $slot_dir = ''; $slot_real = false; if (empty($errors)) { $slot_dir = rtrim($hitme_dir, '/') . '/' . $download_slot; $slot_real = realpath($slot_dir); if ($slot_real === false || !is_dir($slot_real) || !is_path_within_dir($slot_real, $hitme_dir)) { $errors[] = 'Nieprawidlowa sciezka backupu.'; } } $backup_path = ''; $source_db_name = ''; if (empty($errors)) { $source_db_name = db_name_from_dump_filename($backup_file); if ($source_db_name === '') { $errors[] = 'Nieprawidlowa nazwa pliku backupu.'; } elseif ($source_db_name !== $da_user && strpos($source_db_name, $da_user . '_') !== 0) { $errors[] = 'Nieprawidlowa sciezka backupu.'; } } if (empty($errors)) { $backup_path = (string)$slot_real . '/' . $backup_file; if (!is_file($backup_path) || !is_path_within_dir($backup_path, $hitme_dir)) { $errors[] = 'Nie znaleziono pliku dump dla wybranej bazy.'; } } if (empty($errors)) { while (ob_get_level() > 0) { @ob_end_clean(); } if (headers_sent($hs_file, $hs_line)) { $errors[] = 'Nie mozna pobrac pliku backupu (naglowki zostaly juz wyslane).'; @file_put_contents($plugin_log, date('Y-m-d H:i:s') . " download_hitme_backup headers_sent {$hs_file}:{$hs_line}\n", FILE_APPEND); } else { $download_name = basename($backup_path); $content_type = 'application/octet-stream'; if (preg_match('/\.sql$/i', $download_name)) { $content_type = 'application/sql'; } elseif (preg_match('/\.gz$/i', $download_name)) { $content_type = 'application/gzip'; } header('Content-Type: ' . $content_type); header('Content-Disposition: attachment; filename="' . $download_name . '"'); header('X-Content-Type-Options: nosniff'); header('Cache-Control: no-store, no-cache, must-revalidate'); $size = @filesize($backup_path); if (is_int($size) && $size > 0) { header('Content-Length: ' . $size); } readfile($backup_path); exit; } } if (!empty($errors)) { @file_put_contents( $plugin_log, date('Y-m-d H:i:s') . ' download_hitme_backup error: ' . implode(' | ', $errors) . "\n", FILE_APPEND ); } } if ($action === 'download_user_backup' && $method === 'POST') { $token = (string)($params['csrf_token'] ?? ''); require_csrf($token, $plugin_data_dir, $da_user, $errors); $backup_file = basename((string)($params['backup_file'] ?? '')); $download_slot = trim((string)($params['u_slot'] ?? '')); if (empty($errors) && !preg_match('/^[A-Za-z0-9._-]+$/', $download_slot)) { $errors[] = 'Nie wybrano poprawnej godziny backupu uzytkownika.'; } if (empty($errors) && !preg_match('/^[A-Za-z0-9._-]+$/', $backup_file)) { $errors[] = 'Nieprawidlowa nazwa pliku backupu uzytkownika.'; } $slot_dir = ''; $slot_real = false; if (empty($errors)) { $slot_dir = rtrim($user_backup_runtime_dir, '/') . '/' . $download_slot; $slot_real = realpath($slot_dir); if ($slot_real === false || !is_dir($slot_real) || !is_path_within_dir($slot_real, $user_backup_runtime_dir)) { $errors[] = 'Nieprawidlowa sciezka backupu uzytkownika.'; } } $backup_path = ''; $source_db_name = ''; if (empty($errors)) { $source_db_name = db_name_from_dump_filename($backup_file); if ($source_db_name === '') { $errors[] = 'Nieprawidlowa nazwa pliku backupu uzytkownika.'; } elseif ($source_db_name !== $da_user && strpos($source_db_name, $da_user . '_') !== 0) { $errors[] = 'Nieprawidlowa sciezka backupu uzytkownika.'; } } if (empty($errors)) { $backup_path = (string)$slot_real . '/' . $backup_file; if (!is_file($backup_path) || !is_path_within_dir($backup_path, $user_backup_runtime_dir)) { $errors[] = 'Nie znaleziono pliku dump dla wybranej bazy.'; } } if (empty($errors)) { while (ob_get_level() > 0) { @ob_end_clean(); } if (headers_sent($hs_file, $hs_line)) { $errors[] = 'Nie mozna pobrac pliku backupu (naglowki zostaly juz wyslane).'; @file_put_contents($plugin_log, date('Y-m-d H:i:s') . " download_user_backup headers_sent {$hs_file}:{$hs_line}\n", FILE_APPEND); } else { $download_name = basename($backup_path); $content_type = 'application/octet-stream'; if (preg_match('/\.sql$/i', $download_name)) { $content_type = 'application/sql'; } elseif (preg_match('/\.gz$/i', $download_name)) { $content_type = 'application/gzip'; } header('Content-Type: ' . $content_type); header('Content-Disposition: attachment; filename="' . $download_name . '"'); header('X-Content-Type-Options: nosniff'); header('Cache-Control: no-store, no-cache, must-revalidate'); $size = @filesize($backup_path); if (is_int($size) && $size > 0) { header('Content-Length: ' . $size); } readfile($backup_path); exit; } } if (!empty($errors)) { @file_put_contents( $plugin_log, date('Y-m-d H:i:s') . ' download_user_backup error: ' . implode(' | ', $errors) . "\n", FILE_APPEND ); } } if ($action === 'delete_user_backup' && $method === 'POST') { $token = (string)($params['csrf_token'] ?? ''); require_csrf($token, $plugin_data_dir, $da_user, $errors); $backup_file = basename((string)($params['backup_file'] ?? '')); if ($u_selected_slot === '' || !in_array($u_selected_slot, $u_slot_names, true)) { $errors[] = 'Nie wybrano poprawnej godziny backupu uzytkownika.'; } $entry = empty($errors) ? find_user_backup_entry($u_databases, $backup_file) : []; $backup_path = (string)($entry['file'] ?? ''); if (empty($errors) && ($backup_path === '' || !is_file($backup_path))) { $errors[] = 'Nie znaleziono pliku dump dla wybranej bazy.'; } if (empty($errors) && !is_path_within_dir($backup_path, $user_backup_runtime_dir)) { $errors[] = 'Nieprawidlowa sciezka backupu uzytkownika.'; } if (empty($errors) && !@unlink($backup_path)) { $errors[] = 'Nie udalo sie usunac backupu uzytkownika.'; } if (empty($errors)) { $message_status = 'Backup uzytkownika zostal usuniety.'; $u_slot_index = collect_backup_slots_filtered($user_backup_runtime_dir, $da_user, $own_backup_user_restore); $u_days = $u_slot_index['days']; $u_available_months = []; foreach ($u_days as $day_info) { $u_available_months[substr($day_info['day_key'], 0, 7)] = true; } $u_available_months = array_keys($u_available_months); rsort($u_available_months, SORT_STRING); if (empty($u_days)) { $u_selected_month = date('Y-m'); $u_selected_day = ''; $u_selected_slot = ''; $u_selected_db = ''; $u_day_slots = []; $u_slot_names = []; $u_databases = []; $user_restore_empty_message = 'Brak kopii zapasowych użytkownika dostępnych do przywrócenia - najpierw utwórz kopię zapasową na zakładce Wykonaj Backup Baz danych'; } else { // Po usunieciu backupu zawsze przechodzimy na najnowszy dostepny backup. $u_selected_day = (string)array_key_first($u_days); $u_selected_month = substr($u_selected_day, 0, 7); $u_day_slots = $u_days[$u_selected_day]['slots'] ?? []; $u_slot_names = array_map(function ($slot) { return $slot['dir']; }, $u_day_slots); $u_selected_slot = !empty($u_slot_names) ? (string)$u_slot_names[0] : ''; $u_databases = $u_selected_slot !== '' ? list_user_databases($user_backup_runtime_dir, $u_selected_slot, $da_user, $own_backup_user_restore) : []; $u_selected_db = !empty($u_databases) ? (string)($u_databases[0]['name'] ?? '') : ''; } } } if ($action === 'restore_user' && $method === 'POST') { $token = (string)($params['csrf_token'] ?? ''); require_csrf($token, $plugin_data_dir, $da_user, $errors); if ($u_selected_day === '' || !isset($u_days[$u_selected_day])) { $errors[] = 'Nie wybrano poprawnej daty backupu uzytkownika.'; } if ($u_selected_slot === '' || !in_array($u_selected_slot, $u_slot_names, true)) { $errors[] = 'Nie wybrano poprawnej godziny backupu uzytkownika.'; } $u_db_map = []; foreach ($u_databases as $db) { $u_db_map[$db['name']] = $db; } if ($u_selected_db === '' || !isset($u_db_map[$u_selected_db])) { $errors[] = 'Nie wybrano poprawnej bazy danych.'; } $target_db_for_restore = $u_selected_db; if ($restore_mode === 'new_db') { if ($target_restore_db === '' || !is_valid_target_db_name($target_restore_db, $da_user)) { $errors[] = 'Nazwa docelowej bazy danych musi zaczynać się od prefiksu ' . $da_user . '_ (DA_USER_).'; } elseif ($target_restore_db === $u_selected_db) { $errors[] = 'Docelowa baza danych musi byc inna niz zrodlowa baza z backupu.'; } elseif (!in_array($target_restore_db, $owned_user_dbs, true)) { $errors[] = 'Wskazana docelowa baza danych nie istnieje. Utworz ja recznie w DirectAdmin.'; } else { $has_tables = database_has_tables($target_restore_db); if ($has_tables === null) { $errors[] = 'Nie udalo sie sprawdzic, czy docelowa baza danych jest pusta.'; } elseif ($has_tables === true) { $errors[] = 'Docelowa baza danych nie jest pusta. Usun dane przed kontynuowaniem.'; } } if (empty($errors)) { $target_db_for_restore = $target_restore_db; } } $queue_lock = null; if (empty($errors)) { $lock_error = ''; $queue_lock = acquire_jobs_queue_lock($job_base, $lock_error); if ($queue_lock === null) { $errors[] = $lock_error; } } if (empty($errors)) { $sim_error = ''; if (!check_database_collisions($settings, $plugin_dir, $job_base, $da_user, $sim_error, $target_db_for_restore)) { $errors[] = $sim_error; } } if (empty($errors)) { $limit_error = ''; if (!reserve_operation_limit($plugin_data_dir, $da_user, 'restore', 1, $settings, $limit_error)) { $errors[] = $limit_error; } } if (empty($errors)) { $job_dir = $job_base . '/pending'; if (!is_dir($job_dir) && !@mkdir($job_dir, 0700, true) && !is_dir($job_dir)) { $errors[] = 'Nie mozna utworzyc katalogu zadan.'; } else { $job_id = date('YmdHis') . '-' . bin2hex(random_bytes(4)); $job_file = $job_dir . '/restore-' . $job_id . '.env'; $dump_path = (string)($u_db_map[$u_selected_db]['file'] ?? ''); if ($dump_path === '' || !is_file($dump_path)) { $errors[] = 'Nie znaleziono pliku dump dla wybranej bazy.'; } else { $db_lock_error = ''; $db_lock_path = acquire_db_lock($plugin_dir, $target_db_for_restore, $job_id, 'restore', $db_lock_error); if ($db_lock_path === '') { $errors[] = $db_lock_error; } } if (empty($errors)) { $job_content = "DA_USER=" . escapeshellarg($da_user) . "\n"; $job_content .= "START_TS=" . escapeshellarg((string)time()) . "\n"; $job_content .= "DATE_DIR=" . escapeshellarg($u_selected_slot) . "\n"; $job_content .= "DB_NAME=" . escapeshellarg($target_db_for_restore) . "\n"; $job_content .= "SOURCE_DB_NAME=" . escapeshellarg($u_selected_db) . "\n"; $job_content .= "DUMP_FILE=" . escapeshellarg($dump_path) . "\n"; $job_content .= "DB_LOCK_FILE=" . escapeshellarg($db_lock_path) . "\n"; $job_content .= "BACKUP_SOURCE=" . escapeshellarg('user') . "\n"; $job_content .= "RESTORE_MODE=" . escapeshellarg($restore_mode) . "\n"; if (@file_put_contents($job_file, $job_content, LOCK_EX) === false) { release_db_lock_file($db_lock_path); $errors[] = 'Nie udalo sie zapisac pliku zadania.'; } else { @chmod($job_file, 0600); trigger_worker($plugin_dir); $message_status = 'Zadanie przywracania backupu uzytkownika dodane do kolejki.'; } } } } release_jobs_queue_lock($queue_lock); } if ($action === 'restore_pre_backup' && $method === 'POST') { $token = (string)($params['csrf_token'] ?? ''); require_csrf($token, $plugin_data_dir, $da_user, $errors); $file = basename((string)($params['job'] ?? '')); $job_id = job_id_from_file($file); if ($job_id === '' || !job_belongs_to_user($job_id, $job_base, $da_user)) { $errors[] = 'Nie znaleziono zadania.'; } else { $job_file_path = find_job_file($job_base, $file, $job_id); $vars = $job_file_path !== '' ? load_job_vars($job_file_path) : []; $db_name = trim((string)($vars['DB_NAME'] ?? '')); $pre_backup_path = trim((string)($vars['PRE_BACKUP_PATH'] ?? '')); if ($db_name === '') { $errors[] = 'Brak nazwy bazy w zadaniu.'; } elseif ($pre_backup_path === '' || !is_file($pre_backup_path)) { $errors[] = 'Backup przed przywroceniem nie istnieje.'; } elseif (!is_path_within_any_dir($pre_backup_path, [$pre_restore_dir, $pre_restore_user_dir])) { $errors[] = 'Nieprawidlowa sciezka backupu przed przywroceniem.'; } else { $queue_lock = null; $lock_error = ''; $queue_lock = acquire_jobs_queue_lock($job_base, $lock_error); if ($queue_lock === null) { $errors[] = $lock_error; } if (empty($errors)) { $sim_error = ''; if (!check_database_collisions($settings, $plugin_dir, $job_base, $da_user, $sim_error, $db_name)) { $errors[] = $sim_error; } } if (empty($errors)) { $limit_error = ''; if (!reserve_operation_limit($plugin_data_dir, $da_user, 'restore', 1, $settings, $limit_error)) { $errors[] = $limit_error; } } if (empty($errors)) { $job_dir = $job_base . '/pending'; if (!is_dir($job_dir) && !@mkdir($job_dir, 0700, true) && !is_dir($job_dir)) { $errors[] = 'Nie mozna utworzyc katalogu zadan.'; } else { $new_job_id = date('YmdHis') . '-' . bin2hex(random_bytes(4)); $new_job_file = $job_dir . '/restore-' . $new_job_id . '.env'; $db_lock_error = ''; $db_lock_path = acquire_db_lock($plugin_dir, $db_name, $new_job_id, 'restore', $db_lock_error); if ($db_lock_path === '') { $errors[] = $db_lock_error; } } if (empty($errors)) { $job_content = "DA_USER=" . escapeshellarg($da_user) . "\n"; $job_content .= "START_TS=" . escapeshellarg((string)time()) . "\n"; $job_content .= "DATE_DIR=" . escapeshellarg(basename($pre_backup_path)) . "\n"; $job_content .= "DB_NAME=" . escapeshellarg($db_name) . "\n"; $job_content .= "DUMP_FILE=" . escapeshellarg($pre_backup_path) . "\n"; $job_content .= "DB_LOCK_FILE=" . escapeshellarg($db_lock_path) . "\n"; $source = is_path_within_dir($pre_backup_path, $pre_restore_user_dir) ? 'user' : 'hosting'; $job_content .= "BACKUP_SOURCE=" . escapeshellarg($source) . "\n"; $job_content .= "RESTORE_MODE=" . escapeshellarg('overwrite') . "\n"; if (@file_put_contents($new_job_file, $job_content, LOCK_EX) === false) { release_db_lock_file($db_lock_path); $errors[] = 'Nie udalo sie zapisac pliku zadania.'; } else { @chmod($new_job_file, 0600); trigger_worker($plugin_dir); $message_status = 'Dodano zadanie przywracania backupu przed przywroceniem.'; } } } release_jobs_queue_lock($queue_lock); } } } if ($action === 'delete_pre_backup' && $method === 'POST') { $token = (string)($params['csrf_token'] ?? ''); require_csrf($token, $plugin_data_dir, $da_user, $errors); $file = basename((string)($params['job'] ?? '')); $job_id = job_id_from_file($file); if ($job_id === '' || !job_belongs_to_user($job_id, $job_base, $da_user)) { $errors[] = 'Nie znaleziono zadania.'; } else { $job_file_path = find_job_file($job_base, $file, $job_id); $vars = $job_file_path !== '' ? load_job_vars($job_file_path) : []; $pre_backup_path = trim((string)($vars['PRE_BACKUP_PATH'] ?? '')); if ($pre_backup_path === '' || !is_file($pre_backup_path)) { $errors[] = 'Backup przed przywroceniem nie istnieje.'; } elseif (!is_path_within_any_dir($pre_backup_path, [$pre_restore_dir, $pre_restore_user_dir])) { $errors[] = 'Nieprawidlowa sciezka backupu przed przywroceniem.'; } elseif (!@unlink($pre_backup_path)) { $errors[] = 'Nie udalo sie usunac backupu przed przywroceniem.'; } else { $message_status = 'Backup przed przywroceniem zostal usuniety.'; } } } if ($action === 'cancel_job' && $method === 'POST') { $token = (string)($params['csrf_token'] ?? ''); require_csrf($token, $plugin_data_dir, $da_user, $errors); $file = basename((string)($params['job'] ?? '')); $job_id = job_id_from_file($file); if ($job_id === '' || !job_belongs_to_user($job_id, $job_base, $da_user)) { $errors[] = 'Nieprawidlowe zadanie.'; } elseif (!empty($errors)) { } else { $pending_file = $job_base . '/pending/' . $file; $processing_file = $job_base . '/processing/' . $file; $cancel_file = $cancel_dir . '/' . $job_id . '.flag'; if (is_file($pending_file)) { release_db_lock_for_job_path($pending_file, $plugin_dir); $target = $job_base . '/done/' . $job_id . '.cancel'; if (@rename($pending_file, $target)) { $message_status = 'Zadanie zostalo anulowane.'; } else { @unlink($pending_file); $message_status = 'Zadanie zostalo anulowane.'; } } elseif (!is_file($processing_file)) { $errors[] = '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)) { $errors[] = 'Nie znaleziono procesu do anulowania.'; } elseif (!function_exists('posix_kill')) { $errors[] = 'Brak obsugi 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"); $message_status = 'Zadanie zostalo anulowane.'; } else { $errors[] = 'Nie udalo sie anulowac zadania.'; } } } } } if ($action === 'delete_selected' && $method === 'POST') { $token = (string)($params['csrf_token'] ?? ''); require_csrf($token, $plugin_data_dir, $da_user, $errors); if ($prevent_log_deletion) { $errors[] = 'Usuwanie logow i wpisow zadan jest zablokowane przez konfiguracje.'; } else { $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); if ($job_id === '' || !job_belongs_to_user($job_id, $job_base, $da_user)) { continue; } foreach (['pending', 'processing', 'done'] as $dir) { foreach (glob($job_base . '/' . $dir . '/' . $job_id . '*') ?: [] as $path) { if (is_file($path)) { if ($dir !== 'processing') { release_db_lock_for_job_path($path, $plugin_dir); } @unlink($path); } } } @unlink($log_dir . '/' . $job_id . '.log'); @unlink($pid_dir . '/' . $job_id . '.pid'); @unlink($cancel_dir . '/' . $job_id . '.flag'); $deleted++; } $message_status = $deleted > 0 ? 'Wybrane zadania zostaly usuniete.' : 'Nie wybrano zadnych zadan.'; } } if ($action === 'delete_job' && $method === 'POST') { $token = (string)($params['csrf_token'] ?? ''); require_csrf($token, $plugin_data_dir, $da_user, $errors); if ($prevent_log_deletion) { $errors[] = 'Usuwanie logow i wpisow zadan jest zablokowane przez konfiguracje.'; } else { $file = basename((string)($params['job'] ?? '')); $job_id = job_id_from_file($file); if ($job_id === '' || !job_belongs_to_user($job_id, $job_base, $da_user)) { $errors[] = 'Nie znaleziono zadania.'; } else { foreach (['pending', 'processing', 'done'] as $dir) { foreach (glob($job_base . '/' . $dir . '/' . $job_id . '*') ?: [] as $path) { if (is_file($path)) { if ($dir !== 'processing') { release_db_lock_for_job_path($path, $plugin_dir); } @unlink($path); } } } @unlink($log_dir . '/' . $job_id . '.log'); @unlink($pid_dir . '/' . $job_id . '.pid'); @unlink($cancel_dir . '/' . $job_id . '.flag'); $message_status = 'Zadanie zostalo usuniete.'; } } } if ($action === 'download_log' && $method === 'POST') { $token = (string)($params['csrf_token'] ?? ''); if (!check_csrf($token, $plugin_data_dir, $da_user)) { header('HTTP/1.1 403 Forbidden'); exit; } $file = basename((string)($params['job'] ?? '')); $job_id = job_id_from_file($file); if ($job_id === '' || !job_belongs_to_user($job_id, $job_base, $da_user)) { header('HTTP/1.1 404 Not Found'); exit; } $job_file_path = find_job_file($job_base, $job_id . '.env', $job_id); $log_path = $log_dir . '/' . $job_id . '.log'; $content = build_log_download_content($job_id, $job_file_path, $log_path, $job_base); if (!empty($lang_map)) { $content = translate_text($content, $lang_map); } $raw = trim((string)($params['raw'] ?? '')) === '1'; if ($raw) { log_text_output($content); } header('Content-Type: text/plain; charset=utf-8'); header('Content-Disposition: attachment; filename="' . $job_id . '.log"'); echo $content; exit; } $view_log_job = ''; $log_meta_start = ''; $log_meta_db = ''; $log_meta_date = ''; $log_meta_backup_kind = ''; $log_meta_restore_mode = ''; $log_meta_sanitization = 'Nie'; $log_status_value = ''; $log_message_view = ''; $log_progress = null; $log_last_line = '-'; $view_log_status = ''; if ($action === 'view_log') { $file = basename((string)($params['job'] ?? '')); $job_id = job_id_from_file($file); if ($job_id === '' || !job_belongs_to_user($job_id, $job_base, $da_user)) { $errors[] = 'Nie znaleziono logu.'; } else { $job_file_path = find_job_file($job_base, $job_id . '.env', $job_id); $vars = load_job_vars($job_file_path); $log_meta_start = format_datetime($vars['START_TS'] ?? '', time()); $log_meta_db = $vars['DB_NAME'] ?? '-'; $log_meta_date = format_backup_label((string)($vars['DATE_DIR'] ?? '-')); $log_meta_backup_kind = backup_source_label(normalize_backup_source($vars)); $log_meta_restore_mode = restore_mode_label(normalize_restore_mode($vars), normalize_job_type($vars)); $log_meta_sanitization = sanitize_required_label($vars); $status = get_job_status($job_id, $job_base); $log_path = $log_dir . '/' . $job_id . '.log'; $log_message_view = normalize_log(read_log_tail($log_path, 2000)); $log_last_line = last_non_empty_line($log_message_view); $display = display_status($status, $log_last_line); $log_status_value = status_label($display); $log_progress = extract_progress($log_last_line); if (in_array($display, ['done', 'failed', 'canceled'], true)) { $log_progress = $display === 'done' ? 100 : 0; $log_last_line = status_label($display); } elseif ($log_last_line === '') { $log_last_line = '-'; } $view_log_status = $status; $view_log_job = $file; } $view_log_overlay = $enable_logs_overlay && (($params['overlay'] ?? '') === '1'); if ($view_log_overlay) { header('Content-Type: text/html; charset=utf-8'); if ($view_log_job === '') { echo translate_html_safe('
Nie znaleziono logu.
', $lang_map ?? []); } else { $overlay_html = render_log_view_html( $view_log_job, $log_meta_start, $log_meta_db, $log_meta_date, $log_meta_backup_kind, $log_meta_restore_mode, $log_meta_sanitization, $log_status_value, $log_progress, $log_last_line, $log_message_view, $view_log_status, true, $base_url ); echo translate_html_safe($overlay_html, $lang_map ?? []); } exit; } } $jobs = array_merge( list_jobs($job_base . '/pending', 'pending', '*.env', $log_dir, $pid_dir, $cancel_dir, $da_user, [$pre_restore_dir, $pre_restore_user_dir]), list_jobs($job_base . '/processing', 'processing', '*.env', $log_dir, $pid_dir, $cancel_dir, $da_user, [$pre_restore_dir, $pre_restore_user_dir]), list_jobs($job_base . '/done', 'done', '*.ok', $log_dir, $pid_dir, $cancel_dir, $da_user, [$pre_restore_dir, $pre_restore_user_dir]), list_jobs($job_base . '/done', 'failed', '*.fail', $log_dir, $pid_dir, $cancel_dir, $da_user, [$pre_restore_dir, $pre_restore_user_dir]), list_jobs($job_base . '/done', 'canceled', '*.cancel', $log_dir, $pid_dir, $cancel_dir, $da_user, [$pre_restore_dir, $pre_restore_user_dir]) ); usort($jobs, function ($a, $b) { return $b['time'] <=> $a['time']; }); if (count($jobs) > 50) { $jobs = array_slice($jobs, 0, 50); } if ($action === 'status') { header('Content-Type: text/html; charset=utf-8'); $status_html = render_jobs_section($jobs, $csrf_token, $base_url, $enable_logs_overlay, $prevent_log_deletion); echo translate_html_safe($status_html, $lang_map ?? []); exit; } 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); if ($job_id === '' || !job_belongs_to_user($job_id, $job_base, $da_user)) { header('HTTP/1.1 403 Forbidden'); exit; } $log_path = $log_dir . '/' . $job_id . '.log'; $log_text = normalize_log(read_log_tail($log_path, 2000)); $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 . '%') : ($last_line !== '' ? $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; } $active_day_keys = array_keys($days); $month_ts = strtotime($selected_month . '-01'); if ($month_ts === false) { $month_ts = strtotime(date('Y-m-01')); } $calendar_days = (int)date('t', $month_ts); $calendar_offset = (int)date('N', $month_ts); $hosting_month_nav = month_nav_targets($available_months, $selected_month); $hosting_weekdays = calendar_weekdays($lang_code); ob_start(); ?> Manager kopii zapasowych baz danych
Manager kopii zapasowych baz danych

Tryb przywracania baz danych

Backupy udostepniane przez HITME.PL

Kalendarz backupow

Brak aktywnych dat backupu dla tego uzytkownika.

'; for ($col = 1; $col <= 7; $col++) { if (($row === 0 && $col < $calendar_offset) || $day_num > $calendar_days) { echo ''; continue; } $day_key = date('Y-m-', $month_ts) . str_pad((string)$day_num, 2, '0', STR_PAD_LEFT); $is_active = isset($days[$day_key]); $is_selected = $day_key === $selected_day; echo ''; $day_num++; } echo ''; if ($day_num > $calendar_days) { break; } } ?>
'; if ($is_active) { echo ''; } else { echo '' . h((string)$day_num) . ''; } echo '

Wybierz backup i baze

Wybierz aktywna date w kalendarzu.

1) { ?>

Data rozpoczecia generowania backupow

Baza danych Rozmiar Data i godzina backupu Akcje
required />

Brak baz dla wybranego backupu.

Wybierz godzine backupu, aby zobaczyc liste baz.

Backupy Uzytkownika

Status zadan

Katalogi kopii zapasowych

Backup przed przywroceniem (HITME.PL):

Backupy uzytkownika:

Backup przed przywroceniem (backupy uzytkownika):