6

在 Web 开发人员生活的后期或早期,您将不得不处理用户上传的文件和图像。

常见问题:

如何上传?

现代网络浏览器和技术允许通过多种方式将用户提供的文件上传到我的服务器。什么是最佳实践,我必须考虑什么?

我该如何处理?

上传完成后,我需要了解安全性以及文件的进一步处理

我如何存储和交付?

是否有关于如何存储上传文件的最佳实践?

免责声明:我在下面的答案中花了将近 30 分钟,最初的问题已被删除,所以我决定询问用户在处理用户提供的文件时可能面临的一般问题。看我的回答,您可以自由贡献并添加您的想法和经验

4

1 回答 1

28

每个步骤都没有“最佳”方法,而是各种技术和库中的一大堆既定方法和最佳实践,可以帮助您实现用户友好的上传、安全性和速度。

对于另一个不幸被删除的问题,我写了这个小指南。

用户贡献的文件或图像在其生命周期中经历了几个阶段:

  1. 上传本身
  2. 验证
  3. 存储处理(例如类型转换、调整大小、生成缩略图……)
  4. 存储
  5. 前端交付

这将解决所有步骤并尽可能提供示例

1. 上传

现代网络浏览器提供了几种上传文件的方法。

最简单的方法是创建一个带有简单<input type="file" name="userFile" />标签的表单。提交表单后,文件将使用 POST 发送,并且可以使用PHP 中的$_FILES 超全局访问

1.1。HTML 中的简单表单

<form action="upload.php" method="post" enctype="multipart/form-data">
    <input type="file" name="userFile1" />
    <input type="file" name="userFile2" />
    <input type="submit" value="upload files" />
</form>

当提交表单时,会向upload.php 发送一个POST 请求。这种上传方式不是很友好。您的用户将看不到上传的任何进度,并且上传多个文件会很痛苦

1.2. Javascript ajax 上传

在此解决方案中,POST 使用 javascript 异步完成

http://www.saaraan.com/2012/05/ajax-image-upload-with-progressbar-with-jquery-and-php

1.3. HTML 5 上传

现代浏览器支持 HTML5,它允许非常漂亮且用户友好的上传遮罩,带有进度条和预览 - 边框是您自己的创意

例如,我非常喜欢这个演示:http ://html5demos.com/dnd-upload

在服务器端

无论您决定使用哪种上传技术,上传最终都会以 HTTP POST 的形式发送到您的脚本。所有进一步的处理都将在服务器上完成。

PHP 将文件复制到临时路径 ( upload_tmp_dir )

您可以在 php.ini 中或使用ini_set即时调整一些其他与上传相关的设置:http : //php.net/manual/en/ini.core.php#ini.sect.file-上传

上传.php

<pre>
<?php
print_r( $_FILES );

这是$_FILES成功上传后超全局的样子。

  • 名称:原名
  • type:浏览器提供的 mime 类型
  • 大小:以字节为单位的大小
  • tmp_name:服务器上的临时文件名
  • 错误:此处描述的错误代码,当一切都进入文件时为 0

每个文件都有自己的索引

Array
( 
    [userFile1] => Array
    (
         [name] => i_love_ponies.png
         [type] => image/png
         [size] => 42233
         [tmp_name] => /tmp/_x123tfsdayx134
         [error] => 0
    )
    [userFile2] => Array
    (
         [name] => ponies_run_my_server.png
         [type] => image/png
         [size] => 12325
         [tmp_name] => /tmp/_x3123asdad3ssy
         [error] => 0
    )
)

一些额外的提示

如果您期待大文件,请考虑 webserver 和 php 执行超时。如果上传需要 10 分钟,您不希望您的用户最终出错。

在 PHP 中,您可以增加max_execution_time

2. 验证

您可能想问的问题

我是否只想允许特定文件 - 我收到什么样的文件?

您在$_FILES数组中找到的类型由浏览器设置。如果您想确定上传的是哪种类型,您可以使用PHP的fileinfo 扩展名。

此示例将检查上传本身是否成功,并将允许类型的文件写入新数组以进行进一步处理

$allowedTypes = array(
   'image/png'
   'image/gif'
   'image/jpeg'
);

$useFiles = array();

$finfo = new finfo(FILEINFO_MIME_TYPE);
foreach ( $_FILES as $index => $file )
{
    if ( $file['error'] === UPLOAD_ERR_OK ) {
        $type = $finfo->file( $file['tmp_name'] );
        if ( in_array( $type, $allowedTypes ) ) {
             $useFiles[$index] = $file;
        }
    }
}

我要设置最大文件大小 - 大小是多少?

在这种情况下,您可以放心地依赖该$_FILES['key']['size']值,即字节大小。您不应该仅仅依赖客户端设置的文件大小限制

如果谈论图像,我是否要缩放或创建缩略图 - 图像尺寸是多少?

查看getimagesize以确定图像尺寸

3. 加工

在将文件保存到最终位置之前,您可能需要对其进行一些处理。那是你可以的时候

用于图像处理的常用库是gd libimagick。我个人更喜欢 gd lib。它需要更多的手动工作,但速度更快,并且默认情况下与大多数安装一起提供,或者附加安装很简单。Imagemagick 原生拥有非常庞大的图像处理功能池

4. 存储您的数据

现在是时候谈谈存储了。首先是一种将临时文件复制到临时或最终位置的保存方式。

你应该使用move_uploaded_file

move_uploaded_file( $useFiles['tmp_name'], $destination );

同样,存储没有“最佳方式”,这取决于您的环境、文件和使用。我会讲几个

4.1。服务器文件系统

这可能是存储文件最常用和最简单的方法。您可以简单地使用已经运行的网络服务器静态地提供文件。这通常是文档根目录中的一个位置。

为了让您的生活更轻松,您可以将文件名保存到数据库中 - 最好引用或由连接的数据(如用户或位置)引用。

出于各种原因,您不应将所有文件保存到同一个文件夹中。

您必须为每个文件生成一个唯一名称,否则您会用新文件覆盖现有文件。随着节点中文件数量的增加,通常的文件系统也变得越来越慢。当请求传递文件时,这将导致响应时间变慢。

您可以将其保存到每个用户的文件夹中

/uploaded/user-id/file.jpg

如果您希望每个用户有很多文件,您可以拆分 filname 的校验和以获得更深的文件夹结构

例如

$path =  $_SERVER['DOCUMENT_ROOT'] . '/uploaded/' . $userId . '/' . chunk_split( md5( $useFiles['index']['name'] ), 12, '/' );

会导致

/var/www/htdocs/uploaded/1/97e262286853/d52aa8c58eb7/f0431f03/

4.2. 数据库

您可以使用 blob 类型将文件存储到 MySQL 数据库中。我一般不推荐这个

4.3. 内容分发网络

如果您预计全球会有大量流量,您可能需要考虑将文件存储在带有 Cloudfront的Amazon S3等 CDN 上。

S3 是一种便宜、可靠的存储设备,可存储高达 5TB 的文件(据我所知)

http://www.9lessons.info/2012/08/upload-files-to-amazon-s3-php.html

您不必担心文件备份、可用硬盘大小、交付速度等。Cloudfront在 S3 之上添加了一个 CDN 层,边缘位置遍布全球

于 2012-12-20T12:57:37.460 回答