文件上傳是 Web 開發高頻需求,主要分為兩類實現路徑:標準表單上傳(適合大文件、批量)與 Base64 編碼異步上傳(適合圖片預覽、壓縮)。本文將詳細拆解兩種方案的前後端協作細節。
此為最通用、瀏覽器原生支援的方式,適用於任意類型、大體積文件,天然支援多文件批量上傳。
<form enctype="multipart/form-data" method="post" action="upload.php">
<input type="file" name="id_pic[]" accept="image/*" class="form-control" multiple />
<input type="submit" value="上傳" />
</form>
enctype="multipart/form-data":必須,否則文件二進制數據不會發送。accept="image/*":限制文件選擇框優先顯示圖片(MIME 類型過濾)。multiple:允許一次選擇多個文件。name="id_pic[]":陣列命名法,PHP 端將接收到結構化陣列。capture="camera" 直接喚起攝像頭。同 name (陣列模式) name="id_pic[]":
array(1) {
["id_pic"]=> array(5) {
["name"]=> array(2) { [0]=> "1.jpg", [1]=> "2.jpg" }
["type"]=> array(2) { [0]=> "image/jpeg", [1]=> "image/jpeg" }
["tmp_name"]=> array(2) { [0]=> "C:\Windows\Temp\php7A7E.tmp", ... }
["error"]=> array(2) { [0]=> 0, [1]=> 0 }
["size"]=> array(2) { [0]=> 77357, [1]=> 56720 }
}
}
不同 name (獨立模式) name="id_pic_1", name="id_pic_2":
array(2) {
["id_pic_1"]=> array(5) { ["name"]=> "1.jpg", ["type"]=> "image/jpeg", ... }
["id_pic_2"]=> array(5) { ["name"]=> "2.jpg", ["type"]=> "image/jpeg", ... }
}
獨立模式遍歷更方便。建議編寫統一轉換函數 dealFiles() 將陣列模式轉為統一的列表結構:
function dealFiles($files) {
$fileArray = []; $n = 0;
foreach ($files as $key => $file) {
if (is_array($file['name'])) {
$keys = array_keys($file);
$count = count($file['name']);
for ($i = 0; $i < $count; $i++) {
$fileArray[$n]['key'] = $key;
foreach ($keys as $_key) {
$fileArray[$n][$_key] = $file[$_key][$i];
}
$n++;
}
} else {
$fileArray = $files; break;
}
}
return $fileArray;
}
$_FILES['size'] 與 php.ini 的 upload_max_filesize、表單隱藏域 MAX_FILE_SIZE。is_writable())。move_uploaded_file($tmp_name, $destination) 移動臨時文件。移動前可用 is_uploaded_file() 驗證合法性。多文件循環調用。利用 input 的 change 事件,配合 Canvas 壓縮圖片,再以 toDataURL() 生成 Base64 字串,經 AJAX POST 發送至後端。
FileReader 讀取文件 → Image 載入 → Canvas.drawImage() 繪製/壓縮。canvas.toDataURL('image/jpeg', quality) 輸出 Base64 Data URI(含 data:image/jpeg;base64, 前綴)。base64Len 供後端驗證完整性)。<?php
// 接收純 Base64 字串(需去除 data URI 前綴)
$base64 = $_POST['img'];
if (strpos($base64, ',') !== false) {
$base64 = substr($base64, strpos($base64, ',') + 1);
}
$binary = base64_decode($base64);
// 方式一:直接存檔
file_put_contents('upload/xxx.jpg', $binary);
// 方式二:GD 庫進一步處理
$img = imagecreatefromstring($binary);
// ... 處理後 imagejpeg($img, 'path');
?>
| 場景 | 推薦方案 | 理由 |
|---|---|---|
| 大文件、視頻、文檔、批量上傳 | 標準表單 | 流式傳輸,不佔用記憶體編碼開銷,瀏覽器原生支援斷點續傳插件 |
| 頭像、圖片編輯、即時預覽、客戶端壓縮 | Base64 + Canvas | 可在上傳前預覽、裁剪、壓縮,減少頻寬;適合移動端弱網環境 |