PHP 网站文件上传存储方案

在 PHP 网站中实现安全的文件上传和存储需要考虑多个方面,包括安全性、文件组织、性能等。以下是完整的文件上传存储解决方案:

1. 基础文件上传存储实现

上传处理脚本 (upload.php)


php

<?php
// 配置设置
$uploadConfig = [
    'uploadDir' => __DIR__ . '/uploads/', // 上传目录(确保目录存在且有写入权限)
    'allowedTypes' => [ // 允许的MIME类型
        'image/jpeg', 'image/png', 'image/gif', 
        'application/pdf', 'application/msword',
        'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
    ],
    'maxFileSize' => 5 * 1024 * 1024, // 最大文件大小(5MB)
    'fileNameLength' => 32, // 随机文件名长度
    'keepOriginalName' => false // 是否保留原始文件名
];

// 创建上传目录(如果不存在)
if (!file_exists($uploadConfig['uploadDir'])) {
    mkdir($uploadConfig['uploadDir'], 0755, true);
}

// 处理上传
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
    $file = $_FILES['file'];
    
    // 验证上传错误
    if ($file['error'] !== UPLOAD_ERR_OK) {
        http_response_code(400);
        die(json_encode(['error' => '上传错误: ' . $file['error']]));
    }
    
    // 验证文件大小
    if ($file['size'] > $uploadConfig['maxFileSize']) {
        http_response_code(400);
        die(json_encode(['error' => '文件太大,最大允许 ' . ($uploadConfig['maxFileSize'] / 1024 / 1024) . 'MB']));
    }
    
    // 验证文件类型
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $detectedType = finfo_file($finfo, $file['tmp_name']);
    finfo_close($finfo);
    
    if (!in_array($detectedType, $uploadConfig['allowedTypes'])) {
        http_response_code(400);
        die(json_encode(['error' => '不允许的文件类型']));
    }
    
    // 生成安全文件名
    $extension = pathinfo($file['name'], PATHINFO_EXTENSION);
    $extension = strtolower($extension);
    
    if ($uploadConfig['keepOriginalName']) {
        // 清理原始文件名
        $fileName = preg_replace('/[^a-zA-Z0-9\-_]/', '_', pathinfo($file['name'], PATHINFO_FILENAME));
        $fileName = substr($fileName, 0, 50); // 限制长度
        $fileName = $fileName . ($extension ? '.' . $extension : '');
    } else {
        // 生成随机文件名
        $fileName = bin2hex(random_bytes($uploadConfig['fileNameLength'] / 2));
        $fileName = substr($fileName, 0, $uploadConfig['fileNameLength']);
        $fileName = $fileName . ($extension ? '.' . $extension : '');
    }
    
    // 目标路径(按日期组织文件)
    $subDir = date(');
    $targetDir = $uploadConfig['uploadDir'] . $subDir . '/';
    
    if (!file_exists($targetDir)) {
        mkdir($targetDir, 0755, true);
    }
    
    $targetPath = $targetDir . $fileName;
    
    // 移动文件(使用rename避免复制开销)
    if (rename($file['tmp_name'], $targetPath)) {
        // 设置适当权限
        chmod($targetPath, 0644);
        
        // 返回成功响应(包含相对路径)
        $relativePath = 'uploads/' . $subDir . '/' . $fileName;
        echo json_encode([
            'success' => true,
            'filePath' => $relativePath,
            'fileName' => $fileName
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐