PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.3.20
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.3.20
1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 All 49 releases
fluent-cart / vendor / wpfluent / framework / src / WPFluent / Http / Response / Response.php

Response.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.3.20, at vendor/wpfluent/framework/src/WPFluent/Http/Response/Response.php

428 lines 9.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\Framework\Http\Response;
4
5 use DateTime;
6 use WP_Error;
7 use DateTimeInterface;
8 use WP_REST_Response;
9 use FluentCart\Framework\App\App;
10 use InvalidArgumentException;
11 use FluentCart\Framework\Http\Request\File;
12
13 class Response
14 {
15 /**
16 * Response Data
17 * @var mixed
18 */
19 protected $data = null;
20
21 /**
22 * Response Status Code
23 * @var integer
24 */
25 protected $code = 200;
26
27 /**
28 * Response Headers
29 * @var array
30 */
31 protected $headers = [];
32
33 /**
34 * Response Cookies
35 * @var array
36 */
37 protected $cookies = [];
38
39 /**
40 * Construct the response instance.
41 *
42 * @param array $data
43 * @param integer $code
44 * @param array $headers
45 */
46 public function __construct($data = null, $code = 200, $headers = [])
47 {
48 $this->data = $data;
49 $this->code = $code;
50 $this->headers = $headers;
51 }
52
53 /**
54 * Creates an instance of self.
55 *
56 * @param mixed $data
57 * @param integer $code
58 * @param array $headers
59 * @return self
60 */
61 public static function make($data = null, $code = 200, $headers = [])
62 {
63 return new static($data, $code, $headers);
64 }
65
66 /**
67 * Send json response.
68 *
69 * @param array $data
70 * @param integer $code
71 * @return string|false JSON encoded string, or false if fails to encode.
72 */
73 public function json($data = null, $code = 200)
74 {
75 return wp_send_json($data, $code);
76 }
77
78 /**
79 * Send rest response.
80 *
81 * @param mixed $data
82 * @param integer $code
83 * @param array $headers
84 * @return \WP_REST_Response
85 */
86 public function send($data = null, $code = 200, $headers = [])
87 {
88 $response = new WP_REST_Response($data, $code, $headers);
89
90 return $this->maybeMergeHeaders(
91 $this->maybeMergeCookies($response)
92 );
93 }
94
95 /**
96 * Send a success rest response.
97 *
98 * @param mixed $data
99 * @param integer $code
100 * @return \WP_REST_Response
101 */
102 public function sendSuccess($data = null, $code = 200, $headers = [])
103 {
104 return $this->send($data, $code, $headers);
105 }
106
107 /**
108 * Send an error json response
109 * @param array $data
110 * @param integer $code
111 * @return \WP_REST_Response
112 */
113 public function sendError($data = null, $code = 422, $headers = [])
114 {
115 $code = $code < 400 ? 422 : $code;
116
117 return $this->send($data, $code, $headers);
118 }
119
120 /**
121 * Convert the WP_Error to WP_REST_Response
122 *
123 * @param \WP_Error $wpError
124 * @return \WP_REST_Response
125 */
126 public function wpErrorToResponse(WP_Error $wpError)
127 {
128 return rest_convert_error_to_response($wpError);
129 }
130
131 /**
132 * Set response headers
133 * @param string|array $key
134 * @param string|null $value
135 * @return self
136 */
137 public function withHeader($key, $value = null)
138 {
139 if (is_array($key) && !$value) {
140 $this->headers = array_merge($this->headers, (array) $key);
141 } else {
142 $this->headers[$key] = $value;
143 }
144 return $this;
145 }
146
147 /**
148 * Set response cookie
149 *
150 * @param string $name
151 * @param mixed $value
152 * @param int $minutes
153 * @param string $path
154 * @param string|null $domain
155 * @param bool $secure
156 * @param bool $httpOnly
157 * @param string $samesite
158 * @return self
159 */
160 public function withCookie(
161 $name,
162 $value,
163 $minutes,
164 $path = '/',
165 $domain = null,
166 $secure = false,
167 $httpOnly = true,
168 $samesite = 'Lax'
169 )
170 {
171 $cookie = $this->buildCookie(
172 $name,
173 $value,
174 $minutes,
175 $path,
176 $domain,
177 $secure,
178 $httpOnly,
179 $samesite
180 );
181
182 $this->cookies[] = $cookie;
183
184 return $this;
185 }
186
187 /**
188 * Set response cookie
189 *
190 * @param string $name
191 * @param mixed $value
192 * @param int $minutes
193 * @param string $path
194 * @param string|null $domain
195 * @param bool $secure
196 * @param bool $httpOnly
197 * @param string $samesite
198 * @return string
199 */
200 protected function buildCookie(
201 $name,
202 $value,
203 $minutes,
204 $path,
205 $domain,
206 $secure,
207 $httpOnly,
208 $samesite = 'Lax'
209 ) {
210 $expiration = static::expiresAt($minutes);
211
212 $cookieHeader = "{$name}=" . rawurlencode($value);
213
214 if ($expiration !== 0) {
215 $cookieHeader .= "; Expires=" . gmdate(
216 'D, d-M-Y H:i:s T', $expiration
217 );
218 }
219
220 $path = $path ?: '/';
221 $cookieHeader .= "; Path=" . $path;
222
223 if ($domain) {
224 $cookieHeader .= "; Domain=" . $domain;
225 }
226
227 if ($secure) {
228 $cookieHeader .= "; Secure";
229 }
230
231 if ($httpOnly) {
232 $cookieHeader .= "; HttpOnly";
233 }
234
235 if ($samesite) {
236 $cookieHeader .= "; SameSite=" . ucfirst(strtolower($samesite));
237 }
238
239 return $cookieHeader;
240 }
241
242 /**
243 * Merge additional headers if exist.
244 *
245 * @param \WP_REST_Response $response
246 */
247 protected function maybeMergeHeaders(WP_REST_Response $response)
248 {
249 if ($this->headers) {
250 foreach ($this->headers as $key => $value) {
251 $response->header($key, $value);
252 }
253 }
254
255 $this->headers = [];
256
257 return $response;
258 }
259
260 /**
261 * Merge cookies if exist.
262 *
263 * @param \WP_REST_Response $response
264 */
265 protected function maybeMergeCookies(WP_REST_Response $response)
266 {
267 if ($this->cookies) {
268 foreach ($this->cookies as $cookie) {
269 $response->header('Set-Cookie', $cookie);
270 }
271 }
272
273 $this->cookies = [];
274
275 return $response;
276 }
277
278 /**
279 * Prepares expiration time in minutes.
280 *
281 * @param int|DateTimeInterface $minutes
282 * @return int
283 */
284 protected static function expiresAt($minutes = 0)
285 {
286 if ($minutes === 0) {
287 return 0;
288 }
289
290 if (is_int($minutes)) {
291 $minutes = new DateTime("+{$minutes} minutes");
292 }
293
294 if ($minutes instanceof DateTimeInterface) {
295 return $minutes->getTimestamp();
296 }
297
298 throw new InvalidArgumentException('Invalid expiration time provided.');
299 }
300
301 /**
302 * Send the response
303 *
304 * @return \WP_REST_Response
305 */
306 public function toArray()
307 {
308 if ($this->data instanceof WP_Rest_Response) {
309 $response = $this->data;
310 } else {
311 $response = new WP_REST_Response(
312 $this->data, $this->code
313 );
314 }
315
316 return $this->maybeMergeHeaders(
317 $this->maybeMergeCookies($response)
318 );
319 }
320
321 /**
322 * Get data from response.
323 *
324 * @return mixed
325 */
326 public function getData()
327 {
328 if ($this->data instanceof WP_Rest_Response) {
329 return $this->data->get_data();
330 }
331
332 return $this->data;
333 }
334
335 /**
336 * Set data to response.
337 *
338 * @param mixed $data
339 * @return void
340 */
341 public function SetData($data)
342 {
343 if ($data instanceof WP_Rest_Response) {
344 $this->data->set_data($data);
345 return;
346 }
347
348 $this->data = $data;
349 }
350
351 /**
352 * Send a file download response.
353 *
354 * @param string $filePath
355 * @param string|null $fileName
356 * @return void
357 */
358 public static function download($filePath, $fileName = null)
359 {
360 if ($filePath instanceof File) {
361 $array = $filePath->toArray();
362 $filePath = $array['tmp_name'];
363 $fileName = $fileName ?? ($array['name'] ?? null);
364 }
365
366 if (!file_exists($filePath) || !is_readable($filePath)) {
367 wp_die('File does not exist or unreadable.', '404 Not Found');
368 }
369
370 $mimeType = mime_content_type($filePath) ?: 'application/octet-stream';
371
372 $fileName = sanitize_file_name($fileName ?? basename($filePath));
373
374 header('Content-Description: File Transfer');
375 header('Content-Type: ' . $mimeType);
376 header('Content-Disposition: attachment; filename="' . $fileName . '"');
377 header('Content-Transfer-Encoding: binary');
378 header('Expires: 0');
379 header('Cache-Control: must-revalidate');
380 header('Pragma: public');
381 header('Content-Length: ' . filesize($filePath));
382
383 if (php_sapi_name() === 'cli') {
384 ob_start();
385 readfile($filePath);
386 $content = ob_get_clean();
387 add_action('shutdown', function() { exit; });
388 return $content;
389 } else {
390 ob_get_level() && ob_end_clean() && flush();
391 readfile($filePath);
392 exit;
393 }
394 }
395
396 /**
397 * Send a redirect response.
398 *
399 * @param string $route
400 * @param integer $status
401 * @return \WP_REST_Response
402 */
403 public static function redirect($route, $status = 303)
404 {
405 // @phpstan-ignore-next-line
406 [$ns, $ver] = App::config()->only('rest_namespace', 'rest_version');
407
408 $baseUrl = rest_url("{$ns}/{$ver}");
409
410 $parsedUrl = parse_url($route);
411
412 $path = trim($parsedUrl['path'] ?? '', '/');
413
414 parse_str($parsedUrl['query'] ?? '', $queryParams);
415
416 $queryParams['x_redirect_to'] = $path;
417
418 // @phpstan-ignore-next-line
419 $queryParams['x_redirected_from'] = App::request()->url();
420
421 $location = "{$baseUrl}/{$path}?" . http_build_query($queryParams);
422
423 return new WP_REST_Response(null, $status, [
424 'Location' => $location
425 ]);
426 }
427 }
428