简体   繁体   English

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

[英]How to name uploaded files in php to prevent them from being overwritten?

I'm trying to add user submitted articles to my website, (only for admins). 我正在尝试将用户提交的文章添加到我的网站(仅适用于管理员)。 With each article comes an option to upload up to 3 images. 每篇文章都有一个选项,可以上传最多3张图片。 My database is set up like this 我的数据库是这样建立的

Articles 用品

id
user_id
title
body
date_added
last_edited

Photos 相片

id (auto_increment)
article_id

First I save the article in the database, then I upload the photo (temporarily) then I create a new photo record in the database saving the article_id. 首先,我将文章保存在数据库中,然后(临时)上传照片,然后在数据库中创建新的照片记录,并保存article_id。 Then I rename the uploaded photo to be the same as the primary key of the photo record, and to be a png. 然后,我将上传的照片重命名为与照片记录的主键相同,并为png。

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

I figured this would be a good way to prevent files form being overwritten. 我认为这将是防止文件格式被覆盖的好方法。 This seems flawed to me. 这在我看来是有缺陷的。 Any suggestions on how I should save my records and photos? 关于如何保存记录和照片有什么建议吗?

Thanks 谢谢

Hash them. 哈希它们。

I've used PHP's MD5 function to hash images as they were uploaded to a gallery. 我已使用PHP的MD5函数对图像上传到画廊时进行哈希处理。 It has two major benefits: different images will not overwrite each other, identical images will . 它有两个主要好处:不同的图像不会互相覆盖,相同的图像彼此覆盖。 That means each unique picture will have a unique name. 这意味着每张唯一的图片将具有唯一的名称。 Accept the upload, hash the stored data, build the filename ( hash.extension ), check for an existing file. 接受上载,对存储的数据进行哈希处理,构建文件名( hash.extension ),检查现有文件。 If one exists, delete the temporary file and just use the existing copy. 如果存在,请删除该临时文件,然后仅使用现有副本。 Otherwise, rename the temporary file and keep it. 否则,重命名临时文件并保留它。 You may need to keep track of what is linking to each file (to make sure you don't delete a file in use somewhere else), but it can save a lot of space on duplicates and is an easy way to get unique names. 您可能需要跟踪链接到每个文件的内容(以确保您不会删除其他地方使用的文件),但是它可以在重复项上节省大量空间,并且是获取唯一名称的简便方法。

Also, you can't just rename the files to use the PNG extension, you need to convert them to PNG format or save the original extension. 另外,您不能只是将文件重命名为使用PNG扩展名,而是需要将其转换为PNG格式或保存原始扩展名。 Using the wrong extension may cause problems in some places, some browsers, and is just generally incorrect. 使用错误的扩展名可能会在某些地方,某些浏览器中引起问题,并且通常是错误的。

For what it's worth, here's a method I include in my file uploading classes to make sure i don't overwrite existing files. 对于它的价值,这是我在文件上传类中包含的一种方法,以确保我不会覆盖现有文件。 I pass the upload file name ( $_FILES[$img_field]["name"] ) and the directory to save the file into as parameters, so that this remains a general method. 我传递了上传文件的名称($ _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;
  }

There's nothing really wrong with just using the database primary key to name the file. 仅使用数据库主键来命名文件并没有真正的错误。

The only real downside I see is that you end up with fairly useless filenames. 我看到的唯一真正的缺点是,您最终会得到相当无用的文件名。 Someone might complain down the road that more descriptive names would help with search engine rankings, etc. 有人可能会抱怨说,更具描述性的名称将有助于搜索引擎排名等。

As another answer points out, renaming a file to end in .png will not make it a png. 另一个答案指出,将文件重命名为.png结尾不会使它成为png。 You might want to take a look at PHP's built-in GD library (or look up ImageMagick) if you want to actually convert image formats. 如果您想实际转换图像格式,则可能需要看一下PHP的内置GD库(或查找ImageMagick)。

If the image uses an auto-increment primary key as a name there's absolutely no chance of having two images with the same name. 如果图像使用自动递增主键作为名称,则绝对不会有两个具有相同名称的图像。

Hashing or doing anything extra to assure uniqueness in the name is worthless. 散列或进行任何其他操作以确保名称的唯一性是毫无价值的。 Even more, it would imply adding an extra image name field in the DB. 甚至更多,这意味着在数据库中添加了额外的图像名称字段。

The only way images could get overwrited is if you reset the DB auto-increment counter, and in order to do that you need to delete previous records on the table or the counter would get recalculated again by the DBMS to highest id record on the table. 可能会覆盖图像的唯一方法是,如果您重置数据库自动增量计数器,并且要执行此操作,则需要删除表上的先前记录,否则DBMS将再次将计数器重新计算为该表上的最高id记录。

In other words, using your algorithm, you won't have two images with the same name. 换句话说,使用您的算法,就不会有两个具有相同名称的图像。

The proper way is to store the files with the associated record's primary key ID. 正确的方法是使用相关记录的主键ID存储文件。 To handle the "but then it's just a useless number" you can store the original filename in the "photos" table. 要处理“但它只是一个无用的数字”,您可以将原始文件名存储在“照片”表中。 If you're allowing multiple image types, you can also store the mime type, as well. 如果允许多种图像类型,则还可以存储mime类型。

You then use a simple script that'd retrieve the file's name from the database and serve it to the client with a Content-disposition: attachment; filename=$filename 然后,您使用一个简单的脚本,该脚本将从数据库中检索文件的名称,并通过Content-disposition: attachment; filename=$filename将其提供给客户端Content-disposition: attachment; filename=$filename Content-disposition: attachment; filename=$filename header. Content-disposition: attachment; filename=$filename标头。 This way, even though the filename on your server is (say) "3527", the client will see a download of "originalimagefilename.jpg" or whatever. 这样,即使服务器上的文件名是(例如)“ 3527”,客户端也将看到“ originalimagefilename.jpg”或其他文件的下载。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM