http - PHP PUT方式传文件的话,如何获取文件内容呢 ?
PHPz
PHPz 2017-04-11 10:39:10
[PHP讨论组]

最近因为在做前后端分离,后端PHP所有Api都使用RESTFul风格。

但是在使用PUT上传文件的时候,发现$_FILES没有文件信息(可能没有上传临时文件,待验证),使用POST是可以的,并且PUT标准输入流获取过来的数据,读取出来是下面这种格式(上面我猜测没有上传临时文件,是因为看标准输入流里面存着文件信息),需要另外解析。

#获取到的输入流内容

------WebKitFormBoundarybzEhWNCqbo9qKZBX
Content-Disposition: form-data; name="upload"; filename="一些不错的职位.md"
Content-Type: text/markdown

xxxx
xxxx
xxxx

------WebKitFormBoundarybzEhWNCqbo9qKZBX--

目前我的思路是两个:

  1. 如果上传临时文件(这个正在测试...): 如果上传了,可以读临时文件。

  2. 如果不上传临时文件:尝试解析这串form-data传过来的参数,但我不知道这种格式php有没有对应方法进行解析。

顺带吐槽下,RESTFul用起来经常会有问题:

  1. 在跨域的时候,普通的form表单(GET, POST)没问题,但是使用PUT,DELETE的话,需要设置跨域头。
    PS:不明白,为什么需要?

  2. MDN HTTP Method文档竟然没有PUTDELETE的详细介绍...

  3. PHP获取PUTDELETE需要到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-datacomposer组件。

============ [ 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;
    }

}
PHPz
PHPz

学习是最好的投资!

全部回复(6)
大家讲道理

PHP的全局变量$_FILES只能获取post方式上传的文件,若你要使用put 来上传文件,你必须自己处理该stream

高洛峰

手机端来说,目前的主流是 get+post+json

阿神

4,标准的form data上传格式

ringa_lee

php put需要单独解析,另put一般用于接受json格式的数据

PHP中文网

谢谢回答,另外,问题重新编辑了下, :)

ringa_lee

哎,PHP的PUT确实槽点多,所以更新操作我还是用POST...

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号