Passed
Push — 9.0-dev ( 95a6ae...5fff6b )
by Radu
02:04
created

Request::guessAppUrl()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 2
eloc 7
nc 2
nop 0
dl 0
loc 10
rs 9.4285
c 1
b 1
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
    public function __construct($config, $server, $post = [])
36
    {
37
        parent::__construct($config);
38
        
39
        $this->init($server, $post);
40
    }
41
    
42
    private function init($server, $post = [])
43
    {
44
        $this->server = $this->sanitize($server);
45
        $this->method = $this->getMethod();
46
        $this->filename = $this->getFilename();
47
        $this->path = $this->getPath();
48
        $this->process();
49
        
50
        switch ($this->method) {
51
            case \WebServCo\Framework\Http::METHOD_GET:
52
            case \WebServCo\Framework\Http::METHOD_HEAD:
53
                break;
54
            case \WebServCo\Framework\Http::METHOD_POST:
55
                $this->processPost($post);
56
                break;
57
        }
58
        if ($this->setting('clear_globals', true)) {
59
            $this->clearGlobals();
60
        }
61
    }
62
    
63
    private function clearGlobals()
64
    {
65
        if (!empty($_GET)) {
66
            foreach ($_GET as $k => $v) {
67
                unset($_REQUEST[$k]);
68
            }
69
            $_GET = [];
70
        }
71
        if (!empty($_POST)) {
72
            $_POST = [];
73
        }
74
        return true;
75
    }
76
    
77
    private function processPost($post = [])
78
    {
79
        $this->data = [];
80
        foreach ($post as $k => $v) {
81
            $this->data[$this->sanitize($k)] = $v;
82
        }
83
        return true;
84
    }
85
    
86
    private function process()
87
    {
88
        if (\WebServCo\Framework\Framework::isCLI()) {
89
            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...
90
        }
91
        
92
        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...
93
    }
94
    
95
    private function processCli()
96
    {
97
        if (isset($this->server['argv'][1])) {
98
            $this->target = $this->server['argv'][1];
99
        }
100
    }
101
    
102
    private function processHttp()
103
    {
104
        $string = null;
105
        switch (true) {
106
            case isset($this->server['REQUEST_URI']):
107
                $string = $this->server['REQUEST_URI'];
108
                break;
109
            case isset($this->server['PATH_INFO']):
110
                $string = $this->server['PATH_INFO'];
111
                break;
112
            case isset($this->server['ORIG_PATH_INFO']):
113
                $string = $this->server['ORIG_PATH_INFO'];
114
                break;
115
            case !empty($this->server['QUERY_STRING']):
116
                $string = $this->server['ORIG_PATH_INFO'];
117
                break;
118
            default:
119
                break;
120
        }
121
        list ($target, $queryString) = $this->parse($string);
122
        $this->target = $this->sanitize(urldecode($target));
123
        $this->query = $this->format($this->sanitize($queryString));
124
    }
125
    
126
    private function getMethod()
127
    {
128
        return !empty($this->server['REQUEST_METHOD']) &&
129
        in_array(
130
            $this->server['REQUEST_METHOD'],
131
            \WebServCo\Framework\Http::getMethods()
132
        ) ?
133
        $this->server['REQUEST_METHOD'] : false;
134
    }
135
    
136
    private function getFilename()
137
    {
138
        return !empty($this->server['SCRIPT_NAME']) ?
139
        basename($this->server['SCRIPT_NAME']) : false;
140
    }
141
    
142
    private function getPath()
143
    {
144
        if (empty($this->server['SCRIPT_NAME'])) {
145
            return false;
146
        }
147
        $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

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