PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.18.0
GiveWP – Donation Plugin and Fundraising Platform v4.18.0
4.18.0.1 4.18.0 4.17.0 4.16.9 4.16.8.1 4.16.8 4.16.7.2 4.16.7.1 4.16.7 4.16.6.1 4.16.6 4.16.5.1 4.16.5 4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 All 258 releases
give / vendor / vendor-prefixed / symfony / http-foundation / JsonResponse.php

JsonResponse.php in GiveWP – Donation Plugin and Fundraising Platform 4.18.0, at vendor/vendor-prefixed/symfony/http-foundation/JsonResponse.php

222 lines 7.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <[email protected]>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Give\Vendors\Symfony\Component\HttpFoundation;
13
14 /**
15 * Response represents an HTTP response in JSON format.
16 *
17 * Note that this class does not force the returned JSON content to be an
18 * object. It is however recommended that you do return an object as it
19 * protects yourself against XSSI and JSON-JavaScript Hijacking.
20 *
21 * @see https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/AJAX_Security_Cheat_Sheet.md#always-return-json-with-an-object-on-the-outside
22 *
23 * @author Igor Wiedler <[email protected]>
24 */
25 class JsonResponse extends Response
26 {
27 protected $data;
28 protected $callback;
29
30 // Encode <, >, ', &, and " characters in the JSON, making it also safe to be embedded into HTML.
31 // 15 === JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT
32 public const DEFAULT_ENCODING_OPTIONS = 15;
33
34 protected $encodingOptions = self::DEFAULT_ENCODING_OPTIONS;
35
36 /**
37 * @param mixed $data The response data
38 * @param int $status The response status code
39 * @param array $headers An array of response headers
40 * @param bool $json If the data is already a JSON string
41 */
42 public function __construct($data = null, int $status = 200, array $headers = [], bool $json = false)
43 {
44 parent::__construct('', $status, $headers);
45
46 if ($json && !\is_string($data) && !is_numeric($data) && !\is_callable([$data, '__toString'])) {
47 throw new \TypeError(sprintf('"%s": If $json is set to true, argument $data must be a string or object implementing __toString(), "%s" given.', __METHOD__, get_debug_type($data)));
48 }
49
50 if (null === $data) {
51 $data = new \ArrayObject();
52 }
53
54 $json ? $this->setJson($data) : $this->setData($data);
55 }
56
57 /**
58 * Factory method for chainability.
59 *
60 * Example:
61 *
62 * return JsonResponse::create(['key' => 'value'])
63 * ->setSharedMaxAge(300);
64 *
65 * @param mixed $data The JSON response data
66 * @param int $status The response status code
67 * @param array $headers An array of response headers
68 *
69 * @return static
70 *
71 * @deprecated since Symfony 5.1, use __construct() instead.
72 */
73 public static function create($data = null, int $status = 200, array $headers = [])
74 {
75 trigger_deprecation('symfony/http-foundation', '5.1', 'The "%s()" method is deprecated, use "new %s()" instead.', __METHOD__, static::class);
76
77 return new static($data, $status, $headers);
78 }
79
80 /**
81 * Factory method for chainability.
82 *
83 * Example:
84 *
85 * return JsonResponse::fromJsonString('{"key": "value"}')
86 * ->setSharedMaxAge(300);
87 *
88 * @param string $data The JSON response string
89 * @param int $status The response status code
90 * @param array $headers An array of response headers
91 *
92 * @return static
93 */
94 public static function fromJsonString(string $data, int $status = 200, array $headers = [])
95 {
96 return new static($data, $status, $headers, true);
97 }
98
99 /**
100 * Sets the JSONP callback.
101 *
102 * @param string|null $callback The JSONP callback or null to use none
103 *
104 * @return $this
105 *
106 * @throws \InvalidArgumentException When the callback name is not valid
107 */
108 public function setCallback(?string $callback = null)
109 {
110 if (null !== $callback) {
111 // partially taken from https://geekality.net/2011/08/03/valid-javascript-identifier/
112 // partially taken from https://github.com/willdurand/JsonpCallbackValidator
113 // JsonpCallbackValidator is released under the MIT License. See https://github.com/willdurand/JsonpCallbackValidator/blob/v1.1.0/LICENSE for details.
114 // (c) William Durand <[email protected]>
115 $pattern = '/^[$_\p{L}][$_\p{L}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\x{200C}\x{200D}]*(?:\[(?:"(?:\\\.|[^"\\\])*"|\'(?:\\\.|[^\'\\\])*\'|\d+)\])*?$/u';
116 $reserved = [
117 'break', 'do', 'instanceof', 'typeof', 'case', 'else', 'new', 'var', 'catch', 'finally', 'return', 'void', 'continue', 'for', 'switch', 'while',
118 'debugger', 'function', 'this', 'with', 'default', 'if', 'throw', 'delete', 'in', 'try', 'class', 'enum', 'extends', 'super', 'const', 'export',
119 'import', 'implements', 'let', 'private', 'public', 'yield', 'interface', 'package', 'protected', 'static', 'null', 'true', 'false',
120 ];
121 $parts = explode('.', $callback);
122 foreach ($parts as $part) {
123 if (!preg_match($pattern, $part) || \in_array($part, $reserved, true)) {
124 throw new \InvalidArgumentException('The callback name is not valid.');
125 }
126 }
127 }
128
129 $this->callback = $callback;
130
131 return $this->update();
132 }
133
134 /**
135 * Sets a raw string containing a JSON document to be sent.
136 *
137 * @return $this
138 */
139 public function setJson(string $json)
140 {
141 $this->data = $json;
142
143 return $this->update();
144 }
145
146 /**
147 * Sets the data to be sent as JSON.
148 *
149 * @param mixed $data
150 *
151 * @return $this
152 *
153 * @throws \InvalidArgumentException
154 */
155 public function setData($data = [])
156 {
157 try {
158 $data = json_encode($data, $this->encodingOptions);
159 } catch (\Exception $e) {
160 if ('Exception' === \get_class($e) && str_starts_with($e->getMessage(), 'Failed calling ')) {
161 throw $e->getPrevious() ?: $e;
162 }
163 throw $e;
164 }
165
166 if (\PHP_VERSION_ID >= 70300 && (\JSON_THROW_ON_ERROR & $this->encodingOptions)) {
167 return $this->setJson($data);
168 }
169
170 if (\JSON_ERROR_NONE !== json_last_error()) {
171 throw new \InvalidArgumentException(json_last_error_msg());
172 }
173
174 return $this->setJson($data);
175 }
176
177 /**
178 * Returns options used while encoding data to JSON.
179 *
180 * @return int
181 */
182 public function getEncodingOptions()
183 {
184 return $this->encodingOptions;
185 }
186
187 /**
188 * Sets options used while encoding data to JSON.
189 *
190 * @return $this
191 */
192 public function setEncodingOptions(int $encodingOptions)
193 {
194 $this->encodingOptions = $encodingOptions;
195
196 return $this->setData(json_decode($this->data));
197 }
198
199 /**
200 * Updates the content and headers according to the JSON data and callback.
201 *
202 * @return $this
203 */
204 protected function update()
205 {
206 if (null !== $this->callback) {
207 // Not using application/javascript for compatibility reasons with older browsers.
208 $this->headers->set('Content-Type', 'text/javascript');
209
210 return $this->setContent(sprintf('/**/%s(%s);', $this->callback, $this->data));
211 }
212
213 // Only set the header when there is none or when it equals 'text/javascript' (from a previous update with callback)
214 // in order to not overwrite a custom definition.
215 if (!$this->headers->has('Content-Type') || 'text/javascript' === $this->headers->get('Content-Type')) {
216 $this->headers->set('Content-Type', 'application/json');
217 }
218
219 return $this->setContent($this->data);
220 }
221 }
222