PluginProbe ʕ •ᴥ•ʔ
Kirki – Freeform Page Builder, Website Builder & Customizer / 6.0.13
Kirki – Freeform Page Builder, Website Builder & Customizer v6.0.13
6.1.1 6.1.0 6.0.14 6.0.13 6.0.12 6.0.11 6.0.10 6.0.9 6.0.8 6.0.7 6.0.6 6.0.5 6.0.4 6.0.3 6.0.2 6.0.1 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 4.0.19 4.0.20 4.0.21 4.0.22 4.0.23 4.0.24 4.1 4.2.0 5.0.0 5.1.0 5.1.1 5.2.0 5.2.1 5.2.2 5.2.3 6.0.0 trunk 3.0.40 3.0.41 3.0.42 3.0.43 3.0.44 3.0.45 3.1.0 3.1.1 3.1.2
kirki / libraries / framework / Http / Client / MultipartStream.php
kirki / libraries / framework / Http / Client Last commit date
MultipartStream.php 3 weeks ago Request.php 3 weeks ago Response.php 3 weeks ago
MultipartStream.php
217 lines
1 <?php
2
3 /**
4 * Builds multipart/form-data request bodies with configurable boundary strings.
5 * Encodes fields and file attachments into a single stream for HTTP client uploads.
6 * Used by the Http client when sending as_multipart requests.
7 *
8 * @package Framework
9 * @subpackage Http\Client
10 * @since 1.0.0
11 */
12 namespace Kirki\Framework\Http\Client;
13
14 \defined('ABSPATH') || exit;
15 use Kirki\Framework\Collections\Collection;
16 use UnexpectedValueException;
17 use function Kirki\Framework\collection;
18 class MultipartStream
19 {
20 /**
21 * The boundary string used to separate parts of the multipart stream.
22 *
23 * @var string
24 *
25 * @since 1.0.0
26 */
27 protected $boundary;
28 /**
29 * The stream of data to be sent.
30 *
31 * @var string
32 *
33 * @since 1.0.0
34 */
35 protected $stream;
36 /**
37 * Create a new MultipartStream instance.
38 *
39 * @param array $data The data to be sent.
40 * @param string|null $boundary The boundary string to use.
41 *
42 * @return void
43 *
44 * @since 1.0.0
45 */
46 public function __construct(array $data, ?string $boundary = null)
47 {
48 $this->boundary = $boundary ?? "MultipartBoundary" . wp_generate_password(20, \false);
49 $this->stream = $this->create_stream($data);
50 }
51 /**
52 * Get the boundary string used to separate parts of the multipart stream.
53 *
54 * @return string The boundary string.
55 *
56 * @since 1.0.0
57 */
58 public function boundary()
59 {
60 return $this->boundary;
61 }
62 /**
63 * Get the stream of data to be sent.
64 *
65 * @return string The stream of data.
66 *
67 * @since 1.0.0
68 */
69 public function payload()
70 {
71 return $this->stream;
72 }
73 /**
74 * Create the stream of data to be sent.
75 *
76 * @param array $data The data to be sent.
77 *
78 * @return string The stream of data.
79 *
80 * @throws \UnexpectedValueException
81 *
82 * @since 1.0.0
83 */
84 protected function create_stream(array $data)
85 {
86 $stream = collection();
87 foreach ($data as $item) {
88 if (!\is_array($item)) {
89 throw new UnexpectedValueException('Invalid data format');
90 }
91 $stream->push($this->create_stream_item($item));
92 }
93 $stream->push("--{$this->boundary}--\r\n");
94 return $stream->join("");
95 }
96 /**
97 * Create a stream item from the given data.
98 *
99 * @param array $item The data to be sent.
100 *
101 * @return string The stream item.
102 *
103 * @throws \UnexpectedValueException
104 *
105 * @since 1.0.0
106 */
107 protected function create_stream_item(array $item)
108 {
109 foreach (['contents', 'name'] as $key) {
110 if (!\array_key_exists($key, $item)) {
111 throw new UnexpectedValueException("Missing {$key} in item");
112 }
113 }
114 $name = $item['name'];
115 $contents = $item['contents'];
116 $filename = $item['filename'] ?? null;
117 $headers = $item['headers'] ?? [];
118 return $this->create_element($name, $contents, $filename, $headers);
119 }
120 /**
121 * Create a stream element from the given data.
122 *
123 * @param string $name The name of the element.
124 * @param string $contents The contents of the element.
125 * @param string|null $filename The filename of the element.
126 * @param array $headers The headers of the element.
127 *
128 * @return string The stream element.
129 *
130 * @since 1.0.0
131 */
132 protected function create_element($name, $contents, ?string $filename = null, array $headers = [])
133 {
134 if (!empty($filename)) {
135 return $this->create_file_stream($name, $contents, $filename, $headers);
136 }
137 return $this->create_field_stream($name, $contents, $headers);
138 }
139 /**
140 * Create a file stream from the given data.
141 *
142 * @param string $name The name of the element.
143 * @param string $contents The contents of the element.
144 * @param string $filename The filename of the element.
145 * @param array $headers The headers of the element.
146 *
147 * @return string The file stream.
148 *
149 * @since 1.0.0
150 */
151 protected function create_file_stream($name, $contents, $filename, array $headers = [])
152 {
153 $headers['Content-Type'] ??= $this->get_mimetype($filename);
154 $headers['Content-Length'] ??= \strlen($contents);
155 $payload = '';
156 $payload .= "--{$this->boundary}\r\n";
157 $payload .= "Content-Disposition: form-data; name=\"{$name}\"; filename=\"{$filename}\"\r\n";
158 $payload .= $this->create_headers($headers);
159 $payload .= $contents . "\r\n";
160 return $payload;
161 }
162 /**
163 * Get the mimetype of the file.
164 *
165 * @param string $filename The filename of the file.
166 *
167 * @return string The mimetype of the file.
168 *
169 * @since 1.0.0
170 */
171 protected function get_mimetype(string $filename)
172 {
173 return wp_check_filetype($filename)['type'] ?? 'application/octet-stream';
174 }
175 /**
176 * Create a field stream from the given data.
177 *
178 * @param string $name The name of the element.
179 * @param string $contents The contents of the element.
180 * @param array $headers The headers of the element.
181 *
182 * @return string The field stream.
183 *
184 * @since 1.0.0
185 */
186 protected function create_field_stream($name, $contents, array $headers = [])
187 {
188 $payload = '';
189 $payload .= "--{$this->boundary}\r\n";
190 $payload .= "Content-Disposition: form-data; name=\"{$name}\"\r\n";
191 if (!empty($headers)) {
192 $payload .= $this->create_headers($headers);
193 } else {
194 $payload .= "\r\n";
195 }
196 $payload .= $contents . "\r\n";
197 return $payload;
198 }
199 /**
200 * Create headers for the stream.
201 *
202 * @param array $headers The headers to create.
203 *
204 * @return string The headers.
205 *
206 * @since 1.0.0
207 */
208 protected function create_headers(array $headers)
209 {
210 $payload = '';
211 foreach ($headers as $name => $header) {
212 $payload .= "{$name}: {$header}\r\n";
213 }
214 return \trim($payload) . "\r\n\r\n";
215 }
216 }
217