PHP实现远程FTP大文件夹清理、重排及跨FTP传输方案问询
Alright, let's tackle this complex FTP file processing workflow with PHP. I'll walk you through a step-by-step, efficient solution that handles large nested folders (50MB–4GB) while hitting all your requirements:
First, we need to establish connections to both FTP servers and set up a local temporary directory to work with the files—processing large files directly in memory isn't feasible.
// FTP1 (source server) credentials $ftp1Host = 'ftp1.example.com'; $ftp1User = 'your-ftp1-username'; $ftp1Pass = 'your-ftp1-password'; // Target FTP server credentials $targetFtpHost = 'target-ftp.example.com'; $targetFtpUser = 'your-target-username'; $targetFtpPass = 'your-target-password'; // Create a unique temporary local directory $tempDir = sys_get_temp_dir() . '/ftp_process_' . uniqid(); mkdir($tempDir, 0777, true); // Connect to source FTP $ftp1Conn = ftp_connect($ftp1Host); ftp_login($ftp1Conn, $ftp1User, $ftp1Pass); ftp_pasv($ftp1Conn, true); // Enable passive mode for better firewall compatibility // Connect to target FTP $targetFtpConn = ftp_connect($targetFtpHost); ftp_login($targetFtpConn, $targetFtpUser, $targetFtpPass); ftp_pasv($targetFtpConn, true);
We'll use a recursive function to download all files and subdirectories from the source FTP. This handles the complex folder structure seamlessly:
function downloadFtpDirectory($ftpConn, $remoteDir, $localDir) { $files = ftp_nlist($ftpConn, $remoteDir); foreach ($files as $file) { // Skip "." and ".." entries if (in_array(basename($file), ['.', '..'])) continue; $localPath = $localDir . '/' . basename($file); // Check if it's a directory if (ftp_chdir($ftpConn, $file)) { ftp_chdir($ftpConn, '..'); // Go back to parent mkdir($localPath, 0777, true); downloadFtpDirectory($ftpConn, $file, $localPath); } else { // Download the file in binary mode to preserve integrity ftp_get($ftpConn, $localPath, $file, FTP_BINARY); } } } // Start downloading from the source FTP's target folder (adjust path as needed) $remoteRoot = '/path/to/source/folder'; downloadFtpDirectory($ftp1Conn, $remoteRoot, $tempDir);
Next, we'll delete all .exe, .pdf, and other unwanted files, then move all remaining files to the root of our temporary directory to flatten the nested structure:
// Define unwanted file extensions $unwantedExts = ['exe', 'pdf']; function processLocalFiles($dir, $targetRoot, $unwantedExts) { $items = scandir($dir); foreach ($items as $item) { if (in_array($item, ['.', '..'])) continue; $fullPath = $dir . '/' . $item; if (is_dir($fullPath)) { processLocalFiles($fullPath, $targetRoot, $unwantedExts); // Delete empty directory after processing its contents rmdir($fullPath); } else { $ext = strtolower(pathinfo($fullPath, PATHINFO_EXTENSION)); // Delete unwanted files if (in_array($ext, $unwantedExts)) { unlink($fullPath); continue; } // Move file to root, handle duplicates by appending a counter $targetPath = $targetRoot . '/' . basename($fullPath); $counter = 1; while (file_exists($targetPath)) { $filename = pathinfo($fullPath, PATHINFO_FILENAME); $targetPath = $targetRoot . "/{$filename}_{$counter}.{$ext}"; $counter++; } rename($fullPath, $targetPath); } } } processLocalFiles($tempDir, $tempDir, $unwantedExts);
Now we'll sort the flattened files into your predefined directory structure. For example, let's use a common structure based on file types:
// Define your preset directory structure and associated extensions $presetStructure = [ 'docs' => ['txt', 'docx', 'doc', 'odt'], 'images' => ['jpg', 'jpeg', 'png', 'gif', 'svg'], 'data' => ['csv', 'json', 'xml', 'xlsx'] ]; // Create preset directories if they don't exist foreach (array_keys($presetStructure) as $dir) { $presetDir = $tempDir . '/' . $dir; if (!is_dir($presetDir)) mkdir($presetDir, 0777, true); } // Move files to their respective directories $files = scandir($tempDir); foreach ($files as $file) { if (in_array($file, ['.', '..']) || is_dir($tempDir . '/' . $file)) continue; $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION)); $moved = false; foreach ($presetStructure as $dir => $exts) { if (in_array($ext, $exts)) { rename($tempDir . '/' . $file, $tempDir . '/' . $dir . '/' . $file); $moved = true; break; } } // Optional: Handle uncategorized files by moving to a "misc" folder if (!$moved) { $miscDir = $tempDir . '/misc'; if (!is_dir($miscDir)) mkdir($miscDir, 0777, true); rename($tempDir . '/' . $file, $miscDir . '/' . $file); } }
Finally, we'll upload the reorganized directory to the target FTP server using another recursive function:
function uploadFtpDirectory($ftpConn, $localDir, $remoteDir) { // Create remote directory if it doesn't exist if (!@ftp_chdir($ftpConn, $remoteDir)) { ftp_mkdir($ftpConn, $remoteDir); ftp_chdir($ftpConn, $remoteDir); } $items = scandir($localDir); foreach ($items as $item) { if (in_array($item, ['.', '..'])) continue; $localPath = $localDir . '/' . $item; $remotePath = $remoteDir . '/' . $item; if (is_dir($localPath)) { uploadFtpDirectory($ftpConn, $localPath, $remotePath); } else { ftp_put($ftpConn, $remotePath, $localPath, FTP_BINARY); } } } // Upload to target FTP's destination folder (adjust path as needed) $targetRemoteRoot = '/path/to/target/folder'; uploadFtpDirectory($targetFtpConn, $tempDir, $targetRemoteRoot);
Don't forget to clean up the temporary directory and close FTP connections to free up resources:
// Close FTP connections ftp_close($ftp1Conn); ftp_close($targetFtpConn); // Delete temporary directory and all contents function deleteDirectory($dir) { $items = scandir($dir); foreach ($items as $item) { if (in_array($item, ['.', '..'])) continue; $path = $dir . '/' . $item; is_dir($path) ? deleteDirectory($path) : unlink($path); } rmdir($dir); } deleteDirectory($tempDir);
Key Notes for Production Use
- Timeout Settings: Increase FTP timeout for large files with
ftp_set_option($ftpConn, FTP_TIMEOUT_SEC, 300); - Error Handling: Add
try/catchblocks and check return values of all FTP/file functions to log errors properly - Memory & Disk Space: Ensure your server has enough disk space to handle the largest 4GB folder
- Filename Encoding: Use
ftp_raw($ftpConn, 'OPTS UTF8 ON');if your FTP servers use UTF-8 filenames to avoid garbled text - Performance: For extremely large folders, consider processing files in batches to avoid overwhelming the server
内容的提问来源于stack exchange,提问作者Atnaize

