Completed
Push — master ( ac63ed...391fb0 )
by Arman
20s queued 16s
created

HttpRequest::getBasicAuthCredentials()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 13
nc 5
nop 0
dl 0
loc 25
rs 8.8333
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 2.9.7
13
 */
14
15
namespace Quantum\Http\Request;
16
17
use Quantum\Http\Exceptions\HttpException;
18
use Quantum\App\Exceptions\BaseException;
19
use Quantum\Di\Exceptions\DiException;
20
use Quantum\Libraries\Csrf\Csrf;
21
use Quantum\Environment\Server;
22
use ReflectionException;
23
24
/**
25
 * Class HttpRequest
26
 * @package Quantum\Http
27
 */
28
abstract class HttpRequest
29
{
30
31
    use Header;
32
    use Body;
33
    use Url;
34
    use Query;
35
    use Params;
36
    use File;
37
38
    /**
39
     * Multipart form data
40
     */
41
    const CONTENT_FORM_DATA = 'multipart/form-data';
42
43
    /**
44
     * JSON payload
45
     */
46
    const CONTENT_JSON_PAYLOAD = 'application/json';
47
48
    /**
49
     * URL encoded
50
     */
51
    const CONTENT_URL_ENCODED = 'application/x-www-form-urlencoded';
52
53
    /**
54
     * Available methods
55
     */
56
    const METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
57
58
    /**
59
     * Request method
60
     * @var string
61
     */
62
    private static $__method = null;
63
64
    /**
65
     * @var bool
66
     */
67
    private static $initialized = false;
68
69
    /**
70
     * Server
71
     * @var Server
72
     */
73
    private static $server;
74
75
    /**
76
     * Initiates the Request
77
     * @param Server $server
78
     * @return void
79
     * @throws DiException
80
     * @throws HttpException
81
     * @throws ReflectionException
82
     * @throws BaseException
83
     */
84
    public static function init(Server $server)
85
    {
86
        if (self::$initialized) {
87
            return;
88
        }
89
90
        self::$server = $server;
91
92
        self::$__method = self::$server->method();
93
94
        self::$__protocol = self::$server->protocol();
95
96
        self::$__host = self::$server->host();
97
98
        self::$__port = self::$server->port();
99
100
        self::$__uri = self::$server->uri();
101
102
        self::$__query = self::$server->query();
103
104
        self::$__headers = array_change_key_case((array)getallheaders());
105
106
        list('params' => $params, 'files' => $files) = self::parsedParams();
107
108
        self::$__request = array_merge(
109
            self::$__request,
110
            self::getParams(),
111
            self::postParams(),
112
            $params
113
        );
114
115
        self::$__files = array_merge(
116
            self::handleFiles($_FILES),
117
            $files
118
        );
119
120
        self::$initialized = true;
121
    }
122
123
    /**
124
     * Creates new request for internal use
125
     * @param string $method
126
     * @param string $url
127
     * @param array|null $data
128
     * @param array|null $files
129
     * @return void
130
     * @throws BaseException
131
     * @throws DiException
132
     * @throws HttpException
133
     * @throws ReflectionException
134
     */
135
    public static function create(string $method, string $url, array $data = null, array $files = null)
136
    {
137
        if (!self::$initialized) {
138
            self::init(Server::getInstance());
139
        }
140
141
        $parsed = parse_url($url);
142
143
        self::setMethod($method);
144
145
        if (isset($parsed['scheme'])) {
146
            self::setProtocol($parsed['scheme']);
147
        }
148
149
        if (isset($parsed['host'])) {
150
            self::setHost($parsed['host']);
151
        }
152
153
        if (isset($parsed['port'])) {
154
            self::setPort($parsed['port']);
155
        }
156
        if (isset($parsed['path'])) {
157
            self::setUri($parsed['path']);
158
        }
159
        if (isset($parsed['query'])) {
160
            self::setQuery($parsed['query']);
161
        }
162
163
        if ($data) {
164
            self::$__request = $data;
165
        }
166
167
        if ($files) {
168
            self::$__files = self::handleFiles($files);
169
        }
170
    }
171
172
    /**
173
     * Flushes the request header , body and files
174
     */
175
    public static function flush()
176
    {
177
        self::$__headers = [];
178
        self::$__request = [];
179
        self::$__files = [];
180
        self::$__protocol = null;
181
        self::$__host = null;
182
        self::$__port = null;
183
        self::$__uri = null;
184
        self::$__query = null;
185
    }
186
187
    /**
188
     * Gets the request method
189
     * @return string|null
190
     */
191
    public static function getMethod(): ?string
192
    {
193
        return self::$__method;
194
    }
195
196
    /**
197
     * Sets the request method
198
     * @param string $method
199
     * @throws HttpException
200
     */
201
    public static function setMethod(string $method)
202
    {
203
        if (!in_array(strtoupper($method), self::METHODS)) {
204
            throw HttpException::methodNotAvailable($method);
205
        }
206
207
        self::$__method = $method;
208
    }
209
210
    /**
211
     * @param string $method
212
     * @return bool
213
     */
214
    public static function isMethod(string $method): bool
215
    {
216
        return strcasecmp($method, self::$__method) == 0;
217
    }
218
219
    /**
220
     * Gets the nth segment
221
     * @param integer $number
222
     * @return string|null
223
     */
224
    public static function getSegment(int $number): ?string
225
    {
226
        $segments = self::getAllSegments();
227
228
        if (isset($segments[$number])) {
229
            return $segments[$number];
230
        }
231
232
        return null;
233
    }
234
235
    /**
236
     * Gets the segments of current URI
237
     * @return array
238
     */
239
    public static function getAllSegments(): array
240
    {
241
        $segments = explode('/', trim(parse_url(self::$__uri)['path'], '/'));
242
        array_unshift($segments, 'zero_segment');
243
        return $segments;
244
    }
245
246
    /**
247
     * Gets Cross Site Request Forgery Token
248
     * @return string|null
249
     */
250
    public static function getCsrfToken(): ?string
251
    {
252
        $csrfToken = null;
253
254
        if (self::has(Csrf::TOKEN_KEY)) {
255
            $csrfToken = (string)self::get(Csrf::TOKEN_KEY);
256
        } elseif (self::hasHeader('X-' . Csrf::TOKEN_KEY)) {
257
            $csrfToken = self::getHeader('X-' . Csrf::TOKEN_KEY);
258
        }
259
260
        return $csrfToken;
261
    }
262
263
    /**
264
     * Gets Authorization Bearer token
265
     * @return string|null
266
     */
267
    public static function getAuthorizationBearer(): ?string
268
    {
269
        $bearerToken = null;
270
271
        $authorization = (string)self::getHeader('Authorization');
272
273
        if (self::hasHeader('Authorization')) {
274
            if (preg_match('/Bearer\s(\S+)/', $authorization, $matches)) {
275
                $bearerToken = $matches[1];
276
            }
277
        }
278
279
        return $bearerToken;
280
    }
281
282
    /**
283
     * Gets Basic Auth Credentials
284
     * @return array|null
285
     */
286
    public static function getBasicAuthCredentials(): ?array
287
    {
288
        if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
289
            return [
290
                'username' => $_SERVER['PHP_AUTH_USER'],
291
                'password' => $_SERVER['PHP_AUTH_PW']
292
            ];
293
        }
294
295
        if (!self::hasHeader('Authorization')) {
296
            return null;
297
        }
298
299
        $authorization = (string)self::getHeader('Authorization');
300
301
        if (preg_match('/Basic\s(\S+)/', $authorization, $matches)) {
302
            $decoded = base64_decode($matches[1], true);
303
304
            if ($decoded && strpos($decoded, ':') !== false) {
305
                list($username, $password) = explode(':', $decoded, 2);
306
                return ['username' => $username, 'password' => $password];
307
            }
308
        }
309
310
        return null;
311
    }
312
313
    /**
314
     * Checks to see if request was AJAX request
315
     * @return bool
316
     */
317
    public static function isAjax(): bool
318
    {
319
        return self::hasHeader('X-REQUESTED-WITH') || self::$server->ajax();
320
    }
321
322
    /**
323
     * Gets the referrer
324
     * @return string|null
325
     */
326
    public static function getReferrer(): ?string
327
    {
328
        return self::$server->referrer();
329
    }
330
}
331