Passed
Push — 4.1.1 ( 01ed8a )
by Robbie
09:45
created

HTTPRequestBuilder::createFromVariables()   D

Complexity

Conditions 9
Paths 24

Size

Total Lines 44
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 21
nc 24
nop 3
dl 0
loc 44
rs 4.909
c 0
b 0
f 0
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
     * @param string|null $url Provide specific url (relative to base)
32
     * @return HTTPRequest
33
     */
34
    public static function createFromVariables(array $variables, $input, $url = null)
35
    {
36
        // Infer URL from REQUEST_URI unless explicitly provided
37
        if (!isset($url)) {
38
            // Remove query parameters (they're retained separately through $server['_GET']
39
            $url = parse_url($variables['_SERVER']['REQUEST_URI'], PHP_URL_PATH);
40
41
            // Remove base folders from the URL if webroot is hosted in a subfolder
42
            if (substr(strtolower($url), 0, strlen(BASE_URL)) === strtolower(BASE_URL)) {
43
                $url = substr($url, strlen(BASE_URL));
44
            }
45
        }
46
47
        // Build request
48
        $request = new HTTPRequest(
49
            $variables['_SERVER']['REQUEST_METHOD'],
50
            $url,
51
            $variables['_GET'],
52
            $variables['_POST'],
53
            $input
54
        );
55
56
        // Set the scheme to HTTPS if needed
57
        if ((!empty($variables['_SERVER']['HTTPS']) && $variables['_SERVER']['HTTPS'] != 'off')
58
            || isset($variables['_SERVER']['SSL'])) {
59
            $request->setScheme('https');
60
        }
61
62
        // Set the client IP
63
        if (!empty($variables['_SERVER']['REMOTE_ADDR'])) {
64
            $request->setIP($variables['_SERVER']['REMOTE_ADDR']);
65
        }
66
67
        // Add headers
68
        $headers = static::extractRequestHeaders($variables['_SERVER']);
69
        foreach ($headers as $header => $value) {
70
            $request->addHeader($header, $value);
71
        }
72
73
        // Initiate an empty session - doesn't initialize an actual PHP session (see HTTPApplication)
74
        $session = new Session(isset($variables['_SESSION']) ? $variables['_SESSION'] : null);
75
        $request->setSession($session);
76
77
        return $request;
78
    }
79
80
    /**
81
     * Takes a $_SERVER data array and extracts HTTP request headers.
82
     *
83
     * @param array $server
84
     *
85
     * @return array
86
     */
87
    public static function extractRequestHeaders(array $server)
88
    {
89
        $headers = array();
90
        foreach ($server as $key => $value) {
91
            if (substr($key, 0, 5) == 'HTTP_') {
92
                $key = substr($key, 5);
93
                $key = strtolower(str_replace('_', ' ', $key));
94
                $key = str_replace(' ', '-', ucwords($key));
95
                $headers[$key] = $value;
96
            }
97
        }
98
99
        if (isset($server['CONTENT_TYPE'])) {
100
            $headers['Content-Type'] = $server['CONTENT_TYPE'];
101
        }
102
        if (isset($server['CONTENT_LENGTH'])) {
103
            $headers['Content-Length'] = $server['CONTENT_LENGTH'];
104
        }
105
106
        // Enable HTTP Basic authentication workaround for PHP running in CGI mode with Apache
107
        // Depending on server configuration the auth header may be in HTTP_AUTHORIZATION or
108
        // REDIRECT_HTTP_AUTHORIZATION
109
        $authHeader = null;
110
        if (isset($headers['Authorization'])) {
111
            $authHeader = $headers['Authorization'];
112
        } elseif (isset($server['REDIRECT_HTTP_AUTHORIZATION'])) {
113
            $authHeader = $server['REDIRECT_HTTP_AUTHORIZATION'];
114
        }
115
116
        // Ensure basic auth is available via headers
117
        if (isset($server['PHP_AUTH_USER']) && isset($server['PHP_AUTH_PW'])) {
118
            // Shift PHP_AUTH_* into headers so they are available via request
119
            $headers['PHP_AUTH_USER'] = $server['PHP_AUTH_USER'];
120
            $headers['PHP_AUTH_PW'] = $server['PHP_AUTH_PW'];
121
        } elseif ($authHeader && preg_match('/Basic\s+(?<token>.*)$/i', $authHeader, $matches)) {
122
            list($name, $password) = explode(':', base64_decode($matches['token']));
123
            $headers['PHP_AUTH_USER'] = $name;
124
            $headers['PHP_AUTH_PW'] = $password;
125
        }
126
127
        return $headers;
128
    }
129
130
    /**
131
     * Clean up HTTP global vars for $_GET / $_REQUEST prior to bootstrapping
132
     *
133
     * @param array $variables
134
     * @return array Cleaned variables
135
     */
136
    public static function cleanEnvironment(array $variables)
137
    {
138
        // IIS will sometimes generate this.
139
        if (!empty($variables['_SERVER']['HTTP_X_ORIGINAL_URL'])) {
140
            $variables['_SERVER']['REQUEST_URI'] = $variables['_SERVER']['HTTP_X_ORIGINAL_URL'];
141
        }
142
143
        // Override REQUEST_METHOD
144
        if (isset($variables['_SERVER']['X-HTTP-Method-Override'])) {
145
            $variables['_SERVER']['REQUEST_METHOD'] = $variables['_SERVER']['X-HTTP-Method-Override'];
146
        }
147
148
        // Merge $_FILES into $_POST
149
        $variables['_POST'] = array_merge((array)$variables['_POST'], (array)$variables['_FILES']);
150
151
        // 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...
152
        $variables['_REQUEST'] = array_merge(
153
            (array)$variables['_GET'],
154
            (array)$variables['_POST'],
155
            (array)$variables['_COOKIE']
156
        );
157
158
        return $variables;
159
    }
160
}
161