一、前言
写这篇博客的原因是因为,在上传文件的时候,我们都知道要用$_FILES
变量来获取上传的内容,但是$_FILES
是什么使用开始有值的呢?我们上传的是二进制参数,为什么在后台不能通过$_POST
打印出来呢?
这些疑问一直困扰着博主,总感觉是知其然不知其所以然,这次就来好好的研究下$_FILES
。
二、问题的产生,后端无法打印上传的参数
1、首先POST上传的参数如下:
files(binary) //F12看到的参数是这样的,binary代表是二进制的文件流
2、后端打印files参数
var_dump($_POST); //发现没有files参数
3、打印input[type=file]的value
C:\fakepath\job.json //并不是php的tmp临时文件,和咱们平时打印$_FILES看到的不一样
4、打印$_FILES返回数据,代表文件已经传过去了
问题: 那么什么时候$_FILES开始有值的呢?我们传递的files参数又去哪里了,为什么是打印是空
三、$_FILES是如何获取内容的呢
博主在网上查了很多,大部分博客都是简单的介绍下$_FILES
的内容参数,并没有解释这个东西是怎么来的,直到碰到鸟哥的一篇文章,博主才幡然醒悟。
鸟哥博客:http://www.laruence.com/2009/09/26/1103.html
1、大概解释
在客户端执行上传之后,不管是ajax
还是普通表单还是formData
,本质上都是通过http
上传的,php
会获取http
的头部,并且识别出来这个是上传操作,然后找到rfc1867
的处理函数rfc1867_post_handler
, 从而调用这个handler
, 来分析POST
来的数据。
关于rfc1867参考:https://blog.csdn.net/yizhou35/article/details/12358325
2、流程
分析数据可以简单分为:
(1)区分普通数据和文件上传数据(是否有name
,是否有filename
)
(2)读取用户上传的部分自定义设置,如MAX_FILE_SIZE
.
(3)如果是文件上传,就调用代码生成一个临时文件,返回文件名
(4)验证文件名称合法,name
合法等
(5)读取文件内容,写入到临时文件,生成FILE
变量,有命名的上传,如images
,则设置$_FILES['images'] =
文件信息,大小吗,临时目录等,没有命名上传的话,则为$_FILES['tmp_name']
这样就能解释的通了,原来这个$_FILES
变量是php
解析传过来的数据,在有文件上传的时候,通过一系列操作赋值进去的。
四、那么为什么打印files变量为空
这部分本来是一直不理解,后来发现在php
处理解析POST
传过来的数据的时候,是把普通数据和文件流数据分开处理的,是if和elseif
的关系,生成的变量也是不一样的。然后可以参考:
鸟哥的博客:http://www.laruence.com/2008/11/07/581.html
在处理完数据之后,后续的$_POST
大变量生成的时候,是只针对普通的数据,而传过去的文件数据是写入到了$_FILES
里面的。
这样的话,相当于POST
中的文件流被php
特殊处理了,并且和普通的参数进行了区分,赋值为$_FILES
变量。具体代码可以参考(PS:这是c的代码,博主看不懂,只能看个大概,哈哈):
if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) {
char *pair=NULL;
int end=0;
while (isspace(*cd)) {
++cd;
}
while (*cd && (pair = php_ap_getword(&cd, ';')))
{
char *key=NULL, *word = pair;
while (isspace(*cd)) {
++cd;
}
if (strchr(pair, '=')) {
key = php_ap_getword(&pair, '=');
//--------------这里开始处理出具
if (!strcasecmp(key, "name")) {
//获取name字段
if (param) {
efree(param);
}
param = php_ap_getword_conf(&pair TSRMLS_CC);
} else if (!strcasecmp(key, "filename")) { //----------------这里处理文件流数据
//获取filename字段
if (filename) {
efree(filename);
}
filename = php_ap_getword_conf(&pair TSRMLS_CC);
}
}
if (key) {
efree(key);
}
efree(word);
}
这下世界都安静了,咱们的疑问全部得到解决。不得不说,看源码是一种很好的方式,只可惜博主水平不够,只能看着别人分析源码的博客来解决自己的问题。不过这种找到原理的感觉是真的不错,从此不再是“知其然,不知其所以然”!
end