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

Posted

技术标签:

【中文标题】使用 PHP 创建单文件上传表单的最佳方法是啥?【英文标题】:What's the best way to create a single-file upload form using PHP?使用 PHP 创建单文件上传表单的最佳方法是什么? 【发布时间】:2010-09-16 22:26:12 【问题描述】:

我在网上找到了一些示例,但我想从每天使用 php 的人那里获得有关潜在安全性或性能注意事项及其解决方案的反馈。

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

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

我想知道最好的html表单代码和PHP处理代码。

【问题讨论】:

【参考方案1】:

文件上传教程

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 文件(如下)中的相应值。

PHP

<?php
$uploaddir = "/www/uploads/";
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);

echo '<pre>';
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) 
    echo "Success.\n";
 else 
    echo "Failure.\n";


echo 'Here is some more debugging info:';
print_r($_FILES);
print "</pre>";
?>

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

打印$_FILES 的值可以提示正在发生的事情。例如:

大批 ( [用户文件] => 数组 ( [名称] => 文件名.ext [类型] => [tmp_name] => [错误] => 2 [大小] => 0 ) )

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

错误代码

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

php.ini配置

使用较大的文件运行此设置时,您可能会收到错误。检查您的 php.ini 文件以获取这些密钥:

max_execution_time = 30upload_max_filesize = 2M

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

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

检查文件 mimetypes

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

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

// 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 manual 阅读有关处理文件上传的更多信息。

对于 PHP 5.3+

//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 documentation 阅读有关 FILEINFO_MIME_TYPE 的更多信息。

【讨论】:

值得注意的是,在该示例中,我可以上传一个 php 文件并访问您的 Web 服务器。小心那些东西。 :S 没错。我将此作为社区答案发布,因此请随时自行编辑 :) 是的,检查您上传的文件的 mimetype 很重要。最好的保护是允许某些类型(图像/jpeg、存档/zip 等)并禁止所有其他类型。 @Ross:这听起来是个好主意。你能演示一些检查 MIME 类型的代码吗?谢谢你的链接,顺便说一句。 我使用 FileInfo 扩展来检查 MIME 类型。添加到这篇文章中(因为它更好)并稍微改变了格式。【参考方案2】:

安全性对于文件上传来说是一件非常重要的事情,向上传文件夹添加一个 .htaccess 可以阻止脚本从中运行,这可以方便地添加额外的安全层。

.htaccess

Options -Indexes
Options -ExecCGI
AddHandler cgi-script .php .php3 .php4 .phtml .pl .py .jsp .asp .htm .shtml .sh .cgi 

参考:http://www.mysql-apache-php.com/fileupload-security.htm

【讨论】:

【参考方案3】:

阅读this introduction,它应该会告诉你你需要知道的一切。用户 cmets 也相当有用。

【讨论】:

【参考方案4】:

Flash 的主要好处是它允许您上传多个文件。 Java 的主要好处是它允许从文件系统拖放。很抱歉没有回答中心问题,但我想我会把它扔进去,因为它相当简单。

【讨论】:

另一个好处是在 PHP 4 中你不能显示上传进度条。您可以在 PHP 5、Flash 和 Java 中使用。 与其讨论 Java 和 Flash,如果您提供的示例代码展示了如何使用 PHP5 显示进度条会更有用;) 你可以。 phpclasses.org/blog/post/… 可以使用 PHP 支持的 HTML 数组功能上传多个文件。 php manual

以上是关于使用 PHP 创建单文件上传表单的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Web 表单通过 HTTP POST 上传文件的最佳方式是啥?

通过表单按钮在 laravel 中触发 php 脚本的最佳方法是啥?

php单文件上传方法 转

创建单页应用程序 React JS 的最佳方法是啥? [关闭]

从 serialize() AJAX 获取 PHP 中的多个/多个 POST 变量的最佳方法是啥?

在 Laravel 5.4 中创建表单的最佳方法是啥?