求文件下载与合并脚本及基于现有PHP脚本的分块下载方案
Got it, let's revamp your basic download script to support chunked (resumable) downloads—perfect for large files where users might lose connection mid-transfer and need to pick up where they left off. Here's how to do it, with clear breakdowns of key changes:
Key Concepts for Resumable Downloads
Resumable downloads rely on the HTTP Range header: the client tells the server which part of the file it wants, and the server responds with a 206 Partial Content status code plus the requested chunk. We'll build this logic alongside your existing POST trigger.
Modified Script with Chunk Support
<?php // Handle both POST (your original trigger) and GET (for chunked download requests) if (isset($_POST['downloadButton']) || isset($_GET['filename'])) { $filename = isset($_POST["filename"]) ? $_POST["filename"] : $_GET["filename"]; if (!file_exists($filename)) { http_response_code(404); echo "File not found"; exit; } $fileSize = filesize($filename); $file = fopen($filename, 'rb'); // Initialize range boundaries $start = 0; $end = $fileSize - 1; // Parse and validate Range header if present if (isset($_SERVER['HTTP_RANGE'])) { preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches); $start = intval($matches[1]); // Set end to file end if not specified in the request $end = !empty($matches[2]) ? intval($matches[2]) : $fileSize - 1; // Reject invalid range requests if ($start > $end || $start >= $fileSize || $end >= $fileSize) { http_response_code(416); // Requested Range Not Satisfiable header("Content-Range: bytes */$fileSize"); exit; } } $chunkSize = $end - $start + 1; // Set critical response headers header("Content-Type: application/octet-stream"); header("Content-Disposition: attachment; filename=\"" . basename($filename) . "\""); header("Content-Length: $chunkSize"); header("Accept-Ranges: bytes"); // Tell clients resuming is supported // Send appropriate status code if (isset($_SERVER['HTTP_RANGE'])) { http_response_code(206); // Partial Content for chunked requests header("Content-Range: bytes $start-$end/$fileSize"); } else { http_response_code(200); // OK for full file downloads } // Stream the requested chunk efficiently fseek($file, $start); while (!feof($file) && ($currentPos = ftell($file)) <= $end) { // Read in 1MB chunks to avoid memory overload with large files $readChunkSize = min(1024 * 1024, $end - $currentPos + 1); echo fread($file, $readChunkSize); flush(); // Push content to the client immediately } fclose($file); exit; } ?>
What Changed & Why
- Dual Request Support: Now works with your original POST button trigger and GET requests (most download managers use GET for resumable transfers)
- Range Header Handling: Parses client-requested file ranges, validates them, and adjusts output to match
- Proper Status Codes: Returns
206 Partial Contentfor chunks,404for missing files, and416for invalid range requests - Memory Efficiency: Reads and outputs the file in 1MB chunks instead of loading the entire file into memory (critical for large files)
- Resumable Headers: Includes
Accept-Rangesto signal support for resuming, andContent-Rangeto specify which chunk is being sent
Testing the Script
You can test chunked downloads manually with curl:
# Download the first 1MB of the file curl -r 0-1048575 http://your-domain.com/your-script.php?filename=your-large-file.zip -o chunk1.part # Download the next 1MB curl -r 1048576-2097151 http://your-domain.com/your-script.php?filename=your-large-file.zip -o chunk2.part # Combine chunks (Linux/macOS) cat chunk1.part chunk2.part > full-file.zip
Most modern browsers and download managers will automatically use resumable downloads if the server supports it—no extra client-side setup needed!
内容的提问来源于stack exchange,提问作者mohsen hasani

