Passed
Push — 9.0-dev ( 5fff6b...0d4422 )
by Radu
01:42
created

Request::processCli()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 7
nc 8
nop 0
dl 0
loc 11
rs 8.8571
c 1
b 0
f 0
1
<?php
2
namespace WebServCo\Framework\Libraries;
3
4
final class Request extends \WebServCo\Framework\AbstractLibrary
5
{
6
    /**
7
     * Sanitized _SERVER data.
8
     */
9
    public $server = [];
10
    /**
11
     * Request method.
12
     */
13
    public $method;
14
    /**
15
     * Current script filename. Should most commonly be index.php
16
     */
17
    public $filename;
18
    /**
19
     * Script path.
20
     * For HTTP requests this will be public web server subdirectory
21
     * the project is located in.
22
     * For CLI request this will be the script path
23
     * (full or relative, depending on how the script was called).
24
     */
25
    public $path = '';
26
    /**
27
     * Sanitized Framework customized target path.
28
     */
29
    public $target = '';
30
    /**
31
     * Sanitized request query.
32
     */
33
    public $query = [];
34
    /**
35
     * Sanitized Framework customized CLI arguments.
36
     *
37
     * Excludes the script name and the second argument
38
     * which is the Framework customized target path.
39
     */
40
    public $args = [];
41
    
42
    public function __construct($config, $server, $post = [])
43
    {
44
        parent::__construct($config);
45
        
46
        $this->init($server, $post);
47
    }
48
    
49
    private function init($server, $post = [])
50
    {
51
        $this->server = $this->sanitize($server);
52
        $this->method = $this->getMethod();
53
        $this->filename = $this->getFilename();
54
        $this->path = $this->getPath();
55
        $this->process();
56
        
57
        switch ($this->method) {
58
            case \WebServCo\Framework\Http::METHOD_GET:
59
            case \WebServCo\Framework\Http::METHOD_HEAD:
60
                break;
61
            case \WebServCo\Framework\Http::METHOD_POST:
62
                $this->processPost($post);
63
                break;
64
        }
65
        if ($this->setting('clear_globals', true)) {
66
            $this->clearGlobals();
67
        }
68
    }
69
    
70
    private function clearGlobals()
71
    {
72
        if (!empty($_GET)) {
73
            foreach ($_GET as $k => $v) {
74
                unset($_REQUEST[$k]);
75
            }
76
            $_GET = [];
77
        }
78
        if (!empty($_POST)) {
79
            $_POST = [];
80
        }
81
        return true;
82
    }
83
    
84
    private function processPost($post = [])
85
    {
86
        $this->data = [];
87
        foreach ($post as $k => $v) {
88
            $this->data[$this->sanitize($k)] = $v;
89
        }
90
        return true;
91
    }
92
    
93
    private function process()
94
    {
95
        if (\WebServCo\Framework\Framework::isCLI()) {
96
            return $this->processCli();
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->processCli() targeting WebServCo\Framework\Libr...s\Request::processCli() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
97
        }
98
        
99
        return $this->processHttp();
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->processHttp() targeting WebServCo\Framework\Libr...\Request::processHttp() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
100
    }
101
    
102
    private function processCli()
103
    {
104
        if (isset($this->server['argv'][1])) {
105
            $this->target = $this->server['argv'][1];
106
        }
107
        if (isset($this->server['argv'][2])) {
108
            foreach ($this->server['argv'] as $k => $v) {
109
                if (in_array($k, [0,1])) {
110
                    continue;
111
                }
112
                $this->args[] = $this->sanitize($v);
113
            }
114
        }
115
    }
116
    
117
    private function processHttp()
118
    {
119
        $string = null;
120
        switch (true) {
121
            case isset($this->server['REQUEST_URI']):
122
                $string = $this->server['REQUEST_URI'];
123
                break;
124
            case isset($this->server['PATH_INFO']):
125
                $string = $this->server['PATH_INFO'];
126
                break;
127
            case isset($this->server['ORIG_PATH_INFO']):
128
                $string = $this->server['ORIG_PATH_INFO'];
129
                break;
130
            case !empty($this->server['QUERY_STRING']):
131
                $string = $this->server['ORIG_PATH_INFO'];
132
                break;
133
            default:
134
                break;
135
        }
136
        list ($target, $queryString) = $this->parse($string);
137
        $this->target = $this->sanitize(urldecode($target));
138
        $this->query = $this->format($this->sanitize($queryString));
139
    }
140
    
141
    private function getMethod()
142
    {
143
        return !empty($this->server['REQUEST_METHOD']) &&
144
        in_array(
145
            $this->server['REQUEST_METHOD'],
146
            \WebServCo\Framework\Http::getMethods()
147
        ) ?
148
        $this->server['REQUEST_METHOD'] : false;
149
    }
150
    
151
    private function getFilename()
152
    {
153
        return !empty($this->server['SCRIPT_NAME']) ?
154
        basename($this->server['SCRIPT_NAME']) : false;
155
    }
156
    
157
    private function getPath()
158
    {
159
        if (empty($this->server['SCRIPT_NAME'])) {
160
            return false;
161
        }
162
        $path = str_replace($this->getFilename(), '', $this->server['SCRIPT_NAME']);
0 ignored issues
show
Bug introduced by
It seems like $this->getFilename() can also be of type false; however, parameter $search of str_replace() does only seem to accept string|string[], maybe add an additional type check? ( Ignorable by Annotation )

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

162
        $path = str_replace(/** @scrutinizer ignore-type */ $this->getFilename(), '', $this->server['SCRIPT_NAME']);
Loading history...
163
        return rtrim($path, DIRECTORY_SEPARATOR);
164
    }
165
    
166
    public function sanitize($data)
167
    {
168
        if (is_array($data)) {
169
            array_walk_recursive($data, [$this, 'sanitizeString']);
170
            return $data;
171
        }
172
        return $this->sanitizeString($data);
173
    }
174
    
175
    protected function sanitizeString($string)
176
    {
177
        // Strip tags, optionally strip or encode special characters.
178
        $string = filter_var($string, FILTER_SANITIZE_STRING);
179
        $unwanted = [
180
            "`",
181
            //"'",
182
            //'"',
183
            "\b",
184
            "\n",
185
            "\r",
186
            "\t",
187
            //"?",
188
            //"!",
189
            //"~",
190
            //"#",
191
            //"^",
192
            //"&",
193
            //"*",
194
            //"=",
195
            //"[",
196
            //"]",
197
            //":",
198
            //";",
199
            //",",
200
            //"|",
201
            "\\",
202
            //"{",
203
            //"}",
204
            //"(",
205
            //")",
206
            "\$"
207
        ];
208
        $string = str_replace($unwanted, '', $string);
209
        return $string;
210
    }
211
    
212
    private function parse($string)
213
    {
214
        $pathLen = strlen($this->path);
215
        if (0 === strncasecmp($this->path, $string, $pathLen)) {
216
            $string = substr($string, $pathLen);
217
        }
218
        $filenameLen = strlen($this->filename);
219
        if (0 === strncasecmp($this->filename, $string, $filenameLen)) {
220
            $string = substr($string, $filenameLen);
221
        }
222
        list($target, $query) = $this->explode($string);
223
        $target = $this->removeSuffix($this->transform($target));
224
        $query = $this->transform($query);
225
        return [$target, $query];
226
    }
227
    
228
    private function explode($string)
229
    {
230
        if (false !== strpos($string, '?')) {
231
            return explode('?', $string, 2);
232
        } elseif (false !== strpos($string, '&')) {
233
            return explode('&', $string, 2);
234
        }
235
        return [$string, null];
236
    }
237
    
238
    private function transform($string)
239
    {
240
        $string = str_replace(['?','&','=','//'], ['','/','/','/0/'], $string);
241
        return trim($string, ' /');
242
    }
243
    
244
    private function removeSuffix($string)
245
    {
246
        $suffixes = $this->setting('suffixes');
247
        if (is_array($suffixes)) {
248
            $stringRev = strrev($string);
249
            foreach ($suffixes as $suffix) {
250
                $suffixRev = strrev($suffix);
251
                $suffixLen = strlen($suffix);
252
                if (0 === strncasecmp($suffixRev, $stringRev, $suffixLen)) {
253
                    return strrev(substr($stringRev, $suffixLen));
254
                }
255
            }
256
        }
257
        return $string;
258
    }
259
    
260
    private function format($string)
261
    {
262
        $data = [];
263
        $parts = $this->split($string);
264
        $num = count($parts);
265
        for ($position = 0; $position < $num; $position +=2) {
266
            $data[$parts[$position]] = $position == $num -1 ? null :
267
            $parts[$position + 1];
268
        }
269
        return $data;
270
    }
271
    
272
    public function split($string)
273
    {
274
        $parts = explode('/', $string);
275
        $parts = array_map('urldecode', $parts);
276
        return array_diff($parts, ['']);
277
    }
278
    
279
    public function getSchema()
280
    {
281
        if (\WebServCo\Framework\Framework::isCLI()) {
282
            return null;
283
        }
284
        
285
        if (isset($this->server['HTTPS']) && 'off' != $this->server['HTTPS']) {
286
            return 'https';
287
        } elseif (isset($this->server['HTTP_X_FORWARDED_PROTO']) &&
288
        'https' == $this->server['HTTP_X_FORWARDED_PROTO']) {
289
            return 'https';
290
        } elseif (isset($this->server['HTTP_X_FORWARDED_SSL']) &&
291
        'on' == $this->server['HTTP_X_FORWARDED_SSL']) {
292
            return 'https';
293
        }
294
        return 'http';
295
    }
296
    
297
    public function getReferer()
298
    {
299
        return isset($this->server['HTTP_REFERER']) ? $this->server['HTTP_REFERER'] : null;
300
    }
301
    
302
    public function getHost()
303
    {
304
        if (!empty($this->server['HTTP_HOST'])) {
305
            return $this->server['HTTP_HOST'];
306
        } elseif (!empty($this->server['SERVER_NAME'])) {
307
            return $this->server['SERVER_NAME'];
308
        } elseif (!empty($this->server['HOSTNAME'])) {
309
            return $this->server['HOSTNAME']; //CLI
310
        }
311
        return null;
312
    }
313
    
314
    public function guessAppUrl()
315
    {
316
        if (\WebServCo\Framework\Framework::isCLI()) {
317
            return false;
318
        }
319
        return $this->getSchema() .
320
        '://' .
321
        $this->getHost() .
322
        $this->path .
323
        DIRECTORY_SEPARATOR;
324
    }
325
}
326