getMessage() . "\n", FILE_APPEND); throw new Exception("Failed to connect to SFTP server: " . $exception->getMessage()); } function zipFolderRecursive($sftp, $remoteBasePath, $currentPath, $zip, $logFile, &$temporaryFiles) { file_put_contents($logFile, "Processing directory: $currentPath\n", FILE_APPEND); $files = $sftp->nlist($currentPath); if ($files === false) { file_put_contents($logFile, "Failed to list directory contents for: $currentPath\n", FILE_APPEND); throw new Exception("Failed to list directory contents for: $currentPath"); } file_put_contents($logFile, "Found " . count($files) . " items in $currentPath\n", FILE_APPEND); foreach ($files as $fileName) { if ($fileName == '.' || $fileName == '..') continue; $remotePath = rtrim($currentPath, '/') . '/' . $fileName; $relativePath = substr($remotePath, strlen(rtrim(remoteDirname($remoteBasePath), '/')) + 1); file_put_contents($logFile, "Processing: $remotePath (relative: $relativePath)\n", FILE_APPEND); $isDirectory = $sftp->is_dir($remotePath); if ($isDirectory) { file_put_contents($logFile, "Found subdirectory: $remotePath\n", FILE_APPEND); $zip->addEmptyDir($relativePath); zipFolderRecursive($sftp, $remoteBasePath, $remotePath, $zip, $logFile, $temporaryFiles); } else { $temporaryFile = tempnam(sys_get_temp_dir(), 'sftp'); $temporaryFiles[] = $temporaryFile; file_put_contents($logFile, "Downloading to temp file: $temporaryFile\n", FILE_APPEND); $downloadStart = time(); $downloadSuccess = $sftp->get($remotePath, $temporaryFile); $downloadTime = time() - $downloadStart; if ($downloadSuccess) { $fileSize = filesize($temporaryFile); file_put_contents($logFile, "Download successful ($downloadTime seconds), size: $fileSize bytes\n", FILE_APPEND); $zip->addFile($temporaryFile, $relativePath); } else { file_put_contents($logFile, "Failed to download file after $downloadTime seconds\n", FILE_APPEND); } } } } function zipFolder($sftp, $folderPath, $zipFilePath, $logFile) { file_put_contents($logFile, "Starting to zip folder recursively: $folderPath\n", FILE_APPEND); $zip = new ZipArchive(); if ($zip->open($zipFilePath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) { file_put_contents($logFile, "Failed to create zip archive\n", FILE_APPEND); throw new Exception("Unable to create the zip file."); } $temporaryFiles = []; try { zipFolderRecursive($sftp, $folderPath, $folderPath, $zip, $logFile, $temporaryFiles); file_put_contents($logFile, "Closing zip file\n", FILE_APPEND); $zipSuccess = $zip->close(); foreach ($temporaryFiles as $temporaryFile) { if (file_exists($temporaryFile)) { @unlink($temporaryFile); } } if ($zipSuccess) { file_put_contents($logFile, "Zip created successfully, size: " . filesize($zipFilePath) . " bytes\n", FILE_APPEND); return true; } else { file_put_contents($logFile, "Failed to create zip\n", FILE_APPEND); return false; } } catch (Exception $exception) { foreach ($temporaryFiles as $temporaryFile) { if (file_exists($temporaryFile)) { @unlink($temporaryFile); } } file_put_contents($logFile, "Error during zip creation: " . $exception->getMessage() . "\n", FILE_APPEND); throw $exception; } } if (($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['file'])) || ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['file']))) { $filePath = requireRemotePath($_SERVER['REQUEST_METHOD'] === 'POST' ? $_POST['file'] : $_GET['file'], $defaultPath); file_put_contents($logFile, "Requested file: $filePath\n", FILE_APPEND); $fileExists = $sftp->file_exists($filePath); $isDirectory = $sftp->is_dir($filePath); file_put_contents($logFile, "File exists: " . ($fileExists ? "Yes" : "No") . "\n", FILE_APPEND); file_put_contents($logFile, "Is directory: " . ($isDirectory ? "Yes" : "No") . "\n", FILE_APPEND); if (!$fileExists && !$isDirectory) { throw new Exception("File not found: $filePath"); } if ($isDirectory) { $zipFilePath = tempnam(sys_get_temp_dir(), 'folder_') . '.zip'; file_put_contents($logFile, "Creating zip at: $zipFilePath\n", FILE_APPEND); if (zipFolder($sftp, $filePath, $zipFilePath, $logFile)) { if (file_exists($zipFilePath) && filesize($zipFilePath) > 0) { file_put_contents($logFile, "Sending zip file to browser, size: " . filesize($zipFilePath) . " bytes\n", FILE_APPEND); while (ob_get_level()) { ob_end_clean(); } header('Content-Type: application/zip'); header('Content-Disposition: attachment; filename="' . basename($filePath) . '.zip"'); header('Content-Length: ' . filesize($zipFilePath)); header('Cache-Control: no-cache, must-revalidate'); header('Pragma: no-cache'); readfile($zipFilePath); file_put_contents($logFile, "Download completed\n", FILE_APPEND); @unlink($zipFilePath); exit; } else { throw new Exception("Failed to create zip file or zip file is empty"); } } else { throw new Exception("Failed to create zip archive"); } } else { $fileName = basename($filePath); file_put_contents($logFile, "Downloading single file: $fileName\n", FILE_APPEND); $temporaryFile = tempnam(sys_get_temp_dir(), 'file_'); $downloadStart = time(); $downloadSuccess = $sftp->get($filePath, $temporaryFile); $downloadTime = time() - $downloadStart; file_put_contents($logFile, "Download " . ($downloadSuccess ? "successful" : "failed") . " ($downloadTime seconds)\n", FILE_APPEND); if ($downloadSuccess) { $fileSize = filesize($temporaryFile); file_put_contents($logFile, "Downloaded file size: $fileSize bytes\n", FILE_APPEND); if ($fileSize > 0) { while (ob_get_level()) { ob_end_clean(); } header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . $fileName . '"'); header('Content-Length: ' . $fileSize); header('Cache-Control: no-cache, must-revalidate'); header('Pragma: no-cache'); readfile($temporaryFile); file_put_contents($logFile, "Download completed\n", FILE_APPEND); @unlink($temporaryFile); exit; } else { @unlink($temporaryFile); throw new Exception("Downloaded file is empty"); } } else { @unlink($temporaryFile); throw new Exception("Failed to download file from SFTP server"); } } } else { throw new Exception("Invalid request method or missing file parameter"); } } catch (Exception $exception) { $errorMessage = "Error: " . $exception->getMessage(); file_put_contents($logFile, $errorMessage . "\n", FILE_APPEND); while (ob_get_level()) { ob_end_clean(); } header("HTTP/1.1 500 Internal Server Error"); echo $errorMessage; } ?>