http - PHP PUT方式传文件的话,如何获取文件内容呢 ?
问题描述
最近因为在做前后端分离,后端PHP
所有Api都使用RESTFul
风格。
但是在使用PUT
上传文件的时候,发现$_FILES
没有文件信息(可能没有上传临时文件,待验证),使用POST
是可以的,并且PUT
从标准输入流
获取过来的数据,读取出来是下面这种格式(上面我猜测没有上传临时文件,是因为看标准输入流里面存着文件信息),需要另外解析。
#获取到的输入流内容
------WebKitFormBoundarybzEhWNCqbo9qKZBX
Content-Disposition: form-data; name="upload"; filename="一些不错的职位.md"
Content-Type: text/markdown
xxxx
xxxx
xxxx
------WebKitFormBoundarybzEhWNCqbo9qKZBX--
目前我的思路是两个:
如果
上传
临时文件(这个正在测试...): 如果上传了,可以读临时文件。如果
不上传
临时文件:尝试解析这串form-data
传过来的参数,但我不知道这种格式php
有没有对应方法进行解析。
顺带吐槽下,RESTFul用起来经常会有问题:
在跨域的时候,普通的form表单(GET, POST)没问题,但是使用PUT,DELETE的话,需要设置跨域头。
PS:不明白,为什么需要?MDN HTTP Method文档竟然没有
PUT
,DELETE
的详细介绍...PHP获取
PUT
,DELETE
需要到file_get_contents('php://input');
获取参数信息,没有类似$_PUT
,$_DELETE
的全局变量。
============= [ 22:01 ] ===================
到stackoverflow
逛了下,发现不少碰到相同问题的,暂时没看到比较好的解决方案。
补充下,这篇文章jquery ajax put file, php save file,博主和我碰到了一样的问题,不过他是通过用正则来解析处理数据的。
我在想,有没有比较好的方案,能够模仿PHP
处理POST
请求一样,把form-data
串,解析出来,普通参数,存到$_PUT
($_POST
), 文件传到临时目录,然后返回文件信息到$_FILES
.
============ [ 10-10 10:16 ] ===================
这片博文如何使用multipart/form-data格式上传文件,有讲到form-data的格式。
目前先自己简单写一个解析form-data
的composer
组件。
============ [ 10-10 16:24 ] ====================
简单写了个解析form-data的类
默认直接获取文件内容(除文件外其他参数,默认使用json串传输)。
如果配置了$option['saveFile']=true
,保存临时文件,返回临时文件路径。
class FormDataParser
{
private static $partSize = 4096; //每次最大获取字节
/**
* 负责解析FormData
*/
public static function parser($options = [])
{
//$options['saveFile'] = true; 测试能否正常保存临时文件
$formData = fopen("php://input", "r");
$retData = [];
$boundary = rtrim(fgets($formData), "\r\n"); //第一行是boundary
$info = []; //info段的信息
$data = ''; //拼接的数据
$infoPart = true; //是否是info段
while ($line = fgets($formData, self::$partSize)) {
if ($boundary . "\r\n" == $line || $boundary . "--\r\n" == $line) {
//如果是分割
$infoPart = true;
if ($info['type'] == 'json') {
$data = json_decode($data, true);
$retData[$info['name']] = $data;
} else if($info['type'] == 'file') {
if(isset($info['tmp_file'])) {
fclose($info['file_handle']);
$retData[$info['name']] = [
'org_name' => $info['org_name'],
'tmp_file' => $info['tmp_file']
];
} else {
$retData[$info['name']] = $data;
}
}
$data = '';
} else if ("\r\n" == $line) {
if ($infoPart) {
//解析info
$info = self::parserInfo($data, $options);
if (isset($info['tmp_file'])) {
$info['file_handle'] = fopen($info['tmp_file'], 'w');
}
$data = '';
$infoPart = false;
}
} else {
if($infoPart == false && isset($info['tmp_file'])) {
fwrite($info['file_handle'], $line);
} else {
$data .= $line;
}
}
}
fclose($formData);
print_r($retData);
}
private static function parserInfo($data, $options)
{
//获取参数名称, type
$infoPattern = '/name="(.+?)"(; )?(filename="(.+?)")?/'; //todo: 待优化
preg_match($infoPattern, $data, $matches);
$info['name'] = $matches[1];
$info['type'] = 'json';
//如果是文件
if (count($matches) > 4) {
$info['type'] = 'file';
$info['org_name'] = $matches[4];
//如果设置保存文件, 保存到临时文件
if (isset($options['saveFile']) && $options['saveFile']) {
$tmpFile = tempnam(sys_get_temp_dir(), 'FD');
$info['tmp_file'] = $tmpFile;
}
}
return $info;
}
}
PHP的全局变量$_FILES只能获取post方式上传的文件,若你要使用put 来上传文件,你必须自己处理该stream
这篇关于http - PHP PUT方式传文件的话,如何获取文件内容呢 ?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!