【发布时间】:2011-03-18 07:28:25
【问题描述】:
为我的用户上传的图像创建唯一名称的好方法是什么?
我不想有任何重复,所以像 MD5($filename) 这样的东西不适合。
有什么想法吗?
【问题讨论】:
-
有没有办法给出从 1,2,3... 等开始的唯一数字系列,就像它给出数据库中的主键一样?
为我的用户上传的图像创建唯一名称的好方法是什么?
我不想有任何重复,所以像 MD5($filename) 这样的东西不适合。
有什么想法吗?
【问题讨论】:
如前所述,我认为创建唯一文件名的最佳方法是简单地添加 time()。就像
$image_name = time()."_".$image_name;
【讨论】:
从上传的文件中获取文件扩展名:
$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;
我怀疑这是否会发生冲突 - 如果您不介意很长的文件名,您甚至可以不截断它。
【讨论】:
如果你真的需要一个文件名(你的问题并不完全清楚)我会使用tempnam(),它:
在指定目录中创建一个具有唯一文件名、访问权限设置为 0600 的文件。
...让 PHP 来完成唯一性的繁重工作。请注意,除了返回文件名之外,tempnam() 实际上创建了文件;当您将图像文件放在那里时,您可以覆盖它。
【讨论】:
您可以获取图像数据本身的哈希值(例如 md5、sha)。这也将有助于识别重复的图像(如果它是逐字节的,则相同)。但是任何足够长的随机字符串都可以。
您总是可以按照文件名的样子来安装它:
/image/0/1/012345678/original-name.jpg
这样文件名看起来很正常,但它仍然是唯一的。
【讨论】:
我会推荐sha1_file() 而不是md5_file()。它不太容易发生碰撞。
您也可以使用hash_file('sha256', $filePath) 来获得更好的结果。
【讨论】:
http://php.net/manual/en/function.uniqid.php 可能吗?
【讨论】:
对于简称:
$i = 0;
while(file_exists($name . '_' . $i)){
$i++;
}
警告:如果两个用户同时上传具有相同名称的图像,这可能会在多线程服务器上失败。 在这种情况下,您应该包含用户名的 md5。
【讨论】:
大声笑,md5 可以产生大约 633400000000000000000000000000000000000000000000000 种可能性 另外,为了安全起见,您可以使用
$newfilename = md5(time().'image');
if(file_exists('./images/'.$newfilename)){
$newfilename = md5(time().$newfilename);
}
//uploadimage
【讨论】:
两个用户在同一微秒上传同名图片的概率有多大?
试试
$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 ...
}
这也有助于您跟踪文件的上传时间以进行分析。或者可以对文件进行排序,管理文件。
【讨论】:
为了获得良好的性能和独特性,您可以使用以下方法:
文件将存储在名称类似于md5_file($file).jpg的服务器上
从 md5 文件名中定义存储文件的目录,通过剥离前两个字符(第一级)和后两个字符(第二级),如下所示:
uploaded_files\ 30 \ c5 \ 30 c5 67139b64ee14c80cc5f5006d8081.pdf
使用file_id、原始文件名、上传的用户ID和服务器上文件的路径在数据库中创建记录
在服务器端创建脚本,它将获得下载提供的角色 - 它将从 db 通过 id 获取文件,并使用用户提供的原始文件名输出其内容(参见 codeigniter download_helper 的 php 示例)。所以文件的 url 看起来像这样:
优点:
减少碰撞威胁
文件查找性能好(1个目录下文件不多,同级目录不多)
保存原始文件名
您可以通过服务器端脚本(检查会话或 cookie)调整对文件的访问权限
缺点:
【讨论】:
试试这个文件格式:
$filename = microtime(true) . $username . '.jpg';
【讨论】:
我认为这对你有好处。
<?php
$name=uniqid(mt_rand()).$image_name;
?>
【讨论】:
您应该尝试实现两个目标:独特性和实用性。
使用 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 的正确随机字符串)确保。 如果文件曾经被分离,您可以识别用户、日期和时间以及标题。 一切都被折叠成小写,所有非字母数字的东西都被删除并替换为破折号,这使得文件名易于使用简单的工具处理(例如,没有可能混淆编写不好的脚本的空格,没有冒号或某些文件系统上禁止的其他字符,等等)。
【讨论】:
这样的事情可能对你有用:
while (file_exists('/uploads/' . $filename . '.jpeg')) {
$filename .= rand(10, 99);
}
【讨论】:
即用型代码:
$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)
【讨论】: