form.html — 上傳表單頁面upload.php — 上傳處理邏輯check.php — 核心工具函數(擴展名獲取、隨機命名)<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>圖片上傳</title>
</head>
<body>
<form method="post" action="upload.php" enctype="multipart/form-data">
<input type="hidden" name="MAX_FILE_SIZE" value="2000000">
<input type="file" name="file" accept="image/*">
<input type="submit" value="上傳" name="submit">
</form>
</body>
</html>
關鍵點:enctype="multipart/form-data" 必須設置,MAX_FILE_SIZE 僅作客戶端提示,服務端必須再次校驗。
<?php
// check.php
header("Content-Type: text/html; charset=utf-8");
/**
* 獲取文件擴展名(推薦 pathinfo)
*/
function getExtension(string $filename): string {
return strtolower(pathinfo($filename, PATHINFO_EXTENSION));
}
/**
* 生成隨機文件名
* @param int $length 隨機部分長度
* @param string $prefix 前綴
*/
function generateRandomName(int $length = 16, string $prefix = ''): string {
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$name = $prefix;
for ($i = 0; $i < $length; $i++) {
$name .= $chars[random_int(0, strlen($chars) - 1)];
}
return $name;
}
/**
* 完整上傳處理流程
* @return array ['success'=>bool, 'message'=>string, 'path'=>string|null]
*/
function handleUpload(array $file, array $allowedExts, string $uploadDir): array {
// 1. 基礎檢查
if ($file['error'] !== UPLOAD_ERR_OK) {
return ['success' => false, 'message' => '上傳錯誤碼: ' . $file['error']];
}
// 2. 文件大小限制(2MB)
if ($file['size'] > 2 * 1024 * 1024) {
return ['success' => false, 'message' => '文件過大,限制 2MB'];
}
// 3. 擴展名驗證
$ext = getExtension($file['name']);
if (!in_array($ext, $allowedExts, true)) {
return ['success' => false, 'message' => '不允許的文件類型'];
}
// 4. MIME 類型驗證(防偽裝)
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file['tmp_name']);
$allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (!in_array($mime, $allowedMimes, true)) {
return ['success' => false, 'message' => '文件內容類型不合法'];
}
// 5. 目錄檢查
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
// 6. 生成唯一文件名
$newName = generateRandomName(20, 'img_') . '.' . $ext;
$destPath = $uploadDir . '/' . $newName;
// 7. 移動文件
if (!move_uploaded_file($file['tmp_name'], $destPath)) {
return ['success' => false, 'message' => '文件移動失敗'];
}
// 8. 設置權限(僅讀)
chmod($destPath, 0644);
return ['success' => true, 'message' => '上傳成功', 'path' => $destPath];
}
?>
<?php
// upload.php
require_once 'check.php';
$allowedExts = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
$uploadDir = __DIR__ . '/uploads';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
$result = handleUpload($_FILES['file'], $allowedExts, $uploadDir);
if ($result['success']) {
echo "<p style='color:green'>{$result['message']}</p>";
echo "<p>文件路徑: {$result['path']}</p>";
echo "<img src='{$result['path']}' style='max-width:300px'>";
} else {
echo "<p style='color:red'>錯誤: {$result['message']}</p>";
}
echo '<p><a href="form.html">返回繼續上傳</a></p>';
exit;
}
header('Location: form.html');
<?php
// upload_all_in_one.php
header("Content-Type: text/html; charset=utf-8");
function getExtension(string $filename): string {
return strtolower(pathinfo($filename, PATHINFO_EXTENSION));
}
function generateRandomName(int $length = 16): string {
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$name = '';
for ($i = 0; $i < $length; $i++) {
$name .= $chars[random_int(0, strlen($chars) - 1)];
}
return $name;
}
$allowedExts = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
$uploadDir = __DIR__ . '/uploads';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
$file = $_FILES['file'];
if ($file['error'] !== UPLOAD_ERR_OK) die('上傳失敗: ' . $file['error']);
if ($file['size'] > 2 * 1024 * 1024) die('文件過大');
$ext = getExtension($file['name']);
if (!in_array($ext, $allowedExts)) die('類型不允許');
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file['tmp_name']);
if (!in_array($mime, ['image/jpeg','image/png','image/gif','image/webp'])) die('內容類型非法');
if (!is_dir($uploadDir)) mkdir($uploadDir, 0755, true);
$newName = generateRandomName(20) . '.' . $ext;
$dest = $uploadDir . '/' . $newName;
if (move_uploaded_file($file['tmp_name'], $dest)) {
chmod($dest, 0644);
echo "上傳成功!<br><img src='$dest' style='max-width:300px'>";
} else {
echo '移動失敗';
}
exit;
}
?>
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>上傳</title></head><body>
<form method="post" enctype="multipart/form-data">
<input type="file" name="file" accept="image/*">
<input type="submit" value="上傳">
</form></body></html>
location ~ \.php$ { deny all; } 或 Apache SetHandler default-handlerupload_max_filesize + 代碼邏輯判斷display_errors,記錄日志