如何将FormData中附加的Blob发送至PHP?附大文件上传内存优化需求
Hey there, let's tackle this memory issue step by step. Your hunch about switching from DataURI to Blob + FormData is spot-on—let's start with that solution, then cover other strategies to keep your 1GB AWS server memory in check.
DataURI is a major culprit here: it encodes binary data into a base64 string that’s 33% larger than the original file, and forces both the browser and server to load the entire inflated string into memory. Blob + FormData sends raw binary data directly, avoiding that bloat and memory overhead.
Frontend Code (JavaScript)
You don’t even need to explicitly convert to Blob—file inputs return File objects, which are a subclass of Blob:
// Grab the file from your upload input const fileInput = document.getElementById("image-upload"); const selectedFile = fileInput.files[0]; if (selectedFile) { const formData = new FormData(); // Attach the file directly (no DataURI conversion needed) formData.append("uploaded_image", selectedFile, selectedFile.name); // Send to your PHP backend fetch("/upload.php", { method: "POST", body: formData }) .then(res => res.json()) .then(data => console.log("Upload successful:", data)) .catch(err => console.error("Upload failed:", err)); }
PHP Backend Code
PHP handles FormData uploads by streaming the file to a temporary disk location (not holding it all in memory by default). Just move it to your target directory:
<?php // Configure your upload directory $uploadDir = "./uploads/"; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0755, true); } if (isset($_FILES["uploaded_image"])) { $uploadedFile = $_FILES["uploaded_image"]; $targetPath = $uploadDir . basename($uploadedFile["name"]); // Move the temporary file to your storage (low memory footprint) if (move_uploaded_file($uploadedFile["tmp_name"], $targetPath)) { echo json_encode(["status" => "success", "file_path" => $targetPath]); } else { echo json_encode(["status" => "error", "message" => "Failed to save file"]); } } else { echo json_encode(["status" => "error", "message" => "No file uploaded"]); } ?>
Even with Blob/FormData, here are more ways to prevent memory spikes for large images:
- Chunked (Resumable) Uploads
Split large files into smaller chunks (e.g., 5MB each) and upload them sequentially. This way, only one small chunk is loaded into memory at a time. UseFile.slice()on the frontend to split the file, then add logic on your PHP backend to reassemble chunks once all are uploaded:
const chunkSize = 5 * 1024 * 1024; // 5MB per chunk let startByte = 0; const file = fileInput.files[0]; function uploadNextChunk() { const endByte = Math.min(startByte + chunkSize, file.size); const chunk = file.slice(startByte, endByte); const formData = new FormData(); formData.append("chunk", chunk); formData.append("filename", file.name); formData.append("start", startByte); formData.append("total_size", file.size); fetch("/upload-chunk.php", { method: "POST", body: formData }) .then(res => res.json()) .then(data => { if (data.success) { startByte = endByte; if (startByte < file.size) uploadNextChunk(); else fetch("/merge-chunks.php", { method: "POST", body: JSON.stringify({ filename: file.name }), headers: { "Content-Type": "application/json" } }); } }); } uploadNextChunk();
- Client-Side Image Compression
Shrink the file size before uploading using the browser’s canvas API. This reduces both upload time and server memory load:
function compressImage(file, maxWidth = 1920, quality = 0.8) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => { const img = new Image(); img.onload = () => { const canvas = document.createElement("canvas"); let [width, height] = [img.width, img.height]; // Scale down if image is too wide if (width > maxWidth) { height = (maxWidth / width) * height; width = maxWidth; } canvas.width = width; canvas.height = height; const ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, width, height); // Convert canvas back to a Blob canvas.toBlob((compressedBlob) => { resolve(new File([compressedBlob], file.name, { type: file.type })); }, file.type, quality); }; img.src = e.target.result; }; reader.onerror = reject; reader.readAsDataURL(file); }); } // Usage: compress before uploading compressImage(selectedFile).then(compressedFile => { const formData = new FormData(); formData.append("uploaded_image", compressedFile); // Send formData to server... });
Tweak PHP Server Configurations
Adjust these values in yourphp.inito align with your server’s 1GB memory limit:upload_max_filesize: Set to your expected maximum file size (e.g.,64M)post_max_size: Should be slightly larger thanupload_max_filesize(e.g.,70M)memory_limit: Set to a safe value that leaves room for system processes (e.g.,800M—avoid using the full 1GB)- Ensure PHP’s temporary file directory is on disk (not a memory filesystem) to prevent in-memory buffering.
Stream Processing on the Server
If you need to manipulate the image (crop, resize, etc.), avoid loading the entire file into memory. Use PHP’s stream functions (fopen(),fread()) with libraries like GD or Intervention Image that support streaming input/output.
To recap: DataURI converts binary image data into a base64 string that’s 33% larger than the original. When uploading, your browser loads this full string into memory, then sends it to the server—where PHP has to decode it back to binary, doubling the memory footprint for the file. Blob/FormData skips this entire encoding/decoding step, keeping memory usage low.
内容的提问来源于stack exchange,提问作者Satyam Pathak

