Passed
Pull Request — 4.0 (#7723)
by Damian
08:16
created

HTTPRequestBuilder::extractRequestHeaders()   C

Complexity

Conditions 11
Paths 108

Size

Total Lines 41
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 24
nc 108
nop 1
dl 0
loc 41
rs 5.1372
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace SilverStripe\Control;
4
5
use SilverStripe\Core\Environment;
6
7
class HTTPRequestBuilder
8
{
9
    /**
10
     * Create HTTPRequest instance from the current environment variables.
11
     * May throw errors if request is invalid.
12
     *
13
     * @throws HTTPResponse_Exception
14
     * @return HTTPRequest
15
     */
16
    public static function createFromEnvironment()
17
    {
18
        // Clean and update live global variables
19
        $variables = static::cleanEnvironment(Environment::getVariables());
20
        Environment::setVariables($variables); // Currently necessary for SSViewer, etc to work
21
22
        // Health-check prior to creating environment
23
        return static::createFromVariables($variables, @file_get_contents('php://input'));
24
    }
25
26
    /**
27
     * Build HTTPRequest from given variables
28
     *
29
     * @param array $variables
30
     * @param string $input Request body
31
     * @return HTTPRequest
32
     */
33
    public static function createFromVariables(array $variables, $input)
34
    {
35
        // Remove query parameters (they're retained separately through $server['_GET']
36
        $url = parse_url($variables['_SERVER']['REQUEST_URI'], PHP_URL_PATH);
37
38
        // Remove base folders from the URL if webroot is hosted in a subfolder
39
        if (substr(strtolower($url), 0, strlen(BASE_URL)) === strtolower(BASE_URL)) {
40
            $url = substr($url, strlen(BASE_URL));
41
        }
42
43
        // Build request
44
        $request = new HTTPRequest(
45
            $variables['_SERVER']['REQUEST_METHOD'],
46
            $url,
47
            $variables['_GET'],
48
            $variables['_POST'],
49
            $input
50
        );
51
52
        // Set the scheme to HTTPS if needed
53
        if ((!empty($variables['_SERVER']['HTTPS']) && $variables['_SERVER']['HTTPS'] != 'off')
54
            || isset($variables['_SERVER']['SSL'])) {
55
            $request->setScheme('https');
56
        }
57
58
        // Set the client IP
59
        if (!empty($variables['_SERVER']['REMOTE_ADDR'])) {
60
            $request->setIP($variables['_SERVER']['REMOTE_ADDR']);
61
        }
62
63
        // Add headers
64
        $headers = static::extractRequestHeaders($variables['_SERVER']);
65
        foreach ($headers as $header => $value) {
66
            $request->addHeader($header, $value);
67
        }
68
69
        // Initiate an empty session - doesn't initialize an actual PHP session (see HTTPApplication)
70
        $session = new Session(isset($variables['_SESSION']) ? $variables['_SESSION'] : null);
71
        $request->setSession($session);
72
73
        return $request;
74
    }
75
76
    /**
77
     * Takes a $_SERVER data array and extracts HTTP request headers.
78
     *
79
     * @param array $server
80
     *
81
     * @return array
82
     */
83
    public static function extractRequestHeaders(array $server)
84
    {
85
        $headers = array();
86
        foreach ($server as $key => $value) {
87
            if (substr($key, 0, 5) == 'HTTP_') {
88
                $key = substr($key, 5);
89
                $key = strtolower(str_replace('_', ' ', $key));
90
                $key = str_replace(' ', '-', ucwords($key));
91
                $headers[$key] = $value;
92
            }
93
        }
94
95
        if (isset($server['CONTENT_TYPE'])) {
96
            $headers['Content-Type'] = $server['CONTENT_TYPE'];
97
        }
98
        if (isset($server['CONTENT_LENGTH'])) {
99
            $headers['Content-Length'] = $server['CONTENT_LENGTH'];
100
        }
101
102
        // Enable HTTP Basic authentication workaround for PHP running in CGI mode with Apache
103
        // Depending on server configuration the auth header may be in HTTP_AUTHORIZATION or
104
        // REDIRECT_HTTP_AUTHORIZATION
105
        $authHeader = null;
106
        if (isset($headers['Authorization'])) {
107
            $authHeader = $headers['Authorization'];
108
        } elseif (isset($server['REDIRECT_HTTP_AUTHORIZATION'])) {
109
            $authHeader = $server['REDIRECT_HTTP_AUTHORIZATION'];
110
        }
111
112
        // Ensure basic auth is available via headers
113
        if (isset($server['PHP_AUTH_USER']) && isset($server['PHP_AUTH_PW'])) {
114
            // Shift PHP_AUTH_* into headers so they are available via request
115
            $headers['PHP_AUTH_USER'] = $server['PHP_AUTH_USER'];
116
            $headers['PHP_AUTH_PW'] = $server['PHP_AUTH_PW'];
117
        } elseif ($authHeader && preg_match('/Basic\s+(?<token>.*)$/i', $authHeader, $matches)) {
118
            list($name, $password) = explode(':', base64_decode($matches['token']));
119
            $headers['PHP_AUTH_USER'] = $name;
120
            $headers['PHP_AUTH_PW'] = $password;
121
        }
122
123
        return $headers;
124
    }
125
126
    /**
127
     * Clean up HTTP global vars for $_GET / $_REQUEST prior to bootstrapping
128
     *
129
     * @param array $variables
130
     * @return array Cleaned variables
131
     */
132
    public static function cleanEnvironment(array $variables)
133
    {
134
        // IIS will sometimes generate this.
135
        if (!empty($variables['_SERVER']['HTTP_X_ORIGINAL_URL'])) {
136
            $variables['_SERVER']['REQUEST_URI'] = $variables['_SERVER']['HTTP_X_ORIGINAL_URL'];
137
        }
138
139
        // Override REQUEST_METHOD
140
        if (isset($variables['_SERVER']['X-HTTP-Method-Override'])) {
141
            $variables['_SERVER']['REQUEST_METHOD'] = $variables['_SERVER']['X-HTTP-Method-Override'];
142
        }
143
144
        // Merge $_FILES into $_POST
145
        $variables['_POST'] = array_merge((array)$variables['_POST'], (array)$variables['_FILES']);
146
147
        // Merge $_POST, $_GET, and $_COOKIE into $_REQUEST
0 ignored issues
show
Unused Code Comprehensibility introduced by
44% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
148
        $variables['_REQUEST'] = array_merge(
149
            (array)$variables['_GET'],
150
            (array)$variables['_POST'],
151
            (array)$variables['_COOKIE']
152
        );
153
154
        return $variables;
155
    }
156
}
157