Appearance
13.3 上传验证(大小、类型、重命名)
文件上传验证是确保上传文件安全和符合要求的重要步骤。本章节将介绍如何验证上传文件的大小、类型,并实现文件重命名功能。
验证文件大小
1. 服务器端验证
php
// 限制文件大小为 5MB
$maxFileSize = 5 * 1024 * 1024; // 5MB
if ($_FILES['fileToUpload']['size'] > $maxFileSize) {
$error = "文件太大,最大允许 5MB";
}2. 客户端验证
html
<!-- HTML5 文件大小验证 -->
<input type="file" name="fileToUpload" accept="image/*" onchange="validateFileSize(this);">
<script>
function validateFileSize(input) {
const maxSize = 5 * 1024 * 1024; // 5MB
if (input.files && input.files[0]) {
if (input.files[0].size > maxSize) {
alert('文件太大,最大允许 5MB');
input.value = '';
}
}
}
</script>3. 配置文件限制
在 php.ini 文件中设置:
ini
upload_max_filesize = 5M
post_max_size = 10M验证文件类型
1. 通过 MIME 类型验证
php
// 允许的 MIME 类型
$allowedMimeTypes = [
'image/jpeg',
'image/png',
'image/gif',
'image/webp'
];
if (!in_array($_FILES['fileToUpload']['type'], $allowedMimeTypes)) {
$error = "只允许上传图片文件(JPG、PNG、GIF、WebP)";
}2. 通过文件扩展名验证
php
// 允许的文件扩展名
$allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
$fileExtension = strtolower(pathinfo($_FILES['fileToUpload']['name'], PATHINFO_EXTENSION));
if (!in_array($fileExtension, $allowedExtensions)) {
$error = "只允许上传图片文件(JPG、PNG、GIF、WebP)";
}3. 验证是否为真实图片
php
// 检查是否为真实图片
if (getimagesize($_FILES['fileToUpload']['tmp_name']) === false) {
$error = "请上传真实的图片文件";
}4. 客户端文件类型验证
html
<!-- 只允许图片文件 -->
<input type="file" name="fileToUpload" accept="image/*">
<!-- 只允许特定类型 -->
<input type="file" name="fileToUpload" accept=".jpg,.jpeg,.png,.gif">文件重命名
1. 使用唯一 ID 重命名
php
$targetDir = "uploads/";
$fileExtension = strtolower(pathinfo($_FILES['fileToUpload']['name'], PATHINFO_EXTENSION));
$newFileName = uniqid() . '.' . $fileExtension;
$targetFile = $targetDir . $newFileName;
if (move_uploaded_file($_FILES['fileToUpload']['tmp_name'], $targetFile)) {
echo "文件上传成功,新文件名: " . $newFileName;
}2. 使用时间戳重命名
php
$targetDir = "uploads/";
$fileExtension = strtolower(pathinfo($_FILES['fileToUpload']['name'], PATHINFO_EXTENSION));
$newFileName = time() . '_' . mt_rand(1000, 9999) . '.' . $fileExtension;
$targetFile = $targetDir . $newFileName;
if (move_uploaded_file($_FILES['fileToUpload']['tmp_name'], $targetFile)) {
echo "文件上传成功,新文件名: " . $newFileName;
}3. 保留原始文件名但避免冲突
php
$targetDir = "uploads/";
$originalFileName = basename($_FILES['fileToUpload']['name']);
$fileExtension = strtolower(pathinfo($originalFileName, PATHINFO_EXTENSION));
$fileNameWithoutExt = pathinfo($originalFileName, PATHINFO_FILENAME);
$targetFile = $targetDir . $originalFileName;
$counter = 1;
// 避免文件名冲突
while (file_exists($targetFile)) {
$newFileName = $fileNameWithoutExt . '_' . $counter . '.' . $fileExtension;
$targetFile = $targetDir . $newFileName;
$counter++;
}
if (move_uploaded_file($_FILES['fileToUpload']['tmp_name'], $targetFile)) {
echo "文件上传成功,文件���: " . basename($targetFile);
}完整的上传验证示例
php
<?php
$targetDir = "uploads/";
$maxFileSize = 5 * 1024 * 1024; // 5MB
$allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
$errors = [];
// 确保上传目录存在
if (!is_dir($targetDir)) {
mkdir($targetDir, 0755, true);
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['fileToUpload'])) {
$file = $_FILES['fileToUpload'];
// 检查是否有错误
if ($file['error'] !== 0) {
switch ($file['error']) {
case UPLOAD_ERR_INI_SIZE:
$errors[] = '文件大小超过了 php.ini 限制';
break;
case UPLOAD_ERR_FORM_SIZE:
$errors[] = '文件大小超过了表单限制';
break;
case UPLOAD_ERR_PARTIAL:
$errors[] = '文件只有部分被上传';
break;
case UPLOAD_ERR_NO_FILE:
$errors[] = '没有文件被上传';
break;
case UPLOAD_ERR_NO_TMP_DIR:
$errors[] = '找不到临时文件夹';
break;
case UPLOAD_ERR_CANT_WRITE:
$errors[] = '文件写入失败';
break;
case UPLOAD_ERR_EXTENSION:
$errors[] = '文件上传被 PHP 扩展中断';
break;
default:
$errors[] = '上传失败,未知错误';
}
} else {
// 检查文件大小
if ($file['size'] > $maxFileSize) {
$errors[] = "文件太大,最大允许 5MB";
}
// 检查文件扩展名
$fileExtension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($fileExtension, $allowedExtensions)) {
$errors[] = "只允许上传图片文件(JPG、PNG、GIF、WebP)";
}
// 检查是否为真实图片
if (getimagesize($file['tmp_name']) === false) {
$errors[] = "请上传真实的图片文件";
}
// 处理上传
if (empty($errors)) {
// 重命名文件
$newFileName = uniqid() . '.' . $fileExtension;
$targetFile = $targetDir . $newFileName;
if (move_uploaded_file($file['tmp_name'], $targetFile)) {
$success = "文件上传成功!<br>文件名: " . $newFileName . "<br>大小: " . round($file['size'] / 1024, 2) . " KB";
} else {
$errors[] = "上传失败,请重试";
}
}
}
}
?>
<!DOCTYPE html>
<html>
<head>
<title>文件上传验证</title>
<style>
body { font-family: Arial, sans-serif; max-width: 500px; margin: 0 auto; padding: 20px; }
h1 { text-align: center; color: #333; }
.form-group { margin: 15px 0; }
label { display: block; margin-bottom: 5px; font-weight: bold; }
input[type="file"] { padding: 10px; border: 1px solid #ddd; border-radius: 4px; width: 100%; box-sizing: border-box; }
input[type="submit"] { padding: 10px 20px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; }
.message { padding: 10px; margin: 10px 0; border-radius: 4px; }
.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
</style>
</head>
<body>
<h1>文件上传验证</h1>
<?php if (!empty($errors)): ?>
<div class="message error">
<ul>
<?php foreach ($errors as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<?php if (isset($success)): ?>
<div class="message success">
<?php echo $success; ?>
</div>
<?php endif; ?>
<form action="" method="post" enctype="multipart/form-data">
<div class="form-group">
<label>选择图片: <input type="file" name="fileToUpload" accept="image/*"></label>
</div>
<input type="submit" value="上传文件" name="submit">
</form>
</body>
</html>多文件上传验证
php
<?php
$targetDir = "uploads/";
$maxFileSize = 5 * 1024 * 1024; // 5MB
$allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
$errors = [];
$successFiles = [];
// 确保上传目录存在
if (!is_dir($targetDir)) {
mkdir($targetDir, 0755, true);
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['files'])) {
$files = $_FILES['files'];
$fileCount = count($files['name']);
for ($i = 0; $i < $fileCount; $i++) {
$file = [
'name' => $files['name'][$i],
'type' => $files['type'][$i],
'tmp_name' => $files['tmp_name'][$i],
'error' => $files['error'][$i],
'size' => $files['size'][$i]
];
// 检查是否有错误
if ($file['error'] !== 0) {
$errors[] = "文件 " . $file['name'] . " 上传失败: 错误代码 " . $file['error'];
continue;
}
// 检查文件大小
if ($file['size'] > $maxFileSize) {
$errors[] = "文件 " . $file['name'] . " 太大,最大允许 5MB";
continue;
}
// 检查文件扩展名
$fileExtension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($fileExtension, $allowedExtensions)) {
$errors[] = "文件 " . $file['name'] . " 类型不允许,只允许图片文件";
continue;
}
// 检查是否为真实图片
if (getimagesize($file['tmp_name']) === false) {
$errors[] = "文件 " . $file['name'] . " 不是真实的图片文件";
continue;
}
// 重命名文件
$newFileName = uniqid() . '.' . $fileExtension;
$targetFile = $targetDir . $newFileName;
if (move_uploaded_file($file['tmp_name'], $targetFile)) {
$successFiles[] = [
'original' => $file['name'],
'new' => $newFileName,
'size' => round($file['size'] / 1024, 2)
];
} else {
$errors[] = "文件 " . $file['name'] . " 上传失败";
}
}
}
?>
<!DOCTYPE html>
<html>
<head>
<title>多文件上传验证</title>
<style>
body { font-family: Arial, sans-serif; max-width: 500px; margin: 0 auto; padding: 20px; }
h1 { text-align: center; color: #333; }
.form-group { margin: 15px 0; }
label { display: block; margin-bottom: 5px; font-weight: bold; }
input[type="file"] { padding: 10px; border: 1px solid #ddd; border-radius: 4px; width: 100%; box-sizing: border-box; }
input[type="submit"] { padding: 10px 20px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; }
.message { padding: 10px; margin: 10px 0; border-radius: 4px; }
.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
.file-list { margin: 10px 0; }
.file-item { padding: 5px; border-bottom: 1px solid #ddd; }
</style>
</head>
<body>
<h1>多文件上传验证</h1>
<?php if (!empty($errors)): ?>
<div class="message error">
<ul>
<?php foreach ($errors as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<?php if (!empty($successFiles)): ?>
<div class="message success">
<p>上传成功的文件:</p>
<div class="file-list">
<?php foreach ($successFiles as $file): ?>
<div class="file-item">
原始文件名: <?php echo $file['original']; ?><br>
新文件名: <?php echo $file['new']; ?><br>
大小: <?php echo $file['size']; ?> KB
</div>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
<form action="" method="post" enctype="multipart/form-data">
<div class="form-group">
<label>选择图片: <input type="file" name="files[]" multiple accept="image/*"></label>
</div>
<input type="submit" value="上传文件" name="submit">
</form>
</body>
</html>注意事项
安全性:
- 不要信任用户上传的文件,始终进行验证
- 不要将上传的文件直接存储在可执行目录
- 考虑使用安全的文件存储路径
性能:
- 限制上传文件的大小,避免服务器资源耗尽
- 对于大文件,考虑使用分片上传
用户体验:
- 提供清晰的错误提示
- 显示上传进度(对于大文件)
- 提供上传成功的反馈
兼容性:
- 不同浏览器对文件上传的支持不同
- 考虑移动设备的文件上传体验
练习
- 实现一个完整的文件上传验证系统
- 支持多文件上传验证
- 实现文件类型、大小的双重验证
- 实现文件重命名功能,避免文件名冲突
- 显示上传进度和成功/失败信息
