1. 上傳表單 upload.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>檔案上傳</title>
</head>
<body>
<form action="uploadProcess.php" method="post" enctype="multipart/form-data">
<table>
<tr><td>用戶名</td><td><input type="text" name="username" required></td></tr>
<tr><td>檔案說明</td><td><textarea name="fileintro" rows="5" cols="40"></textarea></td></tr>
<tr><td>選擇檔案</td><td><input type="file" name="myfile" required></td></tr>
<tr><td colspan="2"><input type="submit" value="上傳"></td></tr>
</table>
</form>
</body>
</html>
2. 處理邏輯 uploadProcess.php
<?php
$username = $_POST['username'] ?? '';
$fileintro = $_POST['fileintro'] ?? '';
// 檔案資訊
$file = $_FILES['myfile'] ?? null;
if (!$file || $file['error'] !== UPLOAD_ERR_OK) {
die('上傳失敗或無檔案');
}
// 限制大小 2MB
if ($file['size'] > 2 * 1024 * 1024) {
die('檔案不得超過 2MB');
}
// 限制類型(示例僅允許 JPEG)
$allowedTypes = ['image/jpeg', 'image/pjpeg'];
if (!in_array($file['type'], $allowedTypes)) {
die('僅允許 JPG 格式');
}
// 使用者專屬目錄
$userDir = $_SERVER['DOCUMENT_ROOT'] . '/file/up/' . $username;
if (!is_dir($userDir)) mkdir($userDir, 0755, true);
// 防重名:時間戳 + 隨機數 + 原副檔名
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
$newName = time() . '_' . mt_rand(1, 1000) . '.' . $ext;
$dest = $userDir . '/' . $newName;
// 移動檔案(中文檔名編碼轉換視伺服器環境)
if (move_uploaded_file($file['tmp_name'], $dest)) {
echo $file['name'] . ' 上傳成功';
} else {
echo '上傳失敗';
}
?>
3. 物件導向封裝 Upload.php
<?php
class Upload {
public $uploadName;
public $tmpPath;
public $fileSize;
public $fileType;
public $saveRoot;
public $allowedExt = ['jpeg','jpg','png','gif','bmp','doc','zip','rar','txt','wps','xlsx','ppt'];
public $maxSize = 2 * 1024 * 1024;
public function __construct($inputName = 'myfile') {
$f = $_FILES[$inputName] ?? null;
if (!$f || $f['error'] !== UPLOAD_ERR_OK) throw new Exception('無效上傳');
$this->uploadName = $f['name'];
$this->tmpPath = $f['tmp_name'];
$this->fileSize = $f['size'];
$this->fileType = $f['type'];
$this->saveRoot = $_SERVER['DOCUMENT_ROOT'] . '/file/up/';
}
public function upload($username) {
// 大小檢查
if ($this->fileSize > $this->maxSize) throw new Exception('檔案過大');
// 副檔名檢查
$ext = $this->getExt($this->uploadName);
if (!in_array(strtolower($ext), $this->allowedExt)) throw new Exception('副檔名不允許');
// 使用者目錄
$userDir = $this->saveRoot . $username;
if (!is_dir($userDir)) mkdir($userDir, 0755, true);
// 目的檔名
$dest = $userDir . '/' . time() . '_' . mt_rand(1, 1000) . '.' . $ext;
// 移動
if (!move_uploaded_file($this->tmpPath, $dest)) throw new Exception('移動失敗');
return $dest;
}
private function getExt($filename) {
return pathinfo($filename, PATHINFO_EXTENSION);
}
}
// 使用範例
try {
$uploader = new Upload();
$path = $uploader->upload($_POST['username']);
echo '上傳成功:' . $path;
} catch (Exception $e) {
echo '錯誤:' . $e->getMessage();
}
?>
安全防護清單
- ✅ 檢查
$_FILES['error'] === UPLOAD_ERR_OK
- ✅ 限制副檔名白名單(勿信任
type,易偽造)
- ✅ 限制檔案大小
- ✅ 重新命名(避免覆蓋、路徑遍歷、腳本執行)
- ✅ 儲存目錄設為不可執行(Nginx/Apache 禁用 PHP 解析)
- ✅ 圖片類可用
getimagesize() 二次驗證
- ✅ 上傳後掃毒(ClamAV 等)
- ✅ 記錄日誌:用戶、原始檔名、儲存路徑、IP、時間