使用PHP和MySQL存储用户图像的最佳方法是什么?

11
我在想,使用PHP和MySQL存储用户上传的图像(如头像等)的最佳方式是什么? 我应该从哪里开始? 是否有一篇好的文章介绍这个问题?
7个回答

16
“最好”的选择取决于您的目标。
将用户上传的图像存储的两种主要方法是,将二进制内容作为BLOB放入数据库中,或者将图像存储在某个地方的驱动器上,并在数据库中放置一个条目来指示哪个图像属于哪里。
将图像放置在数据库中的优点是不需要在Web服务器上进行任何文件系统权限,并且如果您从多个Web服务器提供站点,则会消除任何同步问题。然而,随着时间的推移,它会使您的数据库变得巨大,并且如果您没有正确设计表格,则可能完全破坏您的性能和可扩展性。
将图像作为文件存储在文件系统中具有极快的检索速度和效率的附加优势,因为Web服务器非常擅长提供静态文件。
编辑以添加
如果您决定在数据库中存储文件内容,则绝对不要将其放在需要快速访问的表格中。例如,如果您有一个“用户”表格几乎在每个页面查看时都会被搜索,则该表格不是放置文件内容的地方。相反,创建一个包含文件和相关元信息的单独的“图像”或“文件”表格。
在一行中放置大量字节会使表格处理变得非常缓慢。您不希望在频繁使用的表格中出现这种情况。

如果你将要使用数据库,那是一个非常好的想法。为了减轻图片表的负担,使用memcache缓存图像也会有所帮助。 - BraedenP
推论:如果您的文件内容需要快速访问,请勿将其存储在数据库中。 - Josh Lee

14

出于以下几个原因,图像应该存储在文件系统中:

  • 代理和 If-Modified-Since 网络请求: Apache 可以为您处理 If-Modified-Since HTTP 头,并返回 304 响应,这是最佳性能。反向 Squid 代理和 ISP 发布的代理将尝试利用此功能。

  • 病毒扫描: 如果允许上传任何文件,混蛋们会尝试上传可怕的东西,看看能否破坏您的网站。运行 ClamAV 或类似软件来查看用户上传是否有问题并不过分。如果想要扫描记录中的恶意软件,你不希望绑定数据库。

  • 模式简单性: 如果允许文件上传,还需要添加有关 MIME 类型、文件大小、高度和宽度的元数据。如果文件本身与表中的 MIME 类型不匹配,则需要从表中进行选择并将其流式传输到 /usr/bin/file。使用 shell_exec( "/usr/bin/file /path/to/mumble" ) 可以更简单。

  • 缩略图: 用户图像上传很可能需要生成缩略图,这通常比实际网络请求更容易完成。当一些好心的用户尝试上传他们的专业摄影师朋友给他们的 150MB Photoshop 文件时,如果 Apache 实例在尝试将 ImageMagick 库加载到 web 工作进程的内存空间中时出现 OOM,则真的很不好玩。这对于 Apache 工作者来说真的不可扩展。创建一个工作队列/定期任务以处理此工作。

  • 表损坏: 真是太糟糕了,如果您的 MySQL 索引文件出现故障并且您需要对该表进行离线表修复,则不会瘫痪所有用户头像。

  • 备份和恢复: 不建议使用mysqldump锁定大表。使用rsync将节省时间并提供更大的灵活性。通常情况下,表格是整个恢复的——表格不会以较小的块进行备份。


  • 3
    在服务器上为每个用户创建一个新目录,该目录的名称应使用用户ID,并将用户的图像保存在其中。每当您想要显示用户的图像时:
    <img src="<path>/users_images/<user_id>/thumb.gif" />
    

    2
    如果我是你,我会将图像保存在您的站点目录中,然后将图像链接保存在MySQL中。如果您真的想将其保存在数据库中,我会将其读入字符串中,然后使用base64_encode()进行编码,然后将其保存在数据库中。
    将它们存储在数据库中会遇到各种小问题,您将不得不创建脚本来输出它们等等,服务器和数据库负载也会大大增加。如果我是你,我会只存储引用。

    1
    我建议您创建一个表格来存储用户数据,例如用户名和名字。在该表中,创建一个名为“avatar”的字段,您可以在其中存储文件引用。
    假设您的用户头像存储在:htdocs/images/avatars/ 并且用户apikot在数据库中存储了头像“avatar.jpg”,那么在生成图像标签时,您可以编译以下URL:“/htdocs/images/avatars/avatar.jpg”。

    0
    这是一个将图像以二进制形式存储在MySQL数据库中的示例。我不确定是否有任何优点,留给其他人评论。
    另一种方法是将图像的位置存储在列中,并查询引用它。

    1
    是的,我建议不要这样做,除非有一些原因需要保护图像。通过这种方式,首先需要从数据库中提取图像,然后处理二进制文件。这将增加PHP服务器和MySQL服务器的负载。你的第二个建议更好;将图像存储在用户图像文件夹中,可能使用uniqid()命名,然后在数据库中引用相对URL。 - BraedenP

    0
    创建一个BLOB类型的字段,并插入file_get_contents($ImageFile)函数的结果。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接