PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 2.3.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v2.3.0
2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 1.7.2 All 33 releases
fluent-booking / vendor / wpfluent / framework / src / WPFluent / Http / Response / Response.php

Response.php in Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution 2.3.0, at vendor/wpfluent/framework/src/WPFluent/Http/Response/Response.php

469 lines 11.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBooking\Framework\Http\Response;
4
5 use DateTime;
6 use WP_Error;
7 use DateTimeInterface;
8 use WP_REST_Response;
9 use FluentBooking\Framework\App\App;
10 use InvalidArgumentException;
11 use FluentBooking\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 * Attach a response cookie whose value is base64(json($value)).
189 *
190 * Pairs with Request::cookie(), which auto-detects this exact format
191 * and decodes back to the original value on read. Use this when you
192 * need to attach arrays/objects to a Response — strings, numbers, and
193 * scalars work fine through plain withCookie() and don't need encoding.
194 *
195 * @param string $name
196 * @param mixed $value Anything json_encode can serialize
197 * @param int $minutes
198 * @param string $path
199 * @param string|null $domain
200 * @param bool $secure
201 * @param bool $httpOnly
202 * @param string $samesite
203 * @return self
204 */
205 public function withEncodedCookie(
206 $name,
207 $value,
208 $minutes,
209 $path = '/',
210 $domain = null,
211 $secure = false,
212 $httpOnly = true,
213 $samesite = 'Lax'
214 )
215 {
216 return $this->withCookie(
217 $name,
218 base64_encode(json_encode($value)),
219 $minutes,
220 $path,
221 $domain,
222 $secure,
223 $httpOnly,
224 $samesite
225 );
226 }
227
228 /**
229 * Set response cookie
230 *
231 * @param string $name
232 * @param mixed $value
233 * @param int $minutes
234 * @param string $path
235 * @param string|null $domain
236 * @param bool $secure
237 * @param bool $httpOnly
238 * @param string $samesite
239 * @return string
240 */
241 protected function buildCookie(
242 $name,
243 $value,
244 $minutes,
245 $path,
246 $domain,
247 $secure,
248 $httpOnly,
249 $samesite = 'Lax'
250 ) {
251 $expiration = static::expiresAt($minutes);
252
253 $cookieHeader = "{$name}=" . rawurlencode($value);
254
255 if ($expiration !== 0) {
256 $cookieHeader .= "; Expires=" . gmdate(
257 'D, d-M-Y H:i:s T', $expiration
258 );
259 }
260
261 $path = $path ?: '/';
262 $cookieHeader .= "; Path=" . $path;
263
264 if ($domain) {
265 $cookieHeader .= "; Domain=" . $domain;
266 }
267
268 if ($secure) {
269 $cookieHeader .= "; Secure";
270 }
271
272 if ($httpOnly) {
273 $cookieHeader .= "; HttpOnly";
274 }
275
276 if ($samesite) {
277 $cookieHeader .= "; SameSite=" . ucfirst(strtolower($samesite));
278 }
279
280 return $cookieHeader;
281 }
282
283 /**
284 * Merge additional headers if exist.
285 *
286 * @param \WP_REST_Response $response
287 */
288 protected function maybeMergeHeaders(WP_REST_Response $response)
289 {
290 if ($this->headers) {
291 foreach ($this->headers as $key => $value) {
292 $response->header($key, $value);
293 }
294 }
295
296 $this->headers = [];
297
298 return $response;
299 }
300
301 /**
302 * Merge cookies if exist.
303 *
304 * @param \WP_REST_Response $response
305 */
306 protected function maybeMergeCookies(WP_REST_Response $response)
307 {
308 if ($this->cookies) {
309 foreach ($this->cookies as $cookie) {
310 $response->header('Set-Cookie', $cookie);
311 }
312 }
313
314 $this->cookies = [];
315
316 return $response;
317 }
318
319 /**
320 * Prepares expiration time in minutes.
321 *
322 * @param int|DateTimeInterface $minutes
323 * @return int
324 */
325 protected static function expiresAt($minutes = 0)
326 {
327 if ($minutes === 0) {
328 return 0;
329 }
330
331 if (is_int($minutes)) {
332 $minutes = new DateTime("+{$minutes} minutes");
333 }
334
335 if ($minutes instanceof DateTimeInterface) {
336 return $minutes->getTimestamp();
337 }
338
339 throw new InvalidArgumentException('Invalid expiration time provided.');
340 }
341
342 /**
343 * Send the response
344 *
345 * @return \WP_REST_Response
346 */
347 public function toArray()
348 {
349 if ($this->data instanceof WP_Rest_Response) {
350 $response = $this->data;
351 } else {
352 $response = new WP_REST_Response(
353 $this->data, $this->code
354 );
355 }
356
357 return $this->maybeMergeHeaders(
358 $this->maybeMergeCookies($response)
359 );
360 }
361
362 /**
363 * Get data from response.
364 *
365 * @return mixed
366 */
367 public function getData()
368 {
369 if ($this->data instanceof WP_Rest_Response) {
370 return $this->data->get_data();
371 }
372
373 return $this->data;
374 }
375
376 /**
377 * Set data to response.
378 *
379 * @param mixed $data
380 * @return void
381 */
382 public function SetData($data)
383 {
384 if ($data instanceof WP_Rest_Response) {
385 $this->data->set_data($data);
386 return;
387 }
388
389 $this->data = $data;
390 }
391
392 /**
393 * Send a file download response.
394 *
395 * @param string $filePath
396 * @param string|null $fileName
397 * @return void
398 */
399 public static function download($filePath, $fileName = null)
400 {
401 if ($filePath instanceof File) {
402 $array = $filePath->toArray();
403 $filePath = $array['tmp_name'];
404 $fileName = $fileName ?? ($array['name'] ?? null);
405 }
406
407 if (!file_exists($filePath) || !is_readable($filePath)) {
408 wp_die('File does not exist or unreadable.', '404 Not Found');
409 }
410
411 $mimeType = mime_content_type($filePath) ?: 'application/octet-stream';
412
413 $fileName = sanitize_file_name($fileName ?? basename($filePath));
414
415 header('Content-Description: File Transfer');
416 header('Content-Type: ' . $mimeType);
417 header('Content-Disposition: attachment; filename="' . $fileName . '"');
418 header('Content-Transfer-Encoding: binary');
419 header('Expires: 0');
420 header('Cache-Control: must-revalidate');
421 header('Pragma: public');
422 header('Content-Length: ' . filesize($filePath));
423
424 if (php_sapi_name() === 'cli') {
425 ob_start();
426 readfile($filePath);
427 $content = ob_get_clean();
428 add_action('shutdown', function() { exit; });
429 return $content;
430 } else {
431 ob_get_level() && ob_end_clean() && flush();
432 readfile($filePath);
433 exit;
434 }
435 }
436
437 /**
438 * Send a redirect response.
439 *
440 * @param string $route
441 * @param integer $status
442 * @return \WP_REST_Response
443 */
444 public static function redirect($route, $status = 303)
445 {
446 // @phpstan-ignore-next-line
447 [$ns, $ver] = App::config()->only('rest_namespace', 'rest_version');
448
449 $baseUrl = rest_url("{$ns}/{$ver}");
450
451 $parsedUrl = parse_url($route);
452
453 $path = trim($parsedUrl['path'] ?? '', '/');
454
455 parse_str($parsedUrl['query'] ?? '', $queryParams);
456
457 $queryParams['x_redirect_to'] = $path;
458
459 // @phpstan-ignore-next-line
460 $queryParams['x_redirected_from'] = App::request()->url();
461
462 $location = "{$baseUrl}/{$path}?" . http_build_query($queryParams);
463
464 return new WP_REST_Response(null, $status, [
465 'Location' => $location
466 ]);
467 }
468 }
469