PHP项目如何实现文件上传?

wen PHP项目 12

本文目录导读:

PHP项目如何实现文件上传?

  1. 创建HTML表单
  2. PHP处理上传文件
  3. 完整的增强版本
  4. 安全注意事项
  5. PHP配置优化

在PHP项目中实现文件上传,主要步骤如下:

创建HTML表单

<!DOCTYPE html>
<html>
<head>文件上传</title>
</head>
<body>
    <form action="upload.php" method="post" enctype="multipart/form-data">
        <input type="file" name="fileToUpload" id="fileToUpload">
        <input type="submit" value="上传文件" name="submit">
    </form>
</body>
</html>

关键点:

  • method="post":必须使用POST方法
  • enctype="multipart/form-data":必须设置此编码类型

PHP处理上传文件

<?php
// upload.php
// 检查是否有文件上传
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_FILES['fileToUpload'])) {
    die('没有文件被上传');
}
$targetDir = "uploads/"; // 上传目录
$targetFile = $targetDir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = true;
$fileType = strtolower(pathinfo($targetFile, PATHINFO_EXTENSION));
// 检查文件是否已存在
if (file_exists($targetFile)) {
    echo "抱歉,文件已存在";
    $uploadOk = false;
}
// 限制文件大小(例如5MB)
if ($_FILES["fileToUpload"]["size"] > 5 * 1024 * 1024) {
    echo "抱歉,文件太大";
    $uploadOk = false;
}
// 限制文件类型
$allowedTypes = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'txt'];
if (!in_array($fileType, $allowedTypes)) {
    echo "抱歉,只允许 " . implode(', ', $allowedTypes) . " 格式的文件";
    $uploadOk = false;
}
// 检查上传状态
if ($uploadOk) {
    if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $targetFile)) {
        echo "文件 " . basename($_FILES["fileToUpload"]["name"]) . " 上传成功";
    } else {
        echo "抱歉,上传过程中出现错误";
    }
}
?>

完整的增强版本

<?php
class FileUploader {
    private $targetDir;
    private $maxFileSize;
    private $allowedTypes;
    private $errors = [];
    public function __construct($targetDir = "uploads/", $maxFileSize = 5 * 1024 * 1024) {
        $this->targetDir = $targetDir;
        $this->maxFileSize = $maxFileSize;
        $this->allowedTypes = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx', 'txt'];
        // 创建上传目录
        if (!file_exists($this->targetDir)) {
            mkdir($this->targetDir, 0777, true);
        }
    }
    public function upload($file) {
        // 验证上传
        if ($file['error'] !== UPLOAD_ERR_OK) {
            $this->errors[] = $this->getErrorMessage($file['error']);
            return false;
        }
        // 生成唯一文件名
        $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        $newFileName = uniqid() . '_' . time() . '.' . $extension;
        $targetFile = $this->targetDir . $newFileName;
        // 验证文件类型
        if (!in_array($extension, $this->allowedTypes)) {
            $this->errors[] = "不允许的文件类型: " . $extension;
            return false;
        }
        // 验证文件大小
        if ($file['size'] > $this->maxFileSize) {
            $this->errors[] = "文件太大,最大允许 " . ($this->maxFileSize / 1024 / 1024) . "MB";
            return false;
        }
        // 验证是否为真实文件
        if (getimagesize($file['tmp_name']) === false && in_array($extension, ['jpg', 'jpeg', 'png', 'gif'])) {
            $this->errors[] = "文件不是有效的图片";
            return false;
        }
        // 移动文件
        if (move_uploaded_file($file['tmp_name'], $targetFile)) {
            return [
                'success' => true,
                'filename' => $newFileName,
                'original_name' => $file['name'],
                'path' => $targetFile,
                'size' => $file['size'],
                'type' => $file['type']
            ];
        } else {
            $this->errors[] = "文件移动失败";
            return false;
        }
    }
    public function getErrors() {
        return $this->errors;
    }
    private function getErrorMessage($errorCode) {
        switch ($errorCode) {
            case UPLOAD_ERR_INI_SIZE:
                return "上传文件超过PHP配置限制";
            case UPLOAD_ERR_FORM_SIZE:
                return "上传文件超过表单限制";
            case UPLOAD_ERR_PARTIAL:
                return "文件仅部分被上传";
            case UPLOAD_ERR_NO_FILE:
                return "没有文件被上传";
            case UPLOAD_ERR_NO_TMP_DIR:
                return "服务器缺少临时目录";
            case UPLOAD_ERR_CANT_WRITE:
                return "文件写入失败";
            case UPLOAD_ERR_EXTENSION:
                return "文件上传被扩展阻止";
            default:
                return "未知上传错误";
        }
    }
}
// 使用示例
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['fileToUpload'])) {
    $uploader = new FileUploader();
    $result = $uploader->upload($_FILES['fileToUpload']);
    if ($result) {
        echo "上传成功!";
        echo "<br>文件名:" . $result['filename'];
        echo "<br>原始名:" . $result['original_name'];
        echo "<br>大小:" . round($result['size'] / 1024, 2) . " KB";
    } else {
        echo "上传失败:";
        foreach ($uploader->getErrors() as $error) {
            echo "<br>- " . $error;
        }
    }
}
?>

安全注意事项

// 1. 验证文件内容,不仅仅是扩展名
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $_FILES['file']['tmp_name']);
finfo_close($finfo);
// 2. 使用白名单限制文件类型
$allowedMimeTypes = ['image/jpeg', 'image/png', 'application/pdf'];
// 3. 防止路径遍历攻击
$fileName = basename($_FILES['file']['name']);
$fileName = preg_replace('/[^a-zA-Z0-9._-]/', '', $fileName);
// 4. 设置文件权限
chmod($targetFile, 0644);
// 5. 扫描病毒(可选)
// exec("clamscan " . escapeshellarg($targetFile), $output, $returnVar);

PHP配置优化

; php.ini 相关配置
file_uploads = On
upload_max_filesize = 20M
post_max_size = 25M
max_execution_time = 300
max_input_time = 300
upload_tmp_dir = /tmp
  1. 创建表单:设置正确的enctype和method
  2. 接收文件:通过$_FILES获取上传的文件
  3. 验证文件:检查类型、大小、错误码
  4. 安全处理:生成唯一文件名,防止路径遍历
  5. 保存文件:使用move_uploaded_file()移动到目标目录
  6. 返回结果:告知用户上传成功或失败

这样就能实现一个安全、完整的文件上传功能了。

抱歉,评论功能暂时关闭!