用户级多部分/表单数据处理程序 [英] userland multipart/form-data handler

查看:56
本文介绍了用户级多部分/表单数据处理程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一个剖析multipart/form-data并从中填充$_POST(+ raw)和$_FILES的嵌入式包含脚本/类.通常,PHP会自行完成.但是因为自动处理对我来说是不够的,并且使 php://input 无法访问 [1] 我可能会使用类似的方法来防止

I'm looking for a drop-in include script / class that dissects multipart/form-data and fills up $_POST(+raw) and $_FILES from it. Usually PHP does that itself. But because the automatic handling is insufficient for me and makes php://input inaccesible[1] I'll probably be using something like this to prevent that:

RewriteRule .* - [E=CONTENT_TYPE:noparsing/for-you-php]
无法正常工作.实际的解决方案需要mod_headers和RequestHeader set ...

RewriteRule .* - [E=CONTENT_TYPE:noparsing/for-you-php]
Does not work. Actual solution requires mod_headers and RequestHeader set...

提取过程可能并不那么复杂.但是,我宁愿使用经过充分测试的解决方案.最重要的是,我更喜欢使用fgets进行拆分并模仿$_FILES紧密高效处理的实现.对于我来说,找到二进制有效载荷的末尾似乎比较棘手,特别是当您必须剥离\r\n但可能遇到仅发送\n的客户端(不允许,但可能)时.

The extracting procedure might not be that complex. But I'd rather use a well-tested solution. And foremost I would prefer an implementation that uses fgets for splitting, and mimics the $_FILES handling closely and efficiently. Finding the end of binary payloads would seem rather tricky to me, in particular when you have to strip off \r\n but might encounter clients that only send \n (not allowed, but possible).

我确定类似的东西存在.但是我在搜索它时遇到了困难.有人知道实现吗? (PEAR :: mimeDecode可以被黑客破解以获取某种形式的数据,但这只是一个内存消耗.)

I'm certain something like this exists. But I'm having a hard time googling it. Does anyone know an implementation? (PEAR::mimeDecode can be hacked to get sort of working for form-data, but is a memory hog.)

简而言之,用例:需要保留原始字段名称(包括空格和特殊字符)以进行日志记录,但不能总是避免文件上传.

The use case in short: need to preserve the raw field names (including whitespace and special characters), for logging, but can't avoid file uploads always.

出于装饰目的,这就是POST请求的外观:

For decorative purposes, that's how a POST request looks:

POST / HTTP/1.1
Host: localhost:8000
Content-Length: 17717
Content-Type: multipart/form-data; boundary=----------3wCuBwquE9P7A4OEylndVx

\r\n\r\n序列之后,multipart/有效负载如下:

And after a \r\n\r\n sequence the multipart/ payload follows like this:

------------3wCuBwquE9P7A4OEylndVx
Content-Disposition: form-data; name="_charset_"

windows-1252
------------3wCuBwquE9P7A4OEylndVx
Content-Disposition: form-data; name=" text field \\ 1 \";inject=1"

text1 te twj sakfkl
------------3wCuBwquE9P7A4OEylndVx
Content-Disposition: form-data; name="file"; filename="dial.png"
Content-Type: image/png

IPNG Z @@@MIHDR@@B`@@B;HF@@@-'.e@@@AsRGB@.N\i@@@FbKGD@?@?@? ='S@@@     
@@@GtIMEGYAAU,#}BRU@@@YtEXtComment@Created with GIMPWANW@@ @IDATxZl]w|

推荐答案

已经很晚了,目前我无法测试,但是以下内容可以满足您的要求:

It's late and I can't test this at the moment but the following should do what you want:

//$boundary = null;

if (is_resource($input = fopen('php://input', 'rb')) === true)
{

    while ((feof($input) !== true) && (($line = fgets($input)) !== false))
    {
        if (isset($boundary) === true)
        {
            $content = null;

            while ((feof($input) !== true) && (($line = fgets($input)) !== false))
            {
                $line = trim($line);

                if (strlen($line) > 0)
                {
                    $content .= $line . ' ';
                }

                else if (empty($line) === true)
                {
                    if (stripos($content, 'name=') !== false)
                    {
                        $name = trim(stripcslashes(preg_replace('~.*name="?(.+)"?.*~i', '$1', $content)));

                        if (stripos($content, 'Content-Type:') !== false)
                        {
                            $tmpname = tempnam(sys_get_temp_dir(), '');

                            if (is_resource($temp = fopen($tmpname, 'wb')) === true)
                            {
                                while ((feof($input) !== true) && (($line = fgets($input)) !== false) && (strpos($line, $boundary) !== 0))
                                {
                                    fwrite($temp, preg_replace('~(?:\r\n|\n)$~', '', $line));
                                }

                                fclose($temp);
                            }

                            $FILES[$name] = array
                            (
                                'name' => trim(stripcslashes(preg_replace('~.*filename="?(.+)"?.*~i', '$1', $content))),
                                'type' => trim(preg_replace('~.*Content-Type: ([^\s]*).*~i', '$1', $content)),
                                'size' => sprintf('%u', filesize($tmpname)),
                                'tmp_name' => $tmpname,
                                'error' => UPLOAD_ERR_OK,
                            );
                        }

                        else
                        {
                            $result = null;

                            while ((feof($input) !== true) && (($line = fgets($input)) !== false) && (strpos($line, $boundary) !== 0))
                            {
                                $result .= preg_replace('~(?:\r\n|\n)$~', '', $line);
                            }

                            if (array_key_exists($name, $POST) === true)
                            {
                                if (is_array($POST[$name]) === true)
                                {
                                    $POST[$name][] = $result;
                                }

                                else
                                {
                                    $POST[$name] = array($POST[$name], $result);
                                }
                            }

                            else
                            {
                                $POST[$name] = $result;
                            }
                        }
                    }

                    if (strpos($line, $boundary) === 0)
                    {
                        //break;
                    }
                }
            }
        }

        else if ((is_null($boundary) === true) && (strpos($line, 'boundary=') !== false))
        {
            $boundary = "--" . trim(preg_replace('~.*boundary="?(.+)"?.*~i', '$1', $line));
        }
    }

    fclose($input);
}

echo '<pre>';
print_r($POST);
echo '</pre>';

echo '<hr />';

echo '<pre>';
print_r($FILES);
echo '</pre>';

这篇关于用户级多部分/表单数据处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆