【发布时间】:2011-03-23 01:07:11
【问题描述】:
所以我制作了一个具有图像上传功能的网站并将图像名称存储到数据库中。我截取了我的 Mac 的屏幕截图并想上传这张照片“屏幕截图 2011-02-18 at 6.52.20 PM.png”。好吧,这不是一个存储在 mysql 中的好名字!人们通常如何重命名照片以使上传的每张照片都有一个唯一的名称?另外,我如何确保在重命名照片时保留文件扩展名。
【问题讨论】:
标签: php mysql image-processing
所以我制作了一个具有图像上传功能的网站并将图像名称存储到数据库中。我截取了我的 Mac 的屏幕截图并想上传这张照片“屏幕截图 2011-02-18 at 6.52.20 PM.png”。好吧,这不是一个存储在 mysql 中的好名字!人们通常如何重命名照片以使上传的每张照片都有一个唯一的名称?另外,我如何确保在重命名照片时保留文件扩展名。
【问题讨论】:
标签: php mysql image-processing
我会放弃扩展,否则 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'])。我会说它应该是独一无二的。
【讨论】:
散列图像名称。可以是 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];
}
?>
【讨论】:
rand()返回相同的随机数且扩展名相同会怎样?
您可以使用如下图像表:
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。
【讨论】: