使用 PHP 创建单文件上传表单的最佳方法是什么?

2021-12-24 00:00:00 file-upload upload php

我在网上找到了一些示例,但我想从每天使用 PHP 的人那里获得关于潜在安全或性能考虑因素及其解决方案的反馈.

I've found a few samples online but I'd like to get feedback from people who use PHP daily as to potential security or performance considerations and their solutions.

请注意,我只对一次上传一个文件感兴趣.

Note that I am only interested in uploading a single file at a time.

理想情况下不需要浏览器插件(Flash/Java),尽管了解使用插件的好处会很有趣.

Ideally no browser plugin would be required (Flash/Java), although it would be interesting to know the benefits of using a plugin.

我想知道最好的 HTML 表单代码和 PHP 处理代码.

I would like to know both the best HTML form code and PHP processing code.

推荐答案

文件上传教程

HTML

<form enctype="multipart/form-data" action="action.php" method="POST">
  <input type="hidden" name="MAX_FILE_SIZE" value="1000000" />
  <input name="userfile" type="file" />
  <input type="submit" value="Go" />
</form>

  • action.php 是将处理上传的 PHP 文件的名称(如下所示)
  • MAX_FILE_SIZE 必须出现在类型为 file 的输入之前.这个值可以很容易地在客户端上操作,所以不应该依赖.它的主要好处是在用户上传文件之前向用户提供文件过大的早期警告.
  • 您可以使用 file 类型更改输入的名称,但请确保它不包含任何空格.您还必须更新 PHP 文件中的相应值(如下).
    • action.php is the name of a PHP file that will process the upload (shown below)
    • MAX_FILE_SIZE must appear immediately before the input with type file. This value can easily be manipulated on the client so should not be relied upon. Its main benefit is to provide the user with early warning that their file is too large, before they've uploaded it.
    • You can change the name of the input with type file, but make sure it doesn't contain any spaces. You must also update the corresponding value in the PHP file (below).
    • <?php
      $uploaddir = "/www/uploads/";
      $uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
      
      echo '<pre>';
      if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
          echo "Success.
      ";
      } else {
          echo "Failure.
      ";
      }
      
      echo 'Here is some more debugging info:';
      print_r($_FILES);
      print "</pre>";
      ?>
      
      The upload-to folder should not be located in a place that's accessible via HTTP, otherwise it would be possible to upload a PHP script and execute it upon the server.

      upload-to 文件夹不应位于可通过 HTTP 访问的位置,否则可能上传 PHP 脚本并在服务器上执行.

      Printing the value of $_FILES can give a hint as to what's going on. For example:

      打印$_FILES 的值可以提示发生了什么.例如:

      Array ( [userfile] => Array ( [name] => Filename.ext [type] => [tmp_name] => [error] => 2 [size] => 0 ) )

      这个结构提供了一些关于文件名、MIME 类型、大小和错误代码的信息.

      This structure gives some information as to the file's name, MIME type, size and error code.

      0 表示没有错误,文件上传成功
      1 表示文件超过了 php.ini 中定义的最大文件大小.如果您想更改最大文件大小,您需要打开您的 php.ini 文件,确定读取的行:upload_max_filesize = 2M 并将值从 2M (2MB) 更改为您需要的任何值
      2 表示已超出页面脚本中手动定义的最大文件大小
      3 表示文件只上传了部分
      4 表示没有指定文件(空文件字段)
      5 尚未定义
      6 表示没有临时文件夹
      7 表示文件无法写入磁盘

      0 Indicates that there was no errors and file has been uploaded successfully
      1 Indicates that the file exceeds the maximum file size defined in php.ini. If you would like to change the maximum file size, you need to open your php.ini file, identify the line which reads: upload_max_filesize = 2M and change the value from 2M (2MB) to whatever you need
      2 Indicates that the maximum file size defined manually, within an on page script has been exceeded
      3 Indicates that file has only been uploaded partially
      4 Indicates that the file hasn't been specified (empty file field)
      5 Not defined yet
      6 Indicates that there´s no temporary folder
      7 Indicates that the file cannot be written to the disk

      php.ini 配置

      使用较大的文件运行此设置时,您可能会收到错误消息.检查您的 php.ini 文件中的这些键:

      php.ini Configuration

      When running this setup with larger files you may receive errors. Check your php.ini file for these keys:

      max_execution_time = 30
      upload_max_filesize = 2M

      适当增加这些值可能会有所帮助.使用 Apache 时,对此文件的更改需要重新启动.

      Increasing these values as appropriate may help. When using Apache, changes to this file require a restart.

      最大内存允许值(通过 memory_limit 设置)在此处不起作用,因为文件在上传时写入 tmp 目录.tmp 目录的位置可以通过 upload_tmp_dir 控制.

      The maximum memory permitted value (set via memory_limit) does not play a role here as the file is written to the tmp directory as it is uploaded. The location of the tmp directory is optionally controlled via upload_tmp_dir.

      您应该检查用户上传的文件类型 - 最佳做法是根据允许的文件类型列表进行验证.允许任何文件的潜在风险是用户可能将 PHP 代码上传到服务器然后运行它.

      You should check the filetype of what the user is uploading - the best practice is to validate against a list of allowed filetypes. A potential risk of allowing any file is that a user could potentially upload PHP code to the server and then run it.

      您可以使用非常有用的fileinfo 扩展(取代旧的 mime_content_type 函数)来验证 MIME 类型.

      You can use the very useful fileinfo extension (that supersedes the older mime_content_type function) to validate mime-types.

      // FILEINFO_MIME set to return MIME types, will return string of info otherwise
      $fileinfo = new finfo(FILEINFO_MIME);
      $file = $fileinfo->file($_FILE['filename']);
      
      $allowed_types = array('image/jpeg', 'image/png');
      if(!in_array($file, $allowed_types))
      {
          die('Files of type' . $file . ' are not allowed to be uploaded.');
      }
      // Continue
      

      更多信息

      您可以在 PHP.net 手册中阅读有关处理文件上传的更多信息.

      //For those who are using PHP 5.3, the code varies.
      $fileinfo = new finfo(FILEINFO_MIME_TYPE);
      $file = $fileinfo->file($_FILE['filename']['tmp_name']);
      $allowed_types = array('image/jpeg', 'image/png');
      if(!in_array($file, $allowed_types))
      {
          die('Files of type' . $file . ' are not allowed to be uploaded.');
      }
      // Continue
      

      更多信息

      您可以在 PHP.net 文档中阅读有关 FILEINFO_MIME_TYPE 的更多信息.

      More Information

      You can read more on FILEINFO_MIME_TYPE at the PHP.net documentation.

相关文章