檔案上傳是 Web 開發核心功能。PHP 內建支援讓上傳處理輕鬆簡單,本文詳細說明表單構造、$_FILES 陣列結構、錯誤碼對照與安全搬移流程。
<form enctype="multipart/form-data" action="upload.php" method="post">
<input type="hidden" name="MAX_FILE_SIZE" value="1000000"> <!-- 1MB 限制,僅建議值 -->
<input name="myFile" type="file">
<input type="submit" value="上傳檔案">
</form>
enctype="multipart/form-data" 必須設定。MAX_FILE_SIZE 必須置於 <input type="file"> 之前,單位為 Bytes,僅為瀏覽器端建議,伺服器仍需驗證。| 鍵名 | 說明 |
|---|---|
$_FILES['myFile']['name'] | 用戶端原始檔名 |
['type'] | MIME 類型(瀏覽器提供,不可全信) |
['size'] | 檔案大小(Bytes) |
['tmp_name'] | 伺服器暫存路徑(upload_tmp_dir 設定) |
['error'] | 錯誤代碼(PHP 4.2.0+) |
| 常數 | 值 | 含義 |
|---|---|---|
| UPLOAD_ERR_OK | 0 | 上傳成功 |
| UPLOAD_ERR_INI_SIZE | 1 | 超過 php.ini upload_max_filesize |
| UPLOAD_ERR_FORM_SIZE | 2 | 超過表單 MAX_FILE_SIZE |
| UPLOAD_ERR_PARTIAL | 3 | 僅部分上傳 |
| UPLOAD_ERR_NO_FILE | 4 | 未選擇檔案 |
| UPLOAD_ERR_ZERO_SIZE | 5 | 檔案大小為 0 |
| UPLOAD_ERR_NO_TMP_DIR | 6 | 缺少暫存目錄 |
| UPLOAD_ERR_CANT_WRITE | 7 | 寫入磁碟失敗 |
| UPLOAD_ERR_EXTENSION | 8 | 被 PHP 擴展阻擋 |
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$file = $_FILES['myFile'] ?? null;
if (!$file || $file['error'] !== UPLOAD_ERR_OK) {
die("上傳失敗,錯誤碼: " . ($file['error'] ?? 'unknown'));
}
// 1. 驗證檔案類型(建議用 finfo 而非 $_FILES['type'])
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($file['tmp_name']);
$allowed = ['image/jpeg', 'image/png', 'application/pdf'];
if (!in_array($mime, $allowed, true)) {
die("不允許的檔案類型: {$mime}");
}
// 2. 驗證大小
if ($file['size'] > 2 * 1024 * 1024) { // 2MB
die("檔案過大");
}
// 3. 產生安全檔名並移動
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
$newName = bin2hex(random_bytes(16)) . '.' . $ext;
$dest = "/var/www/uploads/{$newName}";
if (!move_uploaded_file($file['tmp_name'], $dest)) {
die("檔案儲存失敗");
}
echo "上傳成功: {$dest}";
}
?>
php.ini:file_uploads=On, upload_max_filesize, post_max_size, upload_tmp_dir。www-data 可寫,且禁止腳本執行權限(Nginx/Apache 設定)。遵循「驗證類型、限制大小、隨機命名、隔離儲存」四原則,即能構建安全可靠的上傳功能。