如何在php中命名上传的文件以防止它们被覆盖?

时间:2010-04-25 03:29:42

标签: php mysql upload

我正在尝试将用户提交的文章添加到我的网站上(仅限管理员)。每篇文章都可以选择上传最多3张图片。我的数据库设置如下

文章

id
user_id
title
body
date_added
last_edited

照片

id (auto_increment)
article_id

首先我将文章保存在数据库中,然后我上传照片(暂时)然后我在数据库中创建一个新的照片记录,保存了article_id。然后我将上传的照片重命名为与照片记录的主键相同,并成为png。

$filename = $photo->id . '.png';

我认为这是防止文件形式被覆盖的好方法。这对我来说似乎有缺陷。关于如何保存我的记录和照片的任何建议?

由于

5 个答案:

答案 0 :(得分:1)

哈希他们。

我使用PHP的MD5函数在图像上传到图库时对图像进行哈希处理。它有两个主要的好处:不同的图像不会互相覆盖,相同的图像。这意味着每张独特的图片都有一个唯一的名称。接受上传,散列存储的数据,构建文件名(hash.extension),检查现有文件。如果存在,请删除临时文件并仅使用现有副本。否则,重命名临时文件并保留它。您可能需要跟踪链接到每个文件的内容(以确保您不删除其他位置使用的文件),但它可以在重复项上节省大量空间,并且是获取唯一名称的简便方法。

此外,您不能只重命名文件以使用PNG扩展名,您需要将它们转换为PNG格式或保存原始扩展名。使用错误的扩展名可能会在某些地方,某些浏览器中出现问题,而且通常不正确。

答案 1 :(得分:1)

对于它的价值,这是我在上传类的文件中包含的方法,以确保我不会覆盖现有文件。我传递上传文件名($ _FILES [$ img_field] [“name”])和目录以将文件保存为参数,因此这仍然是一般方法。

 private function unique_file_upload($filename, $dir) {
      $filename = preg_replace("/[^.\w]/",'_',$filename);
      $filename = preg_replace("/__+/",'_',$filename);
      preg_match("/^(.*)\.(\w{2,4})$/",$filename,$f);
      if ( file_exists( $dir . $filename ) ) {
          $num = 1;
          while ( file_exists( $dir . $filename ) ) {
              preg_match("/^(.*)\.(\w{2,4})$/",$filename,$f);
              preg_match("/(\d+)$/",$f[1],$n);
              if ($n[1]) {
                  $x = $n[1];
                  $num = $n[1] + 1;
                  $num .= '.';
                  $filename = preg_replace("/$x\./",$num,$filename);  
              }
              else {
                  $filename = $f[1] . $num . '.' . $f[2];
              }
          }
      }
      return $filename;
  }

答案 2 :(得分:1)

使用数据库主键命名文件并没有什么问题。

我看到的唯一真正的缺点是你最终得到了相当无用的文件名。有人可能会抱怨更多描述性名称会对搜索引擎排名等有所帮助。

正如另一个答案所指出的,将文件重命名为以.png结尾不会使其成为png。如果你想真正转换图像格式,你可能想看看PHP的内置GD库(或查找ImageMagick)。

答案 3 :(得分:1)

如果图像使用自动增量主键作为名称,则绝对不可能有两个具有相同名称的图像。

散打或做任何额外的事情以确保名称的独特性是毫无价值的。更重要的是,它意味着在数据库中添加额外的图像名称字段。

图像可以被覆盖的唯一方法是重置数据库自动增量计数器,为了做到这一点,你需要删除表上的先前记录,否则计数器将被DBMS再次重新计算到最高id记录在桌子上。

换句话说,使用您的算法,您将不会有两个同名的图像。

答案 4 :(得分:0)

正确的方法是使用关联记录的主键ID存储文件。要处理“但它只是一个无用的数字”,您可以将原始文件名存储在“照片”表中。如果您允许多种图像类型,您也可以存储mime类型。

然后使用一个简单的脚本从数据库中检索文件的名称,并使用Content-disposition: attachment; filename=$filename标头将其提供给客户端。这样,即使服务器上的文件名是(例如)“3527”,客户端也会看到“originalimagefilename.jpg”或其他任何内容的下载。