Passed
Pull Request — development (#3766)
by Elk
06:51
created

HttpReq::_loadJson()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 0
dl 0
loc 16
rs 10
c 0
b 0
f 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A HttpReq::__get() 0 13 3
1
<?php
2
3
/**
4
 * Http Request class for providing global vars to class for improved
5
 * encapsulation
6
 *
7
 * @package   ElkArte Forum
8
 * @copyright ElkArte Forum contributors
9
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
10
 *
11
 * @version 2.0 dev
12
 *
13
 */
14
15
namespace ElkArte\Helper;
16
17
/**
18
 * Class used to interact with super globals, POST, GET, SERVER, COOKIES, SESSION
19
 *
20
 * - Currently only a 'getter' of values
21
 * - Can be passed DataValidation sanitation values to return sanitized values
22
 * - Fetch raw values as $instance->post->keyname
23
 *     - $this->-req->post->filename
24
 *     - $this->_req->query->sa
25
 * - Fetch cleaned values with $instance->getPost('keyname', 'sanitation needs', 'default value')
26
 *     - $this->-req->getPost('filename', 'trim|strval', '');
27
 *     - $this->-req->getQuery('filename', 'intval', 0);
28
 *     - Can use rules as 'htmlspecialchars[ENT_COMPAT]', '\\ElkArte\\Helper\\Util::htmlspecialchars[ENT_QUOTES]'
29
 */
30
class HttpReq
31
{
32
	/** @var object The returned POST values */
33
	public $post;
34
35
	/** @var array The compiled post values (json and cleaned from request) */
36
	private $_derived_post;
37
38
	/** @var object The returned GET values */
39
	public $query;
40
41
	/** @var object The returned COOKIE values */
42
	public $cookie;
43
44
	/** @var object The returned SESSION values */
45
	public $session;
46
47
	/** @var object The returned SERVER values */
48
	public $server;
49
50
	/** @var HttpReq Sole private \ElkArte\Helper\HttpReq instance */
51
	private static $instance;
52
53
	/** @var array Used to hold processed (sanitised) values */
54
	private $_param;
55
56
	/** @var DataValidator holds instance of the validator */
57
	protected $_dataValidator;
58
59
	/**
60
	 * Class constructor, sets PHP globals to class members
61
	 *
62
	 * @param $dataValidator DataValidator|null Instance of the data validator
63
	 */
64
	private function __construct($dataValidator = null)
65
	{
66
		// Make sure the validator is initiated
67
		$this->_dataValidator = $dataValidator ?? new DataValidator();
68
69
		// Make the superglobals available as R/W properties
70
		$this->cookie = new \ArrayObject($_COOKIE, \ArrayObject::ARRAY_AS_PROPS);
71
		if (session_status() === PHP_SESSION_ACTIVE)
72
		{
73
			$this->session = new \ArrayObject($_SESSION, \ArrayObject::ARRAY_AS_PROPS);
74
		}
75
		else
76
		{
77
			$this->session = new \ArrayObject(array(), \ArrayObject::ARRAY_AS_PROPS);
78
		}
79
80
		$this->server = detectServer();
81
82
		// Get will be in ->query, Post in ->post
83
		$this->_loadParsed();
84
	}
85
86
	/**
87
	 * Certain variables are born in Request, others are sanitized, and stored in
88
	 * $_REQUEST, its a awful mess really.
89
	 *
90
	 * Once that mess is cleaned up this should not be needed.  But the basis is due to
91
	 * what function cleanRequest() does.
92
	 *
93
	 * What it does:
94
	 *
95
	 * - Finds items added by cleanRequest to $_REQUEST
96
	 * - Adds the above to both $_POST and $_GET
97
	 * - Looks for duplicate items in $_REQUEST and $_POST and uses the $_REQUEST
98
	 *   values, being they are "sanitized"
99
	 * - $_GET ones are already re-stuffed by cleanRequest
100
	 */
101
	private function _loadParsed()
102
	{
103
		// Any that were born in cleanRequest, like start from topic=xyz.START
104
		// are added to the other supers
105
		$derived = array_diff_key($_REQUEST, $_POST, $_GET);
106
		$derived_get = array_merge($_GET, $derived);
107
		$this->_derived_post = array_merge($_POST, $derived);
108
109
		// Others may have been "sanitized" from either get or post and saved in request
110
		// these values replace the existing ones in $_POST
111
		$cleaned = array_intersect_key($_REQUEST, $this->_derived_post);
112
		$this->_derived_post = array_merge($this->_derived_post, $cleaned);
113
114
		// Make the $_GET $_POST super globals available as R/W properties
115
		$this->post = new \ArrayObject($this->_derived_post, \ArrayObject::ARRAY_AS_PROPS);
116
		$this->query = new \ArrayObject($derived_get, \ArrayObject::ARRAY_AS_PROPS);
117
	}
118
119
	/**
120
	 * Generic fetch access for values contained in the super globals
121
	 *
122
	 * - gets in order of param, get and post
123
	 * - $instance->keyanme will check cleaned params, get then post for values
124
	 *     - $_POST['foo'] = 'bar', $_GET['bar'] = 'foo'
125
	 *     - $this->req->post->foo is explicit and returns bar
126
	 *     - $this->req->foo is loose and will trigger this method, return foo as its a found key in GET
127
	 *
128
	 * @param string $key
129
	 *
130
	 * @return mixed|null
131
	 */
132
	public function __get($key)
133
	{
134
		if (isset($this->_param[$key]))
135
		{
136
			return $this->_param[$key];
137
		}
138
139
		if (isset($this->query->{$key}))
140
		{
141
			return $this->query->{$key};
142
		}
143
144
		return $this->post->{$key} ?? null;
145
	}
146
147
	/**
148
	 * Alias to __get
149
	 *
150
	 * Allows lazy way to find and return a value from get or post key name
151
	 *
152
	 * @param string $name The key name of the value to return
153
	 * @param string|null $sanitize a comma separated list of sanitation rules to apply
154
	 * @param mixed|null $default default value to return if key value is not found
155
	 *
156
	 * @return mixed
157
	 */
158
	public function get($name, $sanitize = null, $default = null)
159
	{
160
		// See if it exists in one of the supers
161
		$temp = $this->__get($name);
162
163
		$this->_param[$name] = $default;
164
165
		if (isset($temp))
166
		{
167
			$this->_param[$name] = $temp;
168
			$this->_param[$name] = $this->cleanValue($name, $sanitize);
169
		}
170
171
		return $this->_param[$name];
172
	}
173
174
	/**
175
	 * Generic check to see if a property is set in one of the super globals
176
	 *
177
	 * - checks in order of param, get, post
178
	 *
179
	 * @param string $key
180
	 *
181
	 * @return bool
182
	 */
183
	public function __isset($key)
184
	{
185
		return match (true)
186
		{
187
			isset($this->post->{$key}), isset($this->query->{$key}), isset($this->_param[$key]) => true,
188
			default => false,
189
		};
190
	}
191
192
	/**
193
	 * Alias to __isset()
194
	 *
195
	 * @param string $key
196
	 *
197
	 * @return bool
198
	 */
199
	public function isSet($key)
200
	{
201
		return $this->__isset($key);
202
	}
203
204
	/**
205
	 * Method to return a $_GET value
206
	 *
207
	 * - Uses any sanitize rule(s) that can be passed to the \ElkArte\Helper\DataValidator class
208
	 * - Returned value will be the sanitized value or null of the key is not in $_GET
209
	 * - If you just want a value back access it directly as $req->query->{$name}
210
	 *
211
	 * @param string $name The key name of the value to return
212
	 * @param string|null $sanitize a comma separated list of sanitation rules to apply
213
	 * @param mixed|null $default default value to return if key value is not found
214
	 *
215
	 * @return mixed
216
	 */
217
	public function getQuery($name = '', $sanitize = null, $default = null)
218
	{
219
		$this->_param[$name] = $default;
220
221
		if (isset($this->query->{$name}))
222
		{
223
			$this->_param[$name] = $this->query->{$name};
224
			$this->_param[$name] = $this->cleanValue($name, $sanitize);
225
		}
226
227
		return $this->_param[$name];
228
	}
229
230
	/**
231
	 * Method to return a $_POST value
232
	 *
233
	 * - Uses any sanitize rule(s) that can be passed to the \ElkArte\Helper\DataValidator class
234
	 * - Returned value will be the sanitized value or null of the key is not in $_POST
235
	 * - If you just want a value back access it directly as $req->post->{$name}
236
	 *
237
	 * @param string $name The key name of the value to return
238
	 * @param string|null $sanitize a comma separated list of sanitation rules to apply
239
	 * @param mixed|null $default default value to return if key value is not found
240
	 *
241
	 * @return mixed
242
	 */
243
	public function getPost($name = '', $sanitize = null, $default = null)
244
	{
245
		$this->_param[$name] = $default;
246
247
		if (isset($this->post->{$name}))
248
		{
249
			$this->_param[$name] = $this->post->{$name};
250
			$this->_param[$name] = $this->cleanValue($name, $sanitize);
251
		}
252
253
		return $this->_param[$name];
254
	}
255
256
	/**
257
	 * Method to return a $_REQUEST value
258
	 *
259
	 * - Uses any sanitize rule(s) that can be passed to the \ElkArte\Helper\DataValidator class
260
	 * - Returned value will be the sanitized value or null if the key is not found in either $_GET
261
	 * or $_POST (in that order).  Ideally you should know if something is in GET or POST and use
262
	 * those get function directly.
263
	 *
264
	 * @param string $name The key name of the value to return
265
	 * @param string|null $sanitize a comma separated list of sanitation rules to apply
266
	 * @param mixed|null $default default value to return if key value is not found
267
	 *
268
	 * @return mixed
269
	 */
270
	public function getRequest($name = '', $sanitize = null, $default = null)
271
	{
272
		$this->_param[$name] = $default;
273
274
		if (isset($this->query->{$name}))
275
		{
276
			$this->_param[$name] = $this->query->{$name};
277
			$this->_param[$name] = $this->cleanValue($name, $sanitize);
278
		}
279
		elseif (isset($this->post->{$name}))
280
		{
281
			$this->_param[$name] = $this->post->{$name};
282
			$this->_param[$name] = $this->cleanValue($name, $sanitize);
283
		}
284
285
		return $this->_param[$name];
286
	}
287
288
	/**
289
	 * Helper function to do a value comparison to a GET value.  Returns false
290
	 * if the value does not exist or if it does not equal the comparison value.
291
	 *
292
	 * @param string $name get value to fetch
293
	 * @param mixed $compare value to compare the get value to
294
	 * @param null|string $sanitize optional | delimited data for validator
295
	 * @param null|mixed $default if no value exists, what to set it to (will also be used in the compare)
296
	 *
297
	 * @return bool
298
	 */
299
	public function compareQuery($name, $compare, $sanitize = null, $default = null)
300
	{
301
		$this->getQuery($name, $sanitize, $default);
302
303
		return $this->isSet($name) && $this->_param[$name] === $compare;
304
	}
305
306
	/**
307
	 * Helper function to do a value comparison to a Post value.  Returns false
308
	 * if the value does not exist or if it does not equal the comparison value.
309
	 *
310
	 * @param string $name get value to fetch
311
	 * @param mixed $compare value to compare the post value to
312
	 * @param null|string $sanitize optional | delimited data for validator
313
	 * @param null|mixed $default if no value exists, what to set it to (will also be used in the compare)
314
	 *
315
	 * @return bool
316
	 */
317
	public function comparePost($name, $compare, $sanitize = null, $default = null)
318
	{
319
		$this->getPost($name, $sanitize, $default);
320
321
		return $this->isSet($name) && $this->_param[$name] === $compare;
322
	}
323
324
	/**
325
	 * Method to return a $_COOKIE value
326
	 *
327
	 * - Does not provide sanitation capability
328
	 *
329
	 * @param string $name the name of the value to return
330
	 * @param mixed|null $default default value to return if key value is not found
331
	 *
332
	 * @return mixed|null
333
	 */
334
	public function getCookie($name = '', $default = null)
335
	{
336
		if (isset($this->cookie->{$name}))
337
		{
338
			return $this->cookie->{$name};
339
		}
340
341
		return $default ?? null;
342
	}
343
344
	/**
345
	 * Method to get a $_SESSION value
346
	 *
347
	 * - Does not provide sanitation capability
348
	 *
349
	 * @param string $name the name of the value to return
350
	 * @param mixed|null $default default value to return if key value is not found
351
	 *
352
	 * @return mixed|null
353
	 */
354
	public function getSession($name = '', $default = null)
355
	{
356
		if (isset($this->session->{$name}))
357
		{
358
			return $this->session->{$name};
359
		}
360
361
		return $default ?? null;
362
	}
363
364
	/**
365
	 * Runs sanitation rules against a single value
366
	 *
367
	 * @param string $name the key name in the _param array
368
	 * @param string|null $sanitize comma separated list of rules
369
	 *
370
	 * @return mixed|array|null
371
	 */
372
	public function cleanValue($name, $sanitize = null)
373
	{
374
		// No rules, then return the current value
375
		if ($sanitize === null)
376
		{
377
			return $this->_param[$name];
378
		}
379
380
		// To the validator
381
		$this->_dataValidator->validation_rules();
382
		$this->_dataValidator->sanitation_rules([$name => $sanitize]);
383
384
		if (is_array($this->_param[$name]))
385
		{
386
			$this->_dataValidator->input_processing([$name => 'array']);
387
		}
388
389
		$this->_dataValidator->validate($this->_param);
390
391
		// Return the clean value
392
		return $this->_dataValidator->validation_data($name);
393
	}
394
395
	/**
396
	 * Removes a value from the post or query arrays
397
	 *
398
	 * @param string $name the key name in the _param array
399
	 * @param string|null $type where you want the value removed from post, query, both
400
	 */
401
	public function clearValue($name, $type)
402
	{
403
		unset($this->_param[$name]);
404
405
		if ($type === 'post' || $type === 'both')
406
		{
407
			unset($this->post->{$name});
408
		}
409
410
		if ($type === 'query' || $type === 'both')
411
		{
412
			unset($this->post->{$name});
413
		}
414
	}
415
416
	/**
417
	 * Retrieve the sole instance of this class.
418
	 *
419
	 * @return HttpReq
420
	 */
421
	public static function instance()
422
	{
423
		if (self::$instance === null)
424
		{
425
			self::$instance = new HttpReq();
426
		}
427
428
		return self::$instance;
429
	}
430
}
431