且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

使用PHP手动解析原始multipart / form-data数据

更新时间:2022-03-31 07:40:45

好的,所以Dave和Everts建议我决定手动解析原始请求数据。在搜索了大约一天后,我没有找到任何其他方法来做到这一点。

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);

编辑:这个答案在7年后仍然会定期点击。从那以后我从未使用过此代码,并且不知道这些天是否有更好的方法。请查看下面的评论,并了解有许多情况下此代码无效。使用风险由您自己承担。

this answer is still getting regular hits 7 years later. I have never used this code since then and do not know if there is a better way to do it these days. Please view the comments below and know that there are many scenarios where this code will not work. Use at your own risk.