在 XMLHttpRequest Level 2 支援 FormData 之前,主流做法是利用 `
XMLHttpRequest Level 2
FormData
fetch
axios
upload.php
<?php function uploadFile($file) { $dest = __DIR__ . '/uploads/'; if (!is_dir($dest)) mkdir($dest, 0755, true); // 安全檢查:副檔名、MIME、大小 $allowed = ['jpg','jpeg','png','gif','pdf']; $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); if (!in_array($ext, $allowed)) return ['error' => '副檔名不允許']; if ($file['size'] > 5 * 1024 * 1024) return ['error' => '超過 5MB']; $newName = date('YmdHis') . '_' . bin2hex(random_bytes(8)) . '.' . $ext; if (move_uploaded_file($file['tmp_name'], $dest . $newName)) { return ['success' => true, 'filename' => $newName, 'path' => $dest . $newName]; } return ['error' => '移動檔案失敗']; } $result = uploadFile($_FILES['myfile'] ?? []); // 輸出 JS 呼叫父頁面 callback echo '<script>window.parent.stopUpload(' . json_encode($result) . ');</script>'; ?>
<form id="upForm" action="upload.php" method="post" enctype="multipart/form-data" target="upload_target"> <input type="file" name="myfile" id="myfile" required> <button type="submit">上傳</button> </form> <iframe id="upload_target" name="upload_target" style="display:none;"></iframe> <div id="msg">待上傳</div> <script> function stopUpload(res) { const msg = document.getElementById('msg'); if (res.success) { msg.innerHTML = `成功:${res.filename}`; // 可進一步顯示縮圖、存入隱藏欄位供表單二次送出 } else { msg.innerHTML = `失敗:${res.error}`; } } </script>
finfo_file
// 前端原生 fetch const formData = new FormData(); formData.append('myfile', fileInput.files[0]); fetch('upload.php', { method: 'POST', body: formData }) .then(r => r.json()) .then(res => { /* 處理結果 */ });
優點:無需 iframe、支援進度條 (xhr.upload.onprogress)、錯誤處理更清晰、可攔截取消。
xhr.upload.onprogress
iframe 上傳是歷史產物,理解其運作原理(表單導向、跨框架通訊)有助於閱讀舊碼。新專案請直接使用 FormData + fetch/axios,並搭配後端統一回傳 JSON 格式。
fetch/axios
微信公眾號被動回覆訊息總覽 收到使用者訊息後,需在 5 秒內
PHP 實現冒泡排序:算法原理、代碼實現、性能分析與優化替代
問題現象 使用 Symfony 框架開發手機 App 後台,
場景痛點 專案需將多個文字檔打包為 ZIP 提供下載。生產環