'Forbidden']); exit; } // PHP limits - scoped to this file-restore operation only if (function_exists('set_time_limit')) { set_time_limit(300); } if (function_exists('ini_set')) { ini_set('memory_limit', '512M'); // phpcs:ignore WordPress.PHP.IniSet.memory_limit_Blacklisted } if (function_exists('ignore_user_abort')) { ignore_user_abort(true); } // Json headers are defined by wp_send_json // Basit sanitizasyon function alldami_sanitize_key($key) { $key = strtolower($key); return preg_replace('/[^a-z0-9_\-]/', '', $key); } $job_id = isset($_POST['job_id']) ? alldami_sanitize_key($_POST['job_id']) : ''; $step = isset($_POST['step']) ? alldami_sanitize_key($_POST['step']) : ''; if (empty($job_id)) { echo json_encode(['success' => false, 'message' => 'Geçersiz job_id']); exit; } // State dosyasını oku $state_file = ALLDAMI_STATE_DIR . $job_id . '.json'; if (!file_exists($state_file)) { echo json_encode(['success' => false, 'message' => 'Job bulunamadı: ' . $job_id]); exit; } $state = json_decode(file_get_contents($state_file), true); if (!$state) { echo json_encode(['success' => false, 'message' => 'State okunamadı']); exit; } // Security Token Kontrolü $token_check_enabled = true; if (isset($state['settings']['security_import_token_enabled'])) { $token_check_enabled = (bool) $state['settings']['security_import_token_enabled']; } if ($token_check_enabled && !empty($state['import_token'])) { $provided_token = isset($_POST['token']) ? $_POST['token'] : ''; if ($provided_token !== $state['import_token']) { echo json_encode(['success' => false, 'message' => 'Geçersiz güvenlik token\'ı']); exit; } // Token Expiry Kontrolü (6 saat) $token_created_at = isset($state['import_token_created_at']) ? (int) $state['import_token_created_at'] : 0; $token_max_age = 6 * 3600; // 6 saat if ($token_created_at > 0 && (time() - $token_created_at) > $token_max_age) { echo json_encode(['success' => false, 'message' => 'Güvenlik token\'ı süresi dolmuş.']); exit; } } // PHP limits - scoped to active restore operation if (function_exists('set_time_limit')) { set_time_limit(300); } if (function_exists('ignore_user_abort')) { ignore_user_abort(true); } if (function_exists('ini_set')) { ini_set('memory_limit', '512M'); // phpcs:ignore WordPress.PHP.IniSet.memory_limit_Blacklisted } // Çalışma dizini $work_dir = WP_CONTENT_DIR . '/uploads/alldami-site-migration/temp/' . $job_id . '/'; $files_dir = $work_dir . 'files/'; // Arşiv dosyalarını al $archive_files = []; if (is_dir($files_dir)) { $files = scandir($files_dir); foreach ($files as $file) { if (substr($file, -4) === '.zip') { $archive_files[] = $file; } } sort($archive_files); } if (empty($archive_files)) { // Dosya yok, sonraki adıma geç echo json_encode([ 'success' => true, 'data' => [ 'next_step' => 'replace_direct', 'message' => 'Geri yüklenecek dosya bulunamadı, devam ediliyor...', 'progress' => null ] ]); exit; } $current_index = $state['resume_pointer']['current_archive'] ?? 0; // Tüm arşivler işlendi mi? if ($current_index >= count($archive_files)) { // UI güncelle $state['steps']['file_restore']['status'] = 'completed'; $state['steps']['file_restore']['progress'] = 100; // Sonraki adım $state['steps']['replace']['status'] = 'running'; $state['steps']['replace']['progress'] = 0; $state['messages'][] = [ 'type' => 'success', 'text' => 'Dosya geri yükleme tamamlandı.', 'time' => gmdate('H:i:s') ]; file_put_contents($state_file, json_encode($state)); echo json_encode([ 'success' => true, 'data' => [ 'next_step' => 'replace_direct', 'message' => 'Dosya geri yükleme tamamlandı', 'progress' => null ] ]); exit; } // Mevcut arşivi işle $archive_file = $archive_files[$current_index]; $archive_path = $files_dir . $archive_file; if (!file_exists($archive_path)) { echo json_encode(['success' => false, 'message' => 'Arşiv bulunamadı: ' . $archive_path]); exit; } $zip = new ZipArchive(); if ($zip->open($archive_path) === true) { // extractTo kullanımı: Windows/Linux path uyumluluğu ve performans için daha iyi // WP_CONTENT_DIR hedefimiz if ($zip->extractTo(WP_CONTENT_DIR)) { $extracted = $zip->numFiles; $zip->close(); } else { // Fallback: extractTo başarısız olursa manuel deneyelim (izin sorunları vs için) // Ama genellikle extractTo daha güvenilirdir. $zip->close(); echo json_encode(['success' => false, 'message' => 'Arşiv çıkartılamadı (extractTo failed): ' . $archive_file]); exit; } // State güncelle $state['resume_pointer']['current_archive'] = $current_index + 1; // Progress yüzdesini güncelle $total_archives = count($archive_files); $current_progress = round((($current_index + 1) / $total_archives) * 100); $state['steps']['file_restore']['progress'] = $current_progress; // Genel ilerlemeyi de güncelle (basit hesap: %60 - %90 arası file_restore olsun) // DB import %60'ta bitiyor, file restore %90'da bitsin. // %60 + (%30 * current_file_progress) $state['overall_progress'] = 60 + round($current_progress * 0.3); $state['messages'][] = [ 'type' => 'info', 'text' => sprintf('Arşiv geri yüklendi: %s (%d dosya)', $archive_file, $extracted), 'time' => gmdate('H:i:s') ]; file_put_contents($state_file, json_encode($state)); // Sonraki adımı belirle $next_step = ($current_index + 1 >= count($archive_files)) ? 'replace_direct' : 'file_restore_direct'; echo json_encode([ 'success' => true, 'data' => [ 'next_step' => $next_step, 'job_id' => $job_id, 'message' => sprintf('Arşiv: %s (%d/%d)', $archive_file, $current_index + 1, count($archive_files)), 'extracted' => $extracted, 'progress' => [ 'current' => $current_index + 1, 'total' => count($archive_files) ] ] ]); } else { echo json_encode(['success' => false, 'message' => 'Arşiv açılamadı: ' . $archive_file]); }