一、文件上传

为了让客户端的用户能够上传文件,我们必须在用户界面中提供一个表单用于提交上传文件的请求。由于上传的文件是一种特殊数据,不同于其它的post数据,所以我们必须给表单设置一个特殊的编码:

以上的enctype属性,你可能不太熟悉,因为这常常会被忽略掉。但是,如果http post请求中既有常规数据,又包含文件类数据的话,这个属性就应该显示加上,这样可以提高针对各种浏览器的兼容性。

接下来,我们得向表单中添加一个用于上传文件的字段:

上述文件字段在各种浏览器中可能表现会有所不同。对于大多数的浏览器,上述字段都会被渲染成一个文本框加上一个浏览按钮。这样,用户既可以自行输入文件的路径到文本框中,也可以通过浏览按钮从本地硬盘上选择所要上传的文件。但是,在苹果的Safari中,貌似只能使用浏览这种方式。当然,你也可以自定义这个上传框的样式,使它看起来比默认的样式优雅些。

下面,为了更好的阐述怎么样处理文件上传,举一个完整的例子。比如,以下一个表单允许用户向我的本地服务器上上传附件:

请上传你的附件:

提示:可以通过php.ini中的upload_max_filesize来设置允许上传文件的最大值。另外,还有一个post_max_size也可以用来设置允许上传的最大表单数据,具体意思就是表单中各种数据之和,所以你也可以通过设置这个字段来控制上传文件的最大值。但是,注意后者的值必须大于前者,因为前者属于后者的一部分表单数据。

图1. 显示在在firefox中的上传表单

当这个表单提交的时候,http请求会被发送到upload.php。为了显示具体哪些信息可以在upload.php中使用,我在upload.php将其打印出来:

header('Content-Type: text/plain');

print_r($_FILES);

下面来做个试验,假如我通过以上表单上传一个本博客的logo到我的本地服务器www.360weboy.me/upload.php,看看在upload.php中会输出什么信息:

Array

(

[attachment] => Array

(

[name] => boy.jpg

[type] => image/jpeg

[tmp_name] => D:\xampp\tmp\php1168.tmp

[error] => 0

[size] => 11490

)

)

以上就是文件上传后,在全局数组中的关于当前上传文件的所有信息。但是,我们是否能够保证这些信息是安全的,假如name或者其它信息被篡改过了呢?我们时刻需要对来自客户端的信息保持警惕!

具体的http请求的各个部分

为了更好的理解文件上传,我们必须核对下客户端发送的http请求中到底包含了那些具体的信息。先前我上传的附件是本博客的logo,因为是图片,不太适合我们做以上实验。所以,我重新上传一个test.text文本文件,其中具体包含了以下内容:

360w

360days

Life Of A Web Boy

Okay。现在我上传这个文本文件,在upload.php中会输出:

Array

(

[attachment] => Array

(

[name] => test.txt

[type] => text/plain

[tmp_name] => D:\xampp\tmp\php51C0.tmp

[error] => 0

[size] => 40

)

)

我们再来看下相关的浏览器发送的http post请求(一些可选的头部我省略了):

POST /upload.php HTTP/1.1

Host: www.360weboy.me

Referer: http://www.360weboy.me/

multipart/form-data; boundary=---------------------------24464570528145

Content-Length: 234

-----------------------------24464570528145

Content-Disposition: form-data; name="attachment"; filename="test.txt"

Content-Type: text/plain

360weboy

360days

Life Of A Web Boy

-----------------------------24464570528145--

从上面的请求格式中有几个字段我们要关注下的,分别是name, filename以及Content-Type.它们分别表示上传文件框在form表单中的字段名-attachment,用户从本地硬盘中上传的文件名 – test.txt,以及上传的文件格式 – text/plain(代表文本文件)。然后,我们看到一行空行下面的,就是这个上传文件中的具体内容。

二、安全性的加强

为了加强文件上传中的安全性,我们需要检查下$_FILES全局数组中的tmp_name和size。为了确保tmp_name指向的文件确实是刚刚用户在客户端上传的文件,而不是指向的类似/etc/passwd,可以使用php中的函数is_uploaded_file()来进行下判断:

$filename = $_FILES['attachment']['tmp_name'];

if (is_uploaded_file($filename)) {

/* 是一个上传的文件. */

}

某些情况下,用户上传文件后,可能会将上传成功的文件的内容显示给用户看下,那么上述代码的检查尤其重要。

另外一个需要检查的就是上传文件的mime-type, 也就是上述upload.php中输出数组的type字段。 我在第一个例子中上传的是一个图片,所以$_FILES['attachment']['type']的值为'image/jpeg'。 如果打算在服务器端只接受image/png, image/jpeg, image/gif, image/x-png 以及 image/p-jpeg这些mime-type的图片,可以用类似下面的代码了进行检查(只是举个例子,具体代码,比如报错等,应该遵循你的系统中的机制):

$allow_mimes = array(

'image/png',

'image/x-png',

'image/gif',

'image/jpeg',

'image/pjpeg'

);

$image = $_FILES['attachment'];

if(!in_array($image['type'], $allow_mimes)) {

die('对不起, 你上传的文件格式不准确;我们只接受图片文件.');

}

// 继续处理上传的图片文件

正如你看到的,我们已经保准了文件的mime-type是符合服务器端的要求的。但是,这样是不是就可以防止恶意用户上传其它有害文件,还是不够的,因为这个mime-type恶意用户是可以伪装的。 比如用户做了一张jpg图片,在图片的元数据中写入了一些恶意的php代码,然后保存为后缀名为php的文件。当这个恶意文件上传的时候,将顺利通过服务器端对于mime-type的检查,被认为是一张图片,里面的危险的php代码将会被执行。具体的图片的元数据类似如下:

File name    : image.jpg

File size    : 182007 bytes

File date    : 2012:11:27 7:45:10

Resolution   : 1197 x 478

Comment      : passthru($_POST['cmd']); __halt_compiler();

我们可以看到,在图片元数据的Comment字段中加入了php代码。所以,很显然,为了防止类似危险情况发生,还必须对上传文件的扩展名进行一次必要的检查。下面的代码对前面的检查Mime-type的代码进行了加强:

$allow_mimes = array(

'image/png' => '.png',

'image/x-png' => '.png',

'image/gif' => '.gif',

'image/jpeg' => '.jpg',

'image/pjpeg' => '.jpg'

);

$image = $_FILES['attachment'];

if(!array_key_exists($image['type'], $allow_mimes )) {

die('对不起, 你上传的文件格式不准确;我们只接受图片文件.');

}

// 获取略去后缀名的文件名:

$filename = substr($image['name'], 0, strrpos($image['name'], '.'));

// 添加后缀名

$filename .= $allow_mimes[$image['type']];

// 继续处理上传的文件

通过上述的代码,我们确保即使上传的图片的元文件中包含了php代码的话,图片文件会被重名为后缀名为图片格式的文件,所以其中的php代码也不会被执行了。上述代码对正常的上传的图片也不会有任何负面影响。

进行了上述的几步提高安全性的检查步骤后,如果你只是要把上传的文件保存到一个指定的目录中,那么就可以使用php的默认函数move_uploaded_file来实现了:

$tmp_filename = $_FILES['attachment']['tmp_name'];

$filename = '/path/to/attachment.txt';

if (move_uploaded_file(tmp_filename, $filename)) {

/* $temp_filename 保存在临时目录中的上传文件, 然后成功将其保存到对应目录下的attachment.txt文件中. */

}

你也许还要对上传文件的大小进行限制,那么你可以通过filesize函数来获取上传文件的大小,进行判断后做进一步处理,这具体就不在这将了,自己去折腾吧。

好了,关于文件上传暂时就写到这里吧。希望这篇入门篇文章对你有所帮助。

php文件教程,php的文件上传入门教程(实例讲解)相关推荐

  1. Linux用管道移动文件夹,常用的Linux上的文件管理类命令讲解及演示

    01. 查看目录内容 1.1 终端实用技巧 1> 自动补全在敲出 文件/目录/命令 的前几个字母之后,按下 tab 键 如果输入的没有歧义,系统会自动补全 如果还存在其他 文件/目录/命令,再按 ...

  2. python上传大文件s3_使用Python boto3上传Windows EC2实例中的文件至S3存储桶中

    一.创建终端节点 为什么要创建终端节点,把VPC和S3管理起来呢?如果不将VPC和S3通过终端节点管理起来,那么VPC中EC2实例访问S3存储桶是通过公共网络的:一旦关联起来,那么VPC中EC2实例访 ...

  3. shell把文件导出 怎么通过adb,adb文件管理命令操作实例讲解

    文件管理命令(FileManger) 1.  adb pull [local] 从一个设备或虚拟机下载一个指定文件到电脑. 不指定下载路径:adb pull /sdcard/Music/Honor.m ...

  4. [网络安全自学篇] 二十八.文件上传入门及防御原理(一)

    这是作者的系列网络安全自学教程,主要是关于安全工具和实践操作的在线笔记,特分享出来与博友共勉,希望您们喜欢,一起进步.前文分享了Sqlmap的基本用法.CTF实战,包括设置HTTP.POST请求.参数 ...

  5. linux ubuntu18.1安装教程,Ubuntu 18.04上Qmmp安装教程

    导读 Qmmp是Ubuntu或其他操作系统的Winamp替代品.它像Winamp一样具有最小的界面.Qmmp是一个开源的.免费的基于qm的多媒体播放器,它不仅适用于Ubuntu,还可以安装在ALT L ...

  6. python饼状图教程_Python数据可视化:饼状图的实例讲解

    使用python实现论文里面的饼状图: 原图: python代码实现: # # 饼状图 # plot.figure(figsize=(8,8)) labels = [u'Canteen', u'Sup ...

  7. pythonappend教程_对python append 与浅拷贝的实例讲解

    在做Leetcode的第39题的时候,看到网上一个用递归的解法,很简洁.于是重写了一遍. class Solution(object): def combinationSum(self, candid ...

  8. html5 上传超大文件,HTML5教程 如何拖拽上传大文件

    本篇教程探讨了HTML5教程 如何拖拽上传大文件,希望阅读本篇文章以后大家有所收获,帮助大家HTML5+CSS3从入门到精通 . < 前言: 大文件传输一直是技术上的一大难点.文件过大时,一些性 ...

  9. Spring Boot 2.x基础教程:多文件的上传

    昨天,我们介绍了如何在Spring Boot中实现文件的上传(博客地址:https://blog.didispace.com/spring-boot-learning-21-4-3/).有读者问:那么 ...

最新文章

  1. 区块链创业者:谈企业级区块链落地,传统行业的崛起(分享实录)
  2. 【TensorFlow-windows】学习笔记七——生成对抗网络
  3. 页面获取Spring Security登录用户
  4. C#.NET 权限管理系统组件 - 大数据读写分离实现的例子
  5. Acad多窗体并排展现
  6. C语言递归方法求解背包问题
  7. linux可运行的steam游戏吗,Steam现在可以在Linux上玩仅Windows游戏
  8. Spring AOP 之 通知、连接点、切点、切面
  9. matlab表示网络,Matlab绘制网络
  10. 松原计算机等级考试试题,2019年上半年吉林省松原市计算机等级考试注意事项...
  11. python cmd环境输入python打开应用商店解决
  12. 【汇正财经】选股有什么策略?如何找到适合自己的选股策略?
  13. P1873 砍树 【二分】
  14. 广电网宽带 如果要远程连接阿里RDS数据库,设置了白名单也不行。
  15. 【转】 Vitalik:去中心化的意涵
  16. PTA 计算谱半径 —— 简单题
  17. Hotel California 加州旅馆
  18. 设置(settings)
  19. dell笔记本安装linux系统安装,Dell笔记本 安装linux系统ubuntu详细指南
  20. linux i2c 多字节读写,基于51单片机i2c多字节的读写

热门文章

  1. MySQL InnoDB Cluster安装
  2. redis 流 stream的使用总结 - 基础命令
  3. RequestMethod的参数的含义是?
  4. leetcode 149. Max Points on a Line |149. 直线上最多的点数(Java)
  5. 如何解决JAVA环境变量配好后,重启电脑又失效的问题
  6. java安全编码指南之:对象构建
  7. java关于throw Exception的一个小秘密
  8. java中线程的生命周期
  9. Flume 1.7 源码分析(二)整体架构
  10. linux操作系统原理_Linux系统从新手到运维老鸟学习指南