使用PHP手动解析原始HTTP数据 [英] Manually parse raw HTTP data with PHP

查看:545
本文介绍了使用PHP手动解析原始HTTP数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我似乎找不到这个问题的真正答案,所以这里我去:



如何解析PHP中的原始HTTP请求数据?我知道,如果格式正确,自动解析原始POST,但我所指的数据来自一个PUT请求,这不是由PHP自动解析。数据是multipart,看起来像:

  ----------------- ------------- b2449e94a11c 
Content-Disposition:form-data; name =user_id

3
------------------------------ b2449e94a11c
Content-Disposition:form-data; name =post_id

5
------------------------------ b2449e94a11c
Content-Disposition:form-data; name =image; filename =/ tmp / current_file
Content-Type:application / octet-stream

JFIF ...一堆二进制数据

我使用libcurl发送数据像这样(伪代码):

  curl_setopt_array(
CURLOPT_POSTFIELDS => array(
'user_id'=> 3,
'post_id '=> 5,
'image'=>'@ / tmp / current_file'),
CURLOPT_CUSTOMREQUEST =>'PUT'
);

如果我删除CURLOPT_CUSTOMREQUEST位,请求将作为POST在服务器上处理,一切都被解析只是很好。



有没有办法手动调用PHP的HTTP数据解析器或一些其他好的方法这样做?
是的,我必须以PUT发送请求:)

解决方案

我决定手动解析原始请求数据。我没有找到任何其他的方式,这样做后搜索约一天。



我从这里获得了一些帮助线程。我没有任何运气篡改原始数据,像他们在被引用的线程,因为这将打破上传的文件。所以这是所有正则表达式。这没有测试得很好,但似乎工作在我的工作。没有什么东西,希望这可能有助于别人有一天:

  function parse_raw_http_request(array& $ a_data)
{
//读入数据
$ input = file_get_contents('php:// input');

//从内容类型头获取多部分边界
preg_match('/ boundary =(。*)$ /',$ _SERVER ['CONTENT_TYPE'],$ matches)
$ boundary = $ matches [1];

//根据边界拆分内容,除去最后一个元素
$ a_blocks = preg_split(/ - + $ boundary /,$ input);
array_pop($ a_blocks);

//循环数据块
foreach($ a_blocks as $ id => $ block)
{
if(empty($ block))
继续;

//你必须var_dump $ block才能理解这一点,并且可以用可见性替换\\\
或\r char

//解析上传的文件
if(strpos($ block,'application / octet-stream')!== FALSE)
{
//匹配name,然后stream换行符
preg_match(/ name = \([^ \] *)\。* stream [\\\
| \r] +([^ \\\
\r]。 *)?$ / s,$ block,$ matches);
}
//解析所有其他字段
else
{
// matchname和在换行符序列之间的可选值
preg_match('/ name = \([^ \] *)\[\\\
| \r] +([^ \\\
\ r]。*)?\r $ / s',$ block,$ matches);
}
$ a_data [$ matches [1]] = $ matches [2];
}
}

数据太多):

  $ a_data = array 
parse_raw_http_request($ a_data);
var_dump($ a_data);

编辑:见下面的Jas回答,他添加了对多个文件和一些其他功能的支持。 p>

I can't seem to find a real answer to this problem so here I go:

How do you parse raw HTTP request data in PHP? I know that raw POST is automatically parsed if formatted correctly, but the data I'm referring to is coming from a PUT request, which is not being parsed automatically by PHP. The data is multipart and looks something like:

------------------------------b2449e94a11c
Content-Disposition: form-data; name="user_id"

3
------------------------------b2449e94a11c
Content-Disposition: form-data; name="post_id"

5
------------------------------b2449e94a11c
Content-Disposition: form-data; name="image"; filename="/tmp/current_file"
Content-Type: application/octet-stream

�����JFIF���������... a bunch of binary data

I'm sending the data with libcurl like so (pseudo code):

curl_setopt_array(
  CURLOPT_POSTFIELDS => array(
    'user_id' => 3, 
    'post_id' => 5, 
    'image' => '@/tmp/current_file'),
  CURLOPT_CUSTOMREQUEST => 'PUT'
  );

If I drop the CURLOPT_CUSTOMREQUEST bit, the request is handled as a POST on the server and everything is parsed just fine.

Is there a way to manually invoke PHPs HTTP data parser or some other nice way of doing this? And yes, I have to send the request as PUT :)

解决方案

Ok, so with Dave and Everts suggestions I decided to parse the raw request data manually. I didn't find any other way to do this after searching around for about a day.

I got some help from this thread. I didn't have any luck tampering with the raw data like they do in the referenced thread, as that will break the files being uploaded. So it's all regex. This wasnt't tested very well, but seems to be working for my work case. Without further ado and in the hope that this may help someone else someday:

function parse_raw_http_request(array &$a_data)
{
  // read incoming data
  $input = file_get_contents('php://input');

  // grab multipart boundary from content type header
  preg_match('/boundary=(.*)$/', $_SERVER['CONTENT_TYPE'], $matches);
  $boundary = $matches[1];

  // split content by boundary and get rid of last -- element
  $a_blocks = preg_split("/-+$boundary/", $input);
  array_pop($a_blocks);

  // loop data blocks
  foreach ($a_blocks as $id => $block)
  {
    if (empty($block))
      continue;

    // you'll have to var_dump $block to understand this and maybe replace \n or \r with a visibile char

    // parse uploaded files
    if (strpos($block, 'application/octet-stream') !== FALSE)
    {
      // match "name", then everything after "stream" (optional) except for prepending newlines 
      preg_match("/name=\"([^\"]*)\".*stream[\n|\r]+([^\n\r].*)?$/s", $block, $matches);
    }
    // parse all other fields
    else
    {
      // match "name" and optional value in between newline sequences
      preg_match('/name=\"([^\"]*)\"[\n|\r]+([^\n\r].*)?\r$/s', $block, $matches);
    }
    $a_data[$matches[1]] = $matches[2];
  }        
}

Usage by reference (in order not to copy around the data too much):

$a_data = array();
parse_raw_http_request($a_data);
var_dump($a_data);

Edit: see Jas' answer below, he added support for multiple files and some other functionality.

这篇关于使用PHP手动解析原始HTTP数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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