Passed
Push — orm-dm ( fe3818...c3badf )
by Nikolaos
22:30 queued 19:58
created

ServerRequestFactory::parseCookieHeader()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1.0019

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 1
dl 0
loc 16
ccs 7
cts 8
cp 0.875
crap 1.0019
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of the Phalcon Framework.
5
 *
6
 * (c) Phalcon Team <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE.txt
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Phalcon\Http\Message;
15
16
use Phalcon\Collection;
17
use Phalcon\Helper\Arr;
18
use Phalcon\Http\Message\Traits\ServerRequestFactoryTrait;
19
use Psr\Http\Message\ServerRequestFactoryInterface;
20
use Psr\Http\Message\ServerRequestInterface;
21
use Psr\Http\Message\UriInterface;
22
23
use function apache_request_headers;
24
use function function_exists;
25
use function parse_str;
26
use function str_replace;
27
use function substr;
28
29
class ServerRequestFactory implements ServerRequestFactoryInterface
30
{
31
    use ServerRequestFactoryTrait;
32
33
    /**
34
     * Create a new server request.
35
     *
36
     * Note that server-params are taken precisely as given - no
37
     * parsing/processing of the given values is performed, and, in particular,
38
     * no attempt is made to determine the HTTP method or URI, which must be
39
     * provided explicitly.
40
     *
41
     * @param string              $method       The HTTP method associated with
42
     *                                          the request.
43
     * @param UriInterface|string $uri          The URI associated with the
44
     *                                          request. If the value is a
45
     *                                          string, the factory MUST create
46
     *                                          a UriInterface instance based
47
     *                                          on it.
48
     * @param array               $serverParams Array of SAPI parameters with
49
     *                                          which to seed the generated
50
     *                                          request instance.
51
     *
52
     * @return ServerRequestInterface
53
     */
54 1
    public function createServerRequest(
55
        string $method,
56
        $uri,
57
        array $serverParams = []
58
    ): ServerRequestInterface {
59 1
        return new ServerRequest($method, $uri, $serverParams);
60
    }
61
62
    /**
63
     * Create a request from the supplied superglobal values.
64
     *
65
     * If any argument is not supplied, the corresponding superglobal value will
66
     * be used.
67
     *
68
     * The ServerRequest created is then passed to the fromServer() method in
69
     * order to marshal the request URI and headers.
70
     *
71
     * @param array $server  $_SERVER superglobal
72
     * @param array $get     $_GET superglobal
73
     * @param array $post    $_POST superglobal
74
     * @param array $cookies $_COOKIE superglobal
75
     * @param array $files   $_FILES superglobal
76
     *
77
     * @return ServerRequest
78
     * @see fromServer()
79
     */
80 12
    public function load(
81
        array $server = [],
82
        array $get = [],
83
        array $post = [],
84
        array $cookies = [],
85
        array $files = []
86
    ): ServerRequest {
87 12
        $method   = Arr::get($server, 'REQUEST_METHOD', 'GET');
88 12
        $protocol = Arr::get($server, 'SERVER_PROTOCOL', '1.1');
89
90 12
        $server  = $this->parseServer($server);
91 12
        $headers = $this->parseHeaders($server);
92 12
        $files   = $this->parseUploadedFiles($files);
93
94 11
        if (empty($cookies) && $headers->has('cookie')) {
95 1
            $cookies = $this->parseCookieHeader($headers->get('cookie'));
96
        }
97
98 11
        return new ServerRequest(
99 11
            $method,
0 ignored issues
show
Bug introduced by
It seems like $method can also be of type null; however, parameter $method of Phalcon\Http\Message\ServerRequest::__construct() does only seem to accept 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

99
            /** @scrutinizer ignore-type */ $method,
Loading history...
100 11
            $this->parseUri($server, $headers),
101 11
            $server->toArray(),
102 11
            'php://input',
103 11
            $headers->toArray(),
104
            $cookies,
105
            $get,
106 11
            $files->toArray(),
107
            $post,
108
            $protocol
0 ignored issues
show
Bug introduced by
It seems like $protocol can also be of type null; however, parameter $protocol of Phalcon\Http\Message\ServerRequest::__construct() does only seem to accept 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

108
            /** @scrutinizer ignore-type */ $protocol
Loading history...
109
        );
110
    }
111
112
    /**
113
     * Returns the apache_request_headers if it exists
114
     *
115
     * @return array|false
116
     */
117 11
    protected function getHeaders()
118
    {
119 11
        if (function_exists('apache_request_headers')) {
120
            return apache_request_headers();
121
        }
122
123 11
        return false;
124
    }
125
126
    /**
127
     * Checks if a header starts with CONTENT_ and adds it to the collection
128
     *
129
     * @param string     $key
130
     * @param mixed      $value
131
     * @param Collection $headers
132
     */
133 9
    private function checkContentHeader(string $key, $value, Collection $headers): void
134
    {
135 9
        if (mb_strpos($key, 'CONTENT_') === 0) {
136 1
            $key  = (string) substr($key, 8);
137 1
            $name = 'content-' . mb_strtolower($key);
138 1
            $headers->set($name, $value);
139
        }
140 9
    }
141
142
    /**
143
     * Checks if a header starts with HTTP_ and adds it to the collection
144
     *
145
     * @param string     $key
146
     * @param mixed      $value
147
     * @param Collection $headers
148
     */
149 9
    private function checkHttpHeader(string $key, $value, Collection $headers): void
150
    {
151 9
        if (mb_strpos($key, 'HTTP_') === 0) {
152 5
            $name = str_replace(
153 5
                '_',
154 5
                '-',
155 5
                mb_strtolower(substr($key, 5))
156
            );
157 5
            $headers->set($name, $value);
158
        }
159 9
    }
160
161
    /**
162
     * Parse a cookie header according to RFC 6265.
163
     *
164
     * @param string $cookieHeader A string cookie header value.
165
     *
166
     * @return array key/value cookie pairs.
167
     *
168
     */
169 1
    private function parseCookieHeader($cookieHeader): array
170
    {
171 1
        $cookies = [];
172 1
        parse_str(
173
            strtr(
174 1
                $cookieHeader,
175
                [
176 1
                    '&' => '%26',
177
                    '+' => '%2B',
178
                    ';' => '&',
179
                ]
180
            ),
181 1
            $cookies
182
        );
183
184 1
        return $cookies;
185
    }
186
187
    /**
188
     * Processes headers from SAPI
189
     *
190
     * @param Collection $server
191
     *
192
     * @return Collection
193
     */
194 12
    private function parseHeaders(Collection $server): Collection
195
    {
196 12
        $headers = new Collection();
197 12
        foreach ($server as $key => $value) {
198 9
            if ('' !== $value) {
199
                /**
200
                 * Apache prefixes environment variables with REDIRECT_
201
                 * if they are added by rewrite rules
202
                 */
203 9
                if (mb_strpos($key, 'REDIRECT_') === 0) {
204 1
                    $key = (string) substr($key, 9);
205
                    /**
206
                     * We will not overwrite existing variables with the
207
                     * prefixed versions, though
208
                     */
209 1
                    if ($server->has($key)) {
210 1
                        continue;
211
                    }
212
                }
213
214 9
                $this->checkHttpHeader($key, $value, $headers);
215 9
                $this->checkContentHeader($key, $value, $headers);
216
            }
217
        }
218
219 12
        return $headers;
220
    }
221
222
    /**
223
     * Parse the $_SERVER array amd return it back after looking for the
224
     * authorization header
225
     *
226
     * @param array $server Either verbatim, or with an added
227
     *                      HTTP_AUTHORIZATION header.
228
     *
229
     * @return Collection
230
     */
231 12
    private function parseServer(array $server): Collection
232
    {
233 12
        $collection = new Collection($server);
234 12
        $headers    = $this->getHeaders();
235
236 12
        if (true !== $collection->has("HTTP_AUTHORIZATION") && false !== $headers) {
237 1
            $headersCollection = new Collection($headers);
238
239 1
            if ($headersCollection->has('Authorization')) {
240 1
                $collection->set(
241 1
                    'HTTP_AUTHORIZATION',
242 1
                    $headersCollection->get('Authorization')
243
                );
244
            }
245
        }
246
247 12
        return $collection;
248
    }
249
}
250