ServerRequestFactory::detectProtocolVersion()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 5
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cakasim\Payone\Sdk\Http\Factory;
6
7
use Cakasim\Payone\Sdk\Http\Message\ServerRequest;
8
use Psr\Http\Message\ServerRequestFactoryInterface;
9
use Psr\Http\Message\ServerRequestInterface;
10
use Psr\Http\Message\StreamFactoryInterface;
11
use Psr\Http\Message\UriFactoryInterface;
12
use Psr\Http\Message\UriInterface;
13
14
/**
15
 * Implements the PSR-17 server request factory interface.
16
 *
17
 * @author Fabian Böttcher <[email protected]>
18
 * @since 0.1.0
19
 */
20
class ServerRequestFactory implements ServerRequestFactoryInterface
21
{
22
    protected const DEFAULT_PROTOCOL_VERSION = ServerRequest::PROTOCOL_VERSION_1_1;
23
24
    /**
25
     * @var UriFactoryInterface The URI factory used for generating request URIs.
26
     */
27
    protected $uriFactory;
28
29
    /**
30
     * @var StreamFactoryInterface The stream factory used for generating request bodies.
31
     */
32
    protected $streamFactory;
33
34
    /**
35
     * Constructs the RequestFactory.
36
     *
37
     * @param UriFactoryInterface $uriFactory A URI factory.
38
     * @param StreamFactoryInterface $streamFactory A stream factory.
39
     */
40
    public function __construct(UriFactoryInterface $uriFactory, StreamFactoryInterface $streamFactory)
41
    {
42
        $this->uriFactory = $uriFactory;
43
        $this->streamFactory = $streamFactory;
44
    }
45
46
    /**
47
     * @inheritDoc
48
     */
49
    public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface
50
    {
51
        if (!($uri instanceof UriInterface)) {
52
            $uri = $this->uriFactory->createUri($uri);
53
        }
54
55
        $protocolVersion = $this->detectProtocolVersion($serverParams) ?? static::DEFAULT_PROTOCOL_VERSION;
56
        $body = $this->streamFactory->createStreamFromFile('php://input', 'r');
57
        $headers = $this->detectRequestHeaders($serverParams);
58
59
        $request = new ServerRequest(
60
            $method,
61
            $uri,
62
            $protocolVersion,
63
            $body,
64
            $headers,
65
            $serverParams,
66
            $_COOKIE,
67
            $_GET,
68
            [], // currently no support for uploaded files
69
            null,
70
            []
71
        );
72
73
        $parsedBody = $this->detectParsedBody($request);
74
75
        if ($parsedBody !== null) {
76
            $request = $request->withParsedBody($parsedBody);
77
        }
78
79
        return $request;
80
    }
81
82
    /**
83
     * Detect protocol version from server params.
84
     *
85
     * @param array $serverParams The server params.
86
     * @return string|null The detected protocol version or null if not detectable.
87
     */
88
    protected function detectProtocolVersion(array $serverParams): ?string
89
    {
90
        $matches = [];
91
        preg_match('~^HTTP/(\d+(?:\.\d+)?)$~i', trim($serverParams['SERVER_PROTOCOL'] ?? ''), $matches);
92
        return $matches[1] ?? null;
93
    }
94
95
    /**
96
     * Detect request headers from server params.
97
     * Convert all HTTP prefixed server params to headers.
98
     *
99
     * @param array $serverParams The server params.
100
     * @return array The detected headers.
101
     */
102
    protected function detectRequestHeaders(array $serverParams): array
103
    {
104
        // Filter server params and preserve all HTTP_* params.
105
        $serverParams = array_filter($serverParams, function ($name) {
106
            return substr($name, 0, 5) === 'HTTP_';
107
        }, ARRAY_FILTER_USE_KEY);
108
109
        $headers = [];
110
111
        foreach ($serverParams as $name => $value) {
112
            // Remove HTTP_ prefix.
113
            $name = substr($name, 5);
114
115
            // Make name lowercase.
116
            $name = strtolower($name);
117
118
            // Split name into parts.
119
            $name = explode('_', $name);
120
121
            // Make each name part start with uppercase character.
122
            $name = array_map('ucfirst', $name);
123
124
            // Rejoin name parts by - separator.
125
            $name = join('-', $name);
126
127
            // Store the header.
128
            $headers[$name] = $value;
129
        }
130
131
        return $headers;
132
    }
133
134
    /**
135
     * Detect parsed body from $_POST.
136
     *
137
     * @param ServerRequest $request The request for which the parsed body should be detected.
138
     * @return array|null The parsed body or null if no parsed body exists.
139
     */
140
    protected function detectParsedBody(ServerRequest $request): ?array
141
    {
142
        $contentTypeHeader = $request->getHeaderLine('Content-Type');
143
144
        return
145
            strcasecmp($request->getMethod(), 'POST') === 0 &&
146
            (
147
                stristr($contentTypeHeader, 'application/x-www-form-urlencoded') !== false ||
148
                stristr($contentTypeHeader, 'multipart/form-data') !== false
149
            )
150
            ? $_POST
151
            : null;
152
    }
153
}
154