【问题标题】:What is the "conventional" way of handling uploaded image names?处理上传的图像名称的“常规”方式是什么?
【发布时间】:2011-03-23 01:07:11
【问题描述】:

所以我制作了一个具有图像上传功能的网站并将图像名称存储到数据库中。我截取了我的 Mac 的屏幕截图并想上传这张照片“屏幕截图 2011-02-18 at 6.52.20 PM.png”。好吧,这不是一个存储在 mysql 中的好名字!人们通常如何重命名照片以使上传的每张照片都有一个唯一的名称?另外,我如何确保在重命名照片时保留文件扩展名。

【问题讨论】:

    标签: php mysql image-processing


    【解决方案1】:

    我会放弃扩展,否则 Apache(或等效)将在请求时运行 a1e99398da6cf1faa3f9a196382f1fadc7bb32fb7.php(可能包含恶意 PHP)。我也会把它上传到 docroot 上面。

    如果您需要使图像在 docroot 之上可访问,您可以存储一个通过图像函数运行的安全副本,或者通过某些 PHP 提供它,例如header('Content-Type: image/jpeg')readfile()不是 include 因为我可以将 PHP 嵌入到 GIF 文件中)。

    另外,pathinfo($path, PATHINFO_EXTENSION) 是获得扩展的最佳方式。

    确保您已在数据库中存储了对该文件的引用以及原始文件名和其他元数据。

    function getUniqueName($originalFilename) {
        return sha1(microtime() . $_SERVER['REMOTE_ADDR'] . $originalFilename);
    }
    

    产生重复的唯一方法是如果一个具有相同 IP 的用户在一微秒内多次上传相同的文件名。

    或者,您可以只使用 PHP 在上传图片时分配的 basename($_FILES['upload']['tmp_name'])。我会说它应该是独一无二的。

    【讨论】:

    • “放弃扩展”是什么意思?你是说你只会将哈希值存储在 mysql 中而不是那个哈希 + 文件扩展名?
    • 我会将用户提供给您的所有内容都存储在数据库中,但将文件本身存储在服务器上,使用唯一名称且不带扩展名。
    • 但是如果它是一张图片,并且如果你放弃了扩展,你在访问它时如何知道图片是jpeg、gif还是png?
    • +1 考虑安全性。不要相信用户提供的扩展名。确保使用有效的扩展名,如 jpeg 或 png。此外,您应该始终在放置用户上传文件的任何目录中禁用脚本访问(例如,Apache 的 .htaccess),因为权限通常非常宽松(g+w 或 u+w)。
    • @konforce 非常感谢。
    【解决方案2】:

    散列图像名称。可以是 md5、sha1 甚至是 unix 时间戳。

    这是一个带有随机数(10 到 99)的(未经测试的)示例

    <?php
    function generate_unique_name($file_name)
    {
        $splitted = split(".", $file_name);
        return time() . rand(10,99) . "." . $splitted[count($splitted)-1];
    }
    ?>
    

    【讨论】:

    • 不要 md5 和 sha1 分别输出 32 和 40 个字符?一个图像名称有很多字符...
    • 至少它会是独一无二的。此外,您可以扩展 unix 时间戳,因此如果两个人同时提交,您最终不会有两张同名的图片。
    • 我见过很多unix时间戳+一个随机数。您也可以使用 crc32 之类的东西。
    • 我对php不熟悉,怎么重新生成随机数?如果你要给它加上 unix 时间戳,你将如何维护 .png 扩展名。
    • 如果两个文件在同一秒上传,rand()返回相同的随机数且扩展名相同会怎样?
    【解决方案3】:

    您可以使用如下图像表:

    id: int
    filename: varchar 
    hash: varchar
    format: enum('jpeg', 'png')
    

    哈希可以是 sha1_file($uploaded_file) 之类的东西,用于确保不会上传重复的图像。 (因此,如果需要,您可以在图像表中拥有多个具有相同哈希的条目。) id 很有用,因此您可以将整数外键链接回图像表。

    接下来将图像存储在以下任一位置:

    /image/$id.$format
    

    /image/$hash.$format
    

    通过散列的第二种格式将确保您不会复制图像数据。如果您要处理大量图像,您可能需要执行以下操作:

    /image/a/b/c/abcdef12345.jpg
    

    您使用多层文件夹来存储图像。许多文件系统会因单个目录中的文件过多而变慢。

    现在您可以直接链接到这些文件,或设置如下 URL:

    /image/$id/$filename
    

    例如:

    /image/12347/foo.jpg
    

    foo.jpg 来自用户上传的任何内容。它实际上被忽略了,因为您通过 id 查找。但是,如果人们选择下载它,它会使图像具有一个好听的名称。 (您可以选择在查找 id 后验证图像文件名是否匹配。)

    上面的路径可以通过Apache的MultiView或者ModRewrite翻译成image.php。然后您可以readfile() 或使用 X-SendFile(性能更好,但并不总是可用)将文件发送给用户。

    请注意,如果您没有 X-SendFile 并且不想通过 PHP 处理内容,则可以使用 RewriteRule 将 /image/$hash/foo.jpg 转换为 /image/a/b/c/$hash.jpg

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-09
      • 2014-02-28
      • 1970-01-01
      • 2011-04-18
      • 1970-01-01
      • 1970-01-01
      • 2010-10-10
      • 1970-01-01
      相关资源
      最近更新 更多