如何安全重命名上传的图片文件(去除空格与特殊字符)

如何安全重命名上传的图片文件(去除空格与特殊字符)

本文介绍如何在php文件上传过程中,使用自定义清洗函数自动清理原始文件名中的空格、符号和重复连字符,生成符合web规范的安全文件名,并确保数据库记录与实际存储路径一致。

在处理用户上传的图片时,原始文件名常包含空格(如 “my photo.jpg”)、特殊字符(如 “credit@#%card.png”)或连续标点(如 “file—-2024.jpg”),这些不仅影响URL可读性与SEO,还可能引发服务器解析异常、安全风险(如路径遍历尝试)或CDN/缓存兼容性问题。PHP无法在客户端修改真实文件名(浏览器出于安全限制禁止JS重命名本地文件),但完全可以在服务端接收后、保存前,对文件名进行标准化清洗——这正是最佳实践所在。

以下是一个健壮、可复用的解决方案,整合了您提供的 cleanStr() 函数,并优化了上传逻辑:

✅ 推荐实现代码(含关键改进)

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_GET['id'], $_FILES['files']['name'])) {
    // 清洗函数:统一空格为短横线,移除非字母数字及短横线字符,压缩多连横为单横
    function cleanStr($string) {
        $string = str_replace(' ', '-', $string);
        $string = preg_replace('/[^A-Za-z0-9/-]/', '', $string);
        return preg_replace('/-+/', '-', trim($string, '-'));
    }

    $count = 0;
    $sql = "INSERT INTO images (post_id, name, image) VALUES (?, ?, ?)";
    $stmt = $db->prepare($sql);

    // 定义存储路径(建议使用绝对路径提升可靠性)
    $uploadDir = __DIR__ . '/uploads/documents/';
    $webPath = './uploads/documents/'; // 相对路径,用于前端展示或数据库存储

    $allowedExts = ['png', 'jpg', 'jpeg'];

    foreach ($_FILES['files']['name'] as $index => $originalName) {
        $tmpPath = $_FILES['files']['tmp_name'][$index];
        $error   = $_FILES['files']['error'][$index];

        // 跳过空文件或上传错误
        if (empty($tmpPath) || $error !== UPLOAD_ERR_OK) continue;

        // 解析原始文件信息
        $ext  = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
        $base = pathinfo($originalName, PATHINFO_FILENAME);

        // 基础校验:扩展名 + 是否为有效图像
        if (!in_array($ext, $allowedExts) || !getimagesize($tmpPath)) continue;

        // ✅ 关键步骤:清洗文件名并生成唯一新名
        $safeName = cleanStr($base) ?: 'unnamed'; // 防止清洗后为空
        $timestamp = date('Y-m-d-his');
        $finalName = "{$timestamp}-{$safeName}.{$ext}";
        $savePath  = $uploadDir . $finalName;
        $dbPath    = $webPath . $finalName;

        // 执行移动与入库
        if (move_uploaded_file($tmpPath, $savePath)) {
            $stmt->execute([$_GET['id'], $finalName, $dbPath]);
            $count++;
        }
    }

    // 重定向并携带统计信息
    $redirect = "result.php?id={$_GET['id']}&action=UPLOADED&total={$count}";
    exit(header("Location: {$redirect}"));
}

⚠️ 注意事项与增强建议

  • cleanStr() 补充说明
    原函数未处理首尾连字符,可能导致 “-abc-” → “abc-“。上述代码中 trim($string, ‘-‘) 已修复此问题,确保生成的文件名不以 – 开头或结尾。

  • 安全性强化

    聚蜂消防BeesFPD

    聚蜂消防BeesFPD

    关注消防领域的智慧云平台

    下载

    • 使用 getimagesize() 替代仅靠扩展名判断,防止伪造 .jpg 后缀的恶意脚本;
    • move_uploaded_file() 是必须使用的函数,它能阻止临时文件被篡改或重放攻击;
    • 避免直接拼接 $_FILES[‘files’][‘name’] 到路径中,始终清洗后再组合。
  • 可扩展性提示

    • 如需支持中文,可将 cleanStr() 中正则替换为 preg_replace(‘/[^/p{Han}/p{L}/p{N}/-]/u’, ”, $string)(启用 Unicode 模式);
    • 生产环境建议添加文件大小限制($_FILES[‘files’][‘size’][$i])、防重名机制(如 uniqid() 或哈希前缀);
    • 数据库存储推荐保存相对路径(如 ./uploads/…),而非绝对路径,便于迁移部署。

通过以上方式,您不仅能彻底解决“credi– @% sdfdsf..####tcard.jpg”这类混乱文件名问题,还能构建更安全、可维护的上传流程。

https://www.php.cn/faq/1983556.html

发表回复

Your email address will not be published. Required fields are marked *