file_uploads = On
upload_tmp_dir = /tmp/php_uploads ; 必須存在且 PHP 進程可寫
upload_max_filesize = 10M ; 單檔上限
post_max_size = 12M ; 必須 > upload_max_filesize
max_execution_time = 300 ; 大檔需增加執行時間
max_input_time = 300 ; 解析輸入時間
注意:修改後必須重啟 PHP 服務。
<form action="upload.php" method="POST" enctype="multipart/form-data">
<input type="file" name="userfile" />
<input type="submit" value="上傳" />
</form>
關鍵點:enctype="multipart/form-data"、method="POST"。
<?php
function uploadFile($inputName, $destDir = '../uploads/', $allowedTypes = [], $maxSize = 0)
{
// 1. 檢查是否有檔案上傳
if (empty($_FILES[$inputName]['name']) || $_FILES[$inputName]['error'] !== UPLOAD_ERR_OK) {
return ['success' => false, 'msg' => '無檔案或上傳錯誤'];
}
$file = $_FILES[$inputName];
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
// 2. 類型驗證
if (!empty($allowedTypes) && !in_array($ext, $allowedTypes)) {
return ['success' => false, 'msg' => '檔案類型不允許'];
}
// 3. 大小驗證
if ($maxSize > 0 && $file['size'] > $maxSize) {
return ['success' => false, 'msg' => '檔案大小超過限制'];
}
// 4. 目錄檢查
$destDir = rtrim($destDir, '/') . '/';
if (!is_dir($destDir) || !is_writable($destDir)) {
return ['success' => false, 'msg' => '上傳目錄不存在或不可寫'];
}
// 5. 產生唯一檔名 (避免覆蓋)
$fileName = date('YmdHis') . '_' . bin2hex(random_bytes(8)) . '.' . $ext;
$destPath = $destDir . $fileName;
// 6. 移動暫存檔 (安全: 驗證是真正上傳檔案)
if (!move_uploaded_file($file['tmp_name'], $destPath)) {
return ['success' => false, 'msg' => '檔案移動失敗'];
}
// 7. 設定權限 (視需求)
@chmod($destPath, 0644);
return ['success' => true, 'filename' => $fileName, 'path' => $destPath];
}
// 使用範例
$result = uploadFile('userfile', '../data/agency/', ['jpg','png','gif','pdf'], 2*1024*1024);
if ($result['success']) {
echo "上傳成功:" . $result['filename'];
} else {
echo "失敗:" . $result['msg'];
}
?>
<input type="file" name="userfile[]" multiple />
<input type="file" name="userfile[]" />
<input type="file" name="userfile[]" />
<input type="file" name="userfile[]" />
<?php
// $_FILES['userfile']['name'] 變成陣列
$fileCount = count($_FILES['userfile']['name']);
for ($i = 0; $i < $fileCount; $i++) {
$singleFile = [
'name' => $_FILES['userfile']['name'][$i],
'type' => $_FILES['userfile']['type'][$i],
'tmp_name' => $_FILES['userfile']['tmp_name'][$i],
'error' => $_FILES['userfile']['error'][$i],
'size' => $_FILES['userfile']['size'][$i],
];
// 呼叫單檔處理邏輯...
}
?>
| 代碼 | 常數 | 說明 |
|---|---|---|
| 0 | UPLOAD_ERR_OK | 成功 |
| 1 | UPLOAD_ERR_INI_SIZE | 超過 php.ini upload_max_filesize |
| 2 | UPLOAD_ERR_FORM_SIZE | 超過表單 MAX_FILE_SIZE |
| 3 | UPLOAD_ERR_PARTIAL | 部分上傳 |
| 4 | UPLOAD_ERR_NO_FILE | 未選擇檔案 |
| 6 | UPLOAD_ERR_NO_TMP_DIR | 缺少暫存目錄 |
| 7 | UPLOAD_ERR_CANT_WRITE | 寫入磁碟失敗 |
| 8 | UPLOAD_ERR_EXTENSION | PHP 擴充模組中斷上傳 |
$_FILES['type'],使用 finfo_file() 檢測真實 MIME。.php, .phtml, .php5, .phar, .htaccess 等可執行副檔名。memory_limit、max_execution_time、nginx client_max_body_size。檔案上傳看似簡單,實則涉及環境設定、輸入驗證、安全防護、錯誤處理多個層面。建立可復用的上傳元件,並嚴格遵循「不信任客戶端資料」原則,是打造穩健系統的關鍵。