基础实现步骤
前端表单设计
<form action="upload.php" method="post" enctype="multipart/form-data"> <input type="file" name="fileToUpload" required> <input type="submit" value="上传文件"> </form>
- 关键属性:
enctype="multipart/form-data"
(必须声明)
name="fileToUpload"
(后端通过此名称获取文件)
后端处理(upload.php)
<?php $targetDir = "uploads/"; // 上传目录 $targetFile = $targetDir . basename($_FILES["fileToUpload"]["name"]); // 文件路径 // 1. 检查目录是否存在 if (!file_exists($targetDir)) { mkdir($targetDir, 0755, true); // 自动创建目录(权限755) } // 2. 检查文件是否上传成功 if ($_FILES["fileToUpload"]["error"] !== UPLOAD_ERR_OK) { die("上传失败,错误代码:" . $_FILES["fileToUpload"]["error"]); } // 3. 移动临时文件到目标位置 if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $targetFile)) { echo "文件 " . htmlspecialchars(basename($_FILES["fileToUpload"]["name"])) . " 上传成功"; } else { echo "文件移动失败"; } ?>
安全加固措施
限制文件类型
$allowedTypes = ["jpg", "png", "pdf"]; // 允许的扩展名 $fileExtension = strtolower(pathinfo($targetFile, PATHINFO_EXTENSION)); if (!in_array($fileExtension, $allowedTypes)) { die("错误:仅支持 JPG, PNG, PDF 格式"); }
限制文件大小
$maxSize = 2 * 1024 * 1024; // 2MB if ($_FILES["fileToUpload"]["size"] > $maxSize) { die("文件大小超过 2MB 限制"); }
防止文件名覆盖
// 生成唯一文件名(避免重名覆盖) $newFileName = uniqid() . '.' . $fileExtension; $targetFile = $targetDir . $newFileName;
验证文件内容(防伪装攻击)
// 检查图片是否为真实类型 if (in_array($fileExtension, ["jpg", "png", "jpeg"])) { $check = getimagesize($_FILES["fileToUpload"]["tmp_name"]); if ($check === false) { die("文件不是有效图片"); } }
禁用PHP执行(目录级防护)
在上传目录中创建 .htaccess
文件(Apache):
php_flag engine off
完整安全代码示例
<?php $targetDir = "uploads/"; $allowedTypes = ["jpg", "png", "pdf"]; $maxSize = 2 * 1024 * 1024; // 2MB // 检查请求方法 if ($_SERVER["REQUEST_METHOD"] !== "POST") { die("仅支持POST请求"); } // 检查文件错误 if ($_FILES["fileToUpload"]["error"] !== UPLOAD_ERR_OK) { die("上传错误:" . $_FILES["fileToUpload"]["error"]); } // 生成安全文件名 $fileExtension = strtolower(pathinfo($_FILES["fileToUpload"]["name"], PATHINFO_EXTENSION)); $newFileName = uniqid() . '.' . $fileExtension; $targetFile = $targetDir . $newFileName; // 验证扩展名 if (!in_array($fileExtension, $allowedTypes)) { die("无效文件类型"); } // 验证大小 if ($_FILES["fileToUpload"]["size"] > $maxSize) { die("文件超过大小限制"); } // 验证图片真实性 if (in_array($fileExtension, ["jpg", "png", "jpeg"])) { if (!getimagesize($_FILES["fileToUpload"]["tmp_name"])) { die("非真实图片文件"); } } // 移动文件 if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $targetFile)) { echo "文件上传成功!保存为:" . htmlspecialchars($newFileName); } else { echo "服务器存储失败"; } ?>
常见问题排查
-
权限问题
- 确保上传目录可写:
chmod -R 755 /var/www/html/uploads/
- 检查SELinux状态(如启用):
setenforce 0 # 临时禁用
- 确保上传目录可写:
-
文件大小限制
修改php.ini
:upload_max_filesize = 10M post_max_size = 12M
-
临时目录空间不足
检查/tmp
分区剩余空间:df -h /tmp
最佳实践总结
- 安全第一:始终验证文件类型、大小、内容,避免直接使用用户输入的文件名。
- 隔离上传目录:将上传文件存放在Web根目录外的独立路径(如
/var/uploads
),并通过脚本代理访问。 - 定期清理:设置定时任务删除旧文件,避免存储溢出。
- 日志记录:记录上传操作(IP、文件名、时间)便于审计。
引用说明: 参考PHP官方文档(文件上传处理)及OWASP文件上传安全指南(2025版),技术细节遵循PSR标准,已在Ubuntu 22.04 LTS + PHP 8.1环境中验证。
原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/8446.html