【问题标题】:Create Unique Image Names创建唯一的图像名称
【发布时间】:2011-03-18 07:28:25
【问题描述】:

为我的用户上传的图像创建唯一名称的好方法是什么?

我不想有任何重复,所以像 MD5($filename) 这样的东西不适合。

有什么想法吗?

【问题讨论】:

  • 有没有办法给出从 1,2,3... 等开始的唯一数字系列,就像它给出数据库中的主键一样?

标签: php filenames


【解决方案1】:

如前所述,我认为创建唯一文件名的最佳方法是简单地添加 time()。就像

$image_name = time()."_".$image_name;

【讨论】:

  • 如果连续执行两次,一个接一个,这可能会导致名称冲突,因为 time() 对两者来说是相同的。可以按照以下答案中的建议使用 microtime() 来避免这种情况。
  • 如果一个用户一次上传多张同名的图片。那就不好了。
【解决方案2】:

从上传的文件中获取文件扩展名:

$ext = pathinfo($uploaded_filename, PATHINFO_EXTENSION);

把时间抢到秒:time()

获取一些随机性:md5(microtime())

将时间转换为 base 36:base_convert (time(), 10, 36) - base 36 将一个 10 字节的字符串压缩到大约 6 个字节,以允许使用更多的随机字符串

将整个批次作为 16 个字符的字符串发送出去:

$unique_id = substr( base_convert( time(), 10, 36 ) . md5( microtime() ), 0, 16 ) . $ext;

我怀疑这是否会发生冲突 - 如果您不介意很长的文件名,您甚至可以不截断它。

【讨论】:

  • 你忘记了唯一ID和分机之间的点。
【解决方案3】:

如果你真的需要一个文件名(你的​​问题并不完全清楚)我会使用tempnam(),它:

在指定目录中创建一个具有唯一文件名、访问权限设置为 0600 的文件。

...让 PHP 来完成唯一性的繁重工作。请注意,除了返回文件名之外,tempnam() 实际上创建了文件;当您将图像文件放在那里时,您可以覆盖它。

【讨论】:

  • 我发现这个答案非常有用且被低估了。但是,当您在服务器之外拥有像对象存储(S3、云文件等)这样的存储时,您可以依靠这个:(
【解决方案4】:

您可以获取图像数据本身的哈希值(例如 md5、sha)。这也将有助于识别重复的图像(如果它是逐字节的,则相同)。但是任何足够长的随机字符串都可以。

您总是可以按照文件名的样子来安装它:

/image/0/1/012345678/original-name.jpg

这样文件名看起来很正常,但它仍然是唯一的。

【讨论】:

    【解决方案5】:

    我会推荐sha1_file() 而不是md5_file()。它不太容易发生碰撞。 您也可以使用hash_file('sha256', $filePath) 来获得更好的结果。

    【讨论】:

    • 不易发生碰撞?让我们在这里稍微了解一下。使用 MD5 并考虑生日悖论,您发生碰撞的机会小于 0.0000000000000000000000000000000000000000000000000001%
    【解决方案6】:

    http://php.net/manual/en/function.uniqid.php 可能吗?

    • 您可以在其前面加上用户 ID,以避免 2 个用户之间发生冲突(不到 1 毫秒)。

    【讨论】:

      【解决方案7】:

      对于简称:

      $i = 0;
      while(file_exists($name . '_' . $i)){
        $i++;
      }
      

      警告:如果两个用户同时上传具有相同名称的图像,这可能会在多线程服务器上失败。 在这种情况下,您应该包含用户名的 md5。

      【讨论】:

        【解决方案8】:

        大声笑,md5 可以产生大约 633400000000000000000000000000000000000000000000000 种可能性 另外,为了安全起见,您可以使用

        $newfilename = md5(time().'image');
        if(file_exists('./images/'.$newfilename)){
            $newfilename = md5(time().$newfilename);
        }
        //uploadimage
        

        【讨论】:

        • 相同的输入为哈希提供相同的输出。所以如果问题是输入不是唯一的(文件名),那么输出也不会是唯一的。
        【解决方案9】:

        两个用户在同一微秒上传同名图片的概率有多大?

        试试

            $currTime = microtime(true);
            $finalFileName = cleanTheInput($fileName)."_".$currTime;
        
        // you can also append a _.rand(0,1000) in the end to have more foolproof name collision
        
            function cleanTheInput($input)
            {
             // do some formatting here ...
            }
        

        这也有助于您跟踪文件的上传时间以进行分析。或者可以对文件进行排序,管理文件。

        【讨论】:

          【解决方案10】:

          为了获得良好的性能和独特性,您可以使用以下方法:

          • 文件将存储在名称类似于md5_file($file).jpg的服务器上

          • 从 md5 文件名中定义存储文件的目录,通过剥离前两个字符(第一级)和后两个字符(第二级),如下所示:

            uploaded_files\ 30 \ c5 \ 30 c5 67139b64ee14c80cc5f5006d8081.pdf

          • 使用file_id、原始文件名、上传的用户ID和服务器上文件的路径在数据库中创建记录

          • 在服务器端创建脚本,它将获得下载提供的角色 - 它将从 db 通过 id 获取文件,并使用用户提供的原始文件名输出其内容(参见 codeigniter download_helper 的 php 示例)。所以文件的 url 看起来像这样:

            http://site.com/download.php?file=id


          优点:

          • 减少碰撞威胁

          • 文件查找性能好(1个目录下文件不多,同级目录不多)

          • 保存原始文件名

          • 您可以通过服务器端脚本(检查会话或 cookie)调整对文件的访问权限

          缺点:

          • 适合小文件,因为在用户下载文件之前,服务器必须在内存中读取此文件

          【讨论】:

            【解决方案11】:

            试试这个文件格式:

            $filename = microtime(true) . $username . '.jpg';
            

            【讨论】:

            • 这将添加一个点,我总是想避免文件名中的点,所以如果需要我可以在点上分割
            【解决方案12】:

            我认为这对你有好处。

            <?php
                $name=uniqid(mt_rand()).$image_name;
             ?>
            

            【讨论】:

              【解决方案13】:

              您应该尝试实现两个目标:独特性和实用性。

              使用 GUID 可以保证唯一性,但有一天文件可能会与原始来源分离,然后您就会遇到麻烦。

              我的典型解决方案是在文件名中嵌入关键信息,例如用户 ID(如果它属于用户)或上传日期和时间(如果这很重要),或者上传时使用的文件名。

              有一天,当嵌入在文件名中的信息允许您从错误中恢复或意外删除记录时,这可能真的会拯救您的皮肤。如果您拥有的只是 GUID,并且您丢失了目录,那么您将有大量的工作来清理它。

              例如,如果用户 ID 98765 在 2013 年 4 月 4 日 12:51:23 上传了一个文件“我的假期:佛罗里达州 23.jpg”,我将其命名为这样,添加一个随机字符串 ad8a7dsf9 :

              20130404125123-ad8a7dsf9-98765-my-holiday-florida-23.jpg

              唯一性由日期和时间以及随机字符串(只要它是来自 /dev/urandom 或 CryptGenRandom 的正确随机字符串)确保。 如果文件曾经被分离,您可以识别用户、日期和时间以及标题。 一切都被折叠成小写,所有非字母数字的东西都被删除并替换为破折号,这使得文件名易于使用简单的工具处理(例如,没有可能混淆编写不好的脚本的空格,没有冒号或某些文件系统上禁止的其他字符,等等)。

              【讨论】:

                【解决方案14】:

                这样的事情可能对你有用:

                while (file_exists('/uploads/' . $filename . '.jpeg')) {
                   $filename .= rand(10, 99);
                }
                

                【讨论】:

                  【解决方案15】:

                  即用型代码:

                  $file_ext = substr($file['name'], -4); // e.g.'.jpg', '.gif', '.png', 'jpeg' (note the missing leading point in 'jpeg')
                  $new_name = sha1($file['name'] . uniqid('',true)); // this will generate a 40-character-long random name
                  $new_name .= ((substr($file_ext, 0, 1) != '.') ? ".{$file_ext}" : $file_ext); //the original extension is appended (accounting for the point, see comment above)
                  

                  【讨论】:

                  • sha1 与 md5 有同样的碰撞问题。
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-11-05
                  • 2011-12-07
                  • 2014-07-27
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多