Completed
Pull Request — master (#24)
by
unknown
03:52
created

getPhpServerValuesFromPlainHeader()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 10
nc 2
nop 1
dl 0
loc 14
ccs 9
cts 9
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
namespace Wandu\Http\Factory;
3
4
use Psr\Http\Message\StreamInterface;
5
use Wandu\Http\Psr\ServerRequest;
6
use Wandu\Http\Psr\Stream;
7
use Wandu\Http\Psr\Stream\PhpInputStream;
8
use Wandu\Http\Psr\Uri;
9
10
class ServerRequestFactory
11
{
12
    use HelperTrait;
13
14
    /** @var \Wandu\Http\Factory\UploadedFileFactory */
15
    protected $fileFactory;
16
17
    /**
18
     * @param \Wandu\Http\Factory\UploadedFileFactory $fileFactory
19
     */
20 17
    public function __construct(UploadedFileFactory $fileFactory)
21
    {
22 17
        $this->fileFactory = $fileFactory;
23 17
    }
24
25
    /**
26
     * @return \Psr\Http\Message\ServerRequestInterface
27
     */
28 1
    public function createFromGlobals()
0 ignored issues
show
Coding Style introduced by
createFromGlobals uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
createFromGlobals uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
createFromGlobals uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
createFromGlobals uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
createFromGlobals uses the super-global variable $_FILES which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
29
    {
30 1
        return $this->create($_SERVER, $_GET, $_POST, $_COOKIE, $_FILES, new PhpInputStream());
31
    }
32
33
    /**
34
     * @param string $body
35
     * @return \Psr\Http\Message\ServerRequestInterface
36
     */
37 1
    public function createFromSocketBody($body)
38
    {
39 1
        $lines = array_map('trim', explode("\n", $body));
40 1
        $blankKey = array_search('', $lines);
41
42 1
        $phpServer = $this->getPhpServerValuesFromPlainHeader(array_slice($lines, 0, $blankKey));
43
44 1
        return $this->create($phpServer, [], [], [], []);
45
    }
46
47
    /**
48
     * @param array $server
49
     * @param array $get
50
     * @param array $post
51
     * @param array $cookies
52
     * @param array $files
53
     * @param \Psr\Http\Message\StreamInterface $stream
54
     * @return \Psr\Http\Message\ServerRequestInterface
55
     */
56 17
    public function create(
57
        array $server,
58
        array $get,
59
        array $post,
60
        array $cookies,
61
        array $files,
62
        StreamInterface $stream = null
63
    ) {
64 17
        if (!isset($stream)) {
65 5
            $stream = new Stream('php://memory');
66
        }
67 17
        $headers = $this->getPsrHeadersFromServerParams($server);
68
69
        // exists body, but not exists posts
70 17
        $bodyContent = $stream->__toString();
71 17
        if ($bodyContent !== '' && count($post) === 0) {
72 10
            if (isset($headers['content-type'])) {
73
                // do not define multipart/form-data
74
                // because, it use only in POST method.
75
                // ref. en: https://issues.apache.org/jira/browse/FILEUPLOAD-197#comment-13595136
76
                // ref. kr: https://blog.outsider.ne.kr/1001
77 10
                if (strpos($headers['content-type'], 'application/json') === 0) {
78 6
                    $jsonBody = json_decode($bodyContent, true);
79 6
                    $post = $jsonBody ? $jsonBody : $post;
80 4
                } elseif (strpos($headers['content-type'], 'application/x-www-form-urlencoded') === 0) {
81 4
                    parse_str($bodyContent, $post);
82
                }
83
            }
84
        }
85 17
        return new ServerRequest(
86 17
            $server,
87 17
            $get,
88 17
            $post,
89 17
            $cookies,
90 17
            $this->fileFactory->createFromFiles($files),
91 17
            [],
92 17
            isset($server['REQUEST_METHOD']) ? $server['REQUEST_METHOD'] : 'GET',
93 17
            $this->getUri($server),
94 17
            $stream,
95 17
            $headers,
96 17
            '1.1'
97
        );
98
    }
99
100
    /**
101
     * Parse plain headers.
102
     *
103
     * @param array $plainHeaders
104
     * @return array
105
     */
106 1
    protected function getPhpServerValuesFromPlainHeader(array $plainHeaders)
107
    {
108 1
        $httpInformation = explode(' ', array_shift($plainHeaders));
109
        $servers = [
110 1
            'REQUEST_METHOD' => $httpInformation[0],
111 1
            'REQUEST_URI' => $httpInformation[1],
112 1
            'SERVER_PROTOCOL' => $httpInformation[2],
113
        ];
114 1
        foreach ($plainHeaders as $plainHeader) {
115 1
            list($key, $value) = array_map('trim', explode(':', $plainHeader, 2));
116 1
            $servers['HTTP_' . strtoupper(str_replace('-', '_', $key))] = $value;
117
        }
118 1
        return $servers;
119
    }
120
121
    /**
122
     * @param array $server
123
     * @return \Wandu\Http\Psr\Uri
124
     */
125 17
    protected function getUri(array $server)
126
    {
127 17
        $stringUri = $this->getHostAndPort($server);
128 17
        if ($stringUri !== '') {
129 5
            $stringUri = $this->getScheme($server) . '://' . $stringUri;
130
        }
131 17
        $stringUri .= $this->getRequestUri($server);
132 17
        return new Uri($stringUri);
133
    }
134
135
    /**
136
     * @param array $server
137
     * @return string
138
     */
139 5
    protected function getScheme(array $server)
140
    {
141 5
        if ((isset($server['HTTPS']) && $server['HTTPS'] !== 'off')
142 5
            || (isset($server['HTTP_X_FORWAREDED_PROTO']) && $server['HTTP_X_FORWAREDED_PROTO'] === 'https')) {
143
            return 'https';
144
        }
145 5
        return 'http';
146
    }
147
148
    /**
149
     * @param array $server
150
     * @return string
151
     */
152 17
    protected function getHostAndPort(array $server)
153
    {
154 17
        if (isset($server['HTTP_HOST'])) {
155 4
            return $server['HTTP_HOST'];
156
        }
157 13
        if (!isset($server['SERVER_NAME'])) {
158 12
            return '';
159
        }
160 1
        $host = $server['SERVER_NAME'];
161 1
        if (isset($server['SERVER_PORT'])) {
162 1
            $host .= ':' . $server['SERVER_PORT'];
163
        }
164 1
        return $host;
165
    }
166
167
    /**
168
     * @param array $server
169
     * @return string
170
     */
171 17
    protected function getRequestUri(array $server)
172
    {
173 17
        if (isset($server['REQUEST_URI'])) {
174 4
            return $server['REQUEST_URI'];
175
        }
176 13
        return '/';
177
    }
178
}
179