Skip to content

Commit 0e97dfc

Browse files
committed
opz: (http) Make the behavior of formdata consistent with that of fpm.
1 parent 7c50ecf commit 0e97dfc

2 files changed

Lines changed: 158 additions & 223 deletions

File tree

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
<?php declare(strict_types=1);
2+
/**
3+
* Copyright © 2024 cclilshy
4+
* Email: jingnigg@gmail.com
5+
*
6+
* This software is licensed under the MIT License.
7+
* For full license details, please visit: https://opensource.org/licenses/MIT
8+
*
9+
* By using this software, you agree to the terms of the license.
10+
* Contributions, suggestions, and feedback are always welcome!
11+
*/
12+
13+
namespace Ripple\Net\Http\Server\Upload;
14+
15+
use Ripple\Net\Exception\FormatException;
16+
use Ripple\Runtime\Exception\RuntimeException;
17+
18+
use function fclose;
19+
use function fopen;
20+
use function strpos;
21+
use function substr;
22+
use function sys_get_temp_dir;
23+
use function uniqid;
24+
use function preg_match;
25+
use function sprintf;
26+
use function fwrite;
27+
use function var_dump;
28+
29+
/**
30+
* Http upload parser
31+
*/
32+
class Multipart
33+
{
34+
private const STATUS_WAITING_META = 0;
35+
36+
private const STATUS_TRAN = 1;
37+
38+
/**
39+
* @var int
40+
*/
41+
private int $status = Multipart::STATUS_WAITING_META;
42+
43+
/**
44+
* @var array|null
45+
*/
46+
private array|null $filling = null;
47+
48+
/**
49+
* @var string
50+
*/
51+
private string $buffer = '';
52+
53+
/**
54+
* 上传文件
55+
* @param string $boundary
56+
*/
57+
public function __construct(private readonly string $boundary)
58+
{
59+
}
60+
61+
/**
62+
* CONTEXT PUSH
63+
* @param string $content
64+
* @return array
65+
* @throws FormatException
66+
*/
67+
public function fill(string $content): array
68+
{
69+
$this->buffer .= $content;
70+
$files = array();
71+
72+
do {
73+
if ($this->status === Multipart::STATUS_WAITING_META) {
74+
if ($meta = $this->parseMeta()) {
75+
$meta['path'] = sprintf('%s/%s/%s', sys_get_temp_dir(), '/', uniqid());
76+
$meta['stream'] = fopen($meta['path'], 'wb+');
77+
$this->filling = $meta;
78+
79+
$this->status = Multipart::STATUS_TRAN;
80+
}
81+
}
82+
83+
if ($this->status === Multipart::STATUS_TRAN) {
84+
$meta = $this->filling;
85+
86+
$buffer = $this->readBuffer();
87+
$boundaryPosition = strpos($buffer, "--{$this->boundary}");
88+
if ($boundaryPosition !== false) {
89+
$buffer = substr($buffer, 0, $boundaryPosition - 2);
90+
$this->buffer = substr($buffer, $boundaryPosition);
91+
}
92+
93+
// 填充文件
94+
fwrite($meta['stream'], $buffer);
95+
96+
if ($boundaryPosition !== false) {
97+
// 释放文件
98+
fclose($meta['stream']);
99+
unset($meta['stream']);
100+
$files[$meta['name']][] = $meta;
101+
$this->filling = null;
102+
103+
$this->status = Multipart::STATUS_WAITING_META;
104+
continue;
105+
}
106+
}
107+
108+
break;
109+
} while (1);
110+
111+
return $files;
112+
}
113+
114+
/**
115+
* 解析文件元信息
116+
* @return array|false
117+
* @throws FormatException
118+
*/
119+
private function parseMeta(): array|false
120+
{
121+
$headerEnd = strpos($this->buffer, "\r\n\r\n");
122+
if ($headerEnd === false) {
123+
return false;
124+
}
125+
126+
$header = substr($this->buffer, 0, $headerEnd);
127+
$re = '/^Content-Disposition:\x20*form-data\x20*;\x20*name="([^"]+)"\x20*;?\x20*(?:filename="([^"]*)")?\x20*(?:\r?\nContent-Type:\x20*(.+))?\r?\n/umi';
128+
if (!preg_match($re, $header, $matches)) {
129+
var_dump($header);
130+
throw new RuntimeException('not match meta information');
131+
}
132+
133+
$this->buffer = substr($this->buffer, $headerEnd + 4);
134+
return array(
135+
'name' => $matches[1] ?? null,
136+
'fileName' => $matches[2] ?? null,
137+
'contentType' => $matches[3] ?? null,
138+
);
139+
}
140+
141+
/**
142+
* 读取缓冲区数据
143+
* @param int $length 读取长度
144+
* @return string 读取的数据
145+
*/
146+
private function readBuffer(int $length = 0): string
147+
{
148+
if ($length === 0) {
149+
$buffer = $this->buffer;
150+
$this->buffer = '';
151+
return $buffer;
152+
}
153+
154+
$buffer = substr($this->buffer, 0, $length);
155+
$this->buffer = substr($this->buffer, $length);
156+
return $buffer;
157+
}
158+
}

src/Net/Http/Server/Upload/Multipart.php

Lines changed: 0 additions & 223 deletions
This file was deleted.

0 commit comments

Comments
 (0)