Passed
Push — master ( 1d699e...0f9ddd )
by Thierry
04:26 queued 02:06
created

ParameterReader::getRequestParameters()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 13
nc 4
nop 0
dl 0
loc 23
rs 9.8333
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * ParameterReader.php
5
 *
6
 * This class processes the input arguments from the GET or POST data of the request.
7
 * If this is a request for the initial page load, no arguments will be processed.
8
 * During a jaxon request, any arguments found in the GET or POST will be converted to a PHP array.
9
 *
10
 * @package jaxon-core
0 ignored issues
show
Coding Style introduced by
Package name "jaxon-core" is not valid; consider "Jaxoncore" instead
Loading history...
11
 * @author Jared White
0 ignored issues
show
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
12
 * @author J. Max Wilson
0 ignored issues
show
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
13
 * @author Joseph Woolley
0 ignored issues
show
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
14
 * @author Steffen Konerow
0 ignored issues
show
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
15
 * @author Thierry Feuzeu <[email protected]>
16
 * @copyright Copyright (c) 2005-2007 by Jared White & J. Max Wilson
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
17
 * @copyright Copyright (c) 2008-2010 by Joseph Woolley, Steffen Konerow, Jared White  & J. Max Wilson
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
18
 * @copyright 2016 Thierry Feuzeu <[email protected]>
19
 * @license https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
20
 * @link https://github.com/jaxon-php/jaxon-core
21
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
PHP version not specified
Loading history...
22
23
namespace Jaxon\Request\Handler;
24
25
use Jaxon\Di\Container;
26
use Jaxon\Config\ConfigManager;
27
use Jaxon\Exception\RequestException;
28
use Jaxon\Utils\Http\UriDetector;
29
use Jaxon\Utils\Http\UriException;
30
use Jaxon\Utils\Translation\Translator;
31
32
use function strcasecmp;
33
use function is_array;
34
use function is_string;
35
use function substr;
36
use function strlen;
37
use function floor;
38
use function json_decode;
39
use function call_user_func;
40
use function array_map;
41
use function function_exists;
42
use function iconv;
43
use function intval;
44
use function mb_convert_encoding;
45
use function utf8_decode;
46
use function strpos;
47
use function strrpos;
48
use function parse_str;
49
use function rawurlencode;
50
use function str_replace;
51
52
class ParameterReader
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class ParameterReader
Loading history...
53
{
54
    /**
55
     * @var Container
56
     */
57
    protected $di;
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line(s) before first member var; 0 found
Loading history...
58
59
    /**
60
     * @var ConfigManager
61
     */
62
    protected $xConfigManager;
63
64
    /**
65
     * @var Translator
66
     */
67
    protected $xTranslator;
68
69
    /**
70
     * @var UriDetector
71
     */
72
    private $xUriDetector;
73
74
    /**
75
     * The function which decodes input parameters.
76
     *
77
     * @var callable
78
     */
79
    private $cParamDecoder;
80
81
    /**
82
     * The function which decodes utf8 string.
83
     *
84
     * @var callable
85
     */
86
    private $cUtf8Decoder;
87
88
    /**
89
     * The constructor
90
     *
91
     * @param Container $di
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
92
     * @param ConfigManager $xConfigManager
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
93
     * @param Translator $xTranslator
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
94
     * @param UriDetector $xUriDetector
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
95
     */
96
    public function __construct(Container $di, ConfigManager $xConfigManager,
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines before function; 1 found
Loading history...
97
        Translator $xTranslator, UriDetector $xUriDetector)
98
    {
99
        $this->di = $di;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 13 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
100
        $this->xConfigManager = $xConfigManager;
101
        $this->xTranslator = $xTranslator;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
102
        $this->xUriDetector = $xUriDetector;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
103
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
104
105
    /**
106
     * Choose the function to use to decode input data.
107
     *
108
     * @return void
109
     */
110
    private function setParamDecoder()
111
    {
112
        // Parameters are url encoded when uploading files
113
        $aServerParams = $this->di->getRequest()->getServerParams();
114
        $sContentType = '';
115
        if(isset($aServerParams['CONTENT_TYPE']))
116
        {
117
            $sContentType = $aServerParams['CONTENT_TYPE'];
118
        }
119
        elseif(isset($aServerParams['HTTP_CONTENT_TYPE']))
120
        {
121
            $sContentType = $aServerParams['HTTP_CONTENT_TYPE'];
122
        }
123
        $sType = 'multipart/form-data';
124
        if(strncmp($sContentType, $sType, strlen($sType)) !== 0)
125
        {
126
            $this->cParamDecoder = function($sParam) { return $sParam; };
127
            return;
128
        }
129
        $this->cParamDecoder = function($sParam) { return urldecode($sParam); };
130
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
131
132
    /**
133
     * Choose the function to use to decode input data.
134
     *
135
     * @return void
136
     * @throws RequestException
137
     */
138
    private function setUtf8Decoder()
139
    {
140
        // By default, no decoding
141
        $this->cUtf8Decoder = function($sStr) {
142
            return $sStr;
143
        };
144
        $sEncoding = $this->xConfigManager->getOption('core.encoding', '');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 10 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
145
        if(function_exists('iconv'))
146
        {
147
            $this->cUtf8Decoder = function($sStr) use($sEncoding) {
148
                return iconv("UTF-8", $sEncoding . '//TRANSLIT', $sStr);
149
            };
150
        }
151
        elseif(function_exists('mb_convert_encoding'))
152
        {
153
            $this->cUtf8Decoder = function($sStr) use($sEncoding) {
154
                return mb_convert_encoding($sStr, $sEncoding, "UTF-8");
155
            };
156
        }
157
        elseif($sEncoding === "ISO-8859-1")
158
        {
159
            $this->cUtf8Decoder = function($sStr) {
160
                return utf8_decode($sStr);
161
            };
162
        }
163
        else
164
        {
165
            throw new RequestException($this->xTranslator->trans('errors.request.conversion'));
166
        }
167
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
168
169
    /**
170
     * Converts a string to a bool var
171
     *
172
     * @param string $sValue    The string to be converted
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
173
     *
174
     * @return bool
175
     */
176
    private function convertStringToBool(string $sValue): bool
177
    {
178
        if(strcasecmp($sValue, 'true') === 0)
179
        {
180
            return true;
181
        }
182
        if(strcasecmp($sValue, 'false') === 0)
183
        {
184
            return false;
185
        }
186
        return (intval($sValue) !== 0);
187
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
188
189
    /**
190
     * Convert a Jaxon request argument to its value
191
     *
192
     * Depending on its first char, the Jaxon request argument is converted to a given type.
193
     *
194
     * @param string $sValue    The keys of the options in the file
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
195
     *
196
     * @return string|bool|integer|double|null
197
     */
198
    private function convertValue(string $sValue)
199
    {
200
        $cType = substr($sValue, 0, 1);
201
        $sValue = substr($sValue, 1);
202
        switch($cType)
203
        {
204
        case 'S':
205
            $value = !$sValue ? '' : $sValue;
206
            break;
207
        case 'B':
208
            $value = $this->convertStringToBool($sValue);
209
            break;
210
        case 'N':
211
            $value = ($sValue == floor($sValue) ? (int)$sValue : (float)$sValue);
0 ignored issues
show
Bug introduced by
$sValue of type string is incompatible with the type double|integer expected by parameter $num of floor(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

211
            $value = ($sValue == floor(/** @scrutinizer ignore-type */ $sValue) ? (int)$sValue : (float)$sValue);
Loading history...
212
            break;
213
        case '*':
214
        default:
215
            $value = null;
216
            break;
217
        }
218
        return $value;
219
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
220
221
    /**
222
     * Decode and convert a Jaxon request argument
223
     *
224
     * @param string $sParam    The Jaxon request argument
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
225
     *
226
     * @return mixed
227
     */
228
    private function decodeRequestParameter(string $sParam)
229
    {
230
        if($sParam === '')
231
        {
232
            return $sParam;
233
        }
234
235
        $sParam = call_user_func($this->cParamDecoder, $sParam);
236
237
        $xJson = json_decode($sParam, true);
238
        if($xJson !== null && $sParam != $xJson)
239
        {
240
            return $xJson;
241
        }
242
        return $this->convertValue($sParam);
243
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
244
245
    /**
246
     * @return array
247
     */
248
    private function getRequestParameters(): array
249
    {
250
        $aParams = [];
251
        $xRequest = $this->di->getRequest();
252
        $aBody = $xRequest->getParsedBody();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
253
        if(is_array($aBody))
254
        {
255
            if(isset($aBody['jxnargs']))
256
            {
257
                $aParams = $aBody['jxnargs'];
258
            }
259
        }
260
        else
261
        {
262
            $aParams = $xRequest->getQueryParams();
263
            if(isset($aParams['jxnargs']))
264
            {
265
                $aParams = $aParams['jxnargs'];
266
            }
267
        }
268
        return array_map(function($sParam) {
269
            return $this->decodeRequestParameter((string)$sParam);
270
        }, $aParams);
271
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
272
273
    /**
274
     * Decode a Jaxon request argument from UTF8
275
     *
276
     * @param mixed $xValue    The value of the argument being decoded
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
277
     *
278
     * @return mixed
279
     */
280
    private function decodeUtf8Parameter($xValue)
281
    {
282
        if(is_string($xValue))
283
        {
284
            return call_user_func($this->cUtf8Decoder, $xValue);
285
        }
286
        // elseif(is_numeric($xValue) || is_bool($xValue))
287
        {
288
            return $xValue;
289
        }
290
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
291
292
    /**
293
     * Decode an array of Jaxon request arguments from UTF8
294
     *
295
     * @param array $aParams
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
296
     *
297
     * @return array
298
     */
299
    private function decodeUtf8Parameters(array $aParams): array
300
    {
301
        $aValues = [];
302
        foreach($aParams as $sKey => $xValue)
303
        {
304
            // Decode the key
305
            $sKey = call_user_func($this->cUtf8Decoder, $sKey);
306
            // Decode the value
307
            $aValues[$sKey] = is_array($xValue) ?
0 ignored issues
show
Coding Style introduced by
Expected 1 space after "?"; newline found
Loading history...
308
                $this->decodeUtf8Parameters($xValue) : $this->decodeUtf8Parameter($xValue);
309
        }
310
        return $aValues;
311
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
312
313
    /**
314
     * Return the array of arguments from the GET or POST data
315
     *
316
     * @return array
317
     * @throws RequestException
318
     */
319
    public function args(): array
320
    {
321
        $this->setParamDecoder();
322
        $aParams = $this->getRequestParameters();
323
        if(!$this->xConfigManager->getOption('core.decode_utf8'))
324
        {
325
            return $aParams;
326
        }
327
        $this->setUtf8Decoder();
328
        $this->xConfigManager->setOption('core.decode_utf8', false);
329
        return $this->decodeUtf8Parameters($aParams);
330
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
331
332
    /**
333
     * Get the URI of the current request
334
     *
335
     * @throws UriException
336
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
337
    public function uri(): string
338
    {
339
        return $this->xUriDetector->detect($this->di->getRequest()->getServerParams());
340
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
341
342
    /**
343
     * @param string $sQueryPart
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
344
     *
345
     * @return string
346
     */
347
    private function parseQueryPart(string $sQueryPart): string
348
    {
349
        parse_str($sQueryPart, $aQueryParts);
350
        if(($aQueryParts))
351
        {
352
            $sNewQueryPart = '';
353
            foreach($aQueryParts as $key => $value)
354
            {
355
                $sNewQueryPart .= rawurlencode($key) . '=' . rawurlencode($value);
356
            }
357
            return ($sNewQueryPart) ? '&' . $sNewQueryPart : $sNewQueryPart;
358
        }
359
        //couldn't break up the query, but there's one there
360
        //possibly "http://url/page.html?query1234" type of query?
361
        //just encode it and hope it works
362
        $aServerParams = $this->di->getRequest()->getServerParams();
363
        if($aServerParams['QUERY_STRING'])
364
        {
365
            return rawurlencode($aServerParams['QUERY_STRING']);
366
        }
367
        return $sQueryPart;
368
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 1 found
Loading history...
369
370
    /**
371
     * Make the specified URL suitable for redirect
372
     *
373
     * @param string $sURL    The relative or fully qualified URL
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
374
     *
375
     * @return string
376
     */
377
    public function parseUrl(string $sURL): string
378
    {
379
        // we need to parse the query part so that the values are rawurlencode()'ed
380
        // can't just use parse_url() cos we could be dealing with a relative URL which
381
        // parse_url() can't deal with.
382
        $nQueryStart = strpos($sURL, '?', strrpos($sURL, '/'));
383
        if($nQueryStart === false)
384
        {
385
            return $sURL;
386
        }
387
        $nQueryStart++;
388
        $nQueryEnd = strpos($sURL, '#', $nQueryStart);
389
        if($nQueryEnd === false)
390
        {
391
            $nQueryEnd = strlen($sURL);
392
        }
393
        $sQueryPart = substr($sURL, $nQueryStart, $nQueryEnd - $nQueryStart);
394
        return str_replace($sQueryPart, $this->parseQueryPart($sQueryPart), $sURL);
395
    }
0 ignored issues
show
Coding Style introduced by
Expected 2 blank lines after function; 0 found
Loading history...
396
}
397