/www/slight

To get this branch, use:
bzr branch http://bzr.ed.am/www/slight
1 by Tim Marston
initial commit
1
<?php
2
/**
3
 * Flight: An extensible micro-framework.
4
 *
5
 * @copyright   Copyright (c) 2011, Mike Cao <mike@mikecao.com>
6
 * @license     MIT, http://flightphp.com/license
7
 */
8
9
namespace flight\net;
10
11
use flight\util\Collection;
12
13
/**
14
 * The Request class represents an HTTP request. Data from
15
 * all the super globals $_GET, $_POST, $_COOKIE, and $_FILES
16
 * are stored and accessible via the Request object.
17
 *
18
 * The default request properties are:
19
 *   url - The URL being requested
20
 *   base - The parent subdirectory of the URL
21
 *   method - The request method (GET, POST, PUT, DELETE)
22
 *   referrer - The referrer URL
23
 *   ip - IP address of the client
24
 *   ajax - Whether the request is an AJAX request
25
 *   scheme - The server protocol (http, https)
26
 *   user_agent - Browser information
27
 *   type - The content type
28
 *   length - The content length
29
 *   query - Query string parameters
30
 *   data - Post parameters
31
 *   cookies - Cookie parameters
32
 *   files - Uploaded files
33
 *   secure - Connection is secure
34
 *   accept - HTTP accept parameters
35
 *   proxy_ip - Proxy IP address of the client
36
 */
37
class Request {
38
    /**
39
     * @var string URL being requested
40
     */
41
    public $url;
42
43
    /**
44
     * @var string Parent subdirectory of the URL
45
     */
46
    public $base;
47
48
    /**
49
     * @var string Request method (GET, POST, PUT, DELETE)
50
     */
51
    public $method;
52
53
    /**
54
     * @var string Referrer URL
55
     */
56
    public $referrer;
57
58
    /**
59
     * @var string IP address of the client
60
     */
61
    public $ip;
62
63
    /**
64
     * @var bool Whether the request is an AJAX request
65
     */
66
    public $ajax;
67
68
    /**
69
     * @var string Server protocol (http, https)
70
     */
71
    public $scheme;
72
73
    /**
74
     * @var string Browser information
75
     */
76
    public $user_agent;
77
78
    /**
79
     * @var string Content type
80
     */
81
    public $type;
82
83
    /**
84
     * @var int Content length
85
     */
86
    public $length;
87
88
    /**
89
     * @var \flight\util\Collection Query string parameters
90
     */
91
    public $query;
92
93
    /**
94
     * @var \flight\util\Collection Post parameters
95
     */
96
    public $data;
97
98
    /**
99
     * @var \flight\util\Collection Cookie parameters
100
     */
101
    public $cookies;
102
103
    /**
104
     * @var \flight\util\Collection Uploaded files
105
     */
106
    public $files;
107
108
    /**
109
     * @var bool Whether the connection is secure
110
     */
111
    public $secure;
112
113
    /**
114
     * @var string HTTP accept parameters
115
     */
116
    public $accept;
117
118
    /**
119
     * @var string Proxy IP address of the client
120
     */
121
    public $proxy_ip;
122
123
    /**
124
     * Constructor.
125
     *
126
     * @param array $config Request configuration
127
     */
128
    public function __construct($config = array()) {
129
        // Default properties
130
        if (empty($config)) {
131
            $config = array(
132
                'url' => self::getVar('REQUEST_URI', '/'),
133
                'base' => str_replace(array('\\',' '), array('/','%20'), dirname(self::getVar('SCRIPT_NAME'))),
134
                'method' => self::getMethod(),
135
                'referrer' => self::getVar('HTTP_REFERER'),
136
                'ip' => self::getVar('REMOTE_ADDR'),
137
                'ajax' => self::getVar('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest',
138
                'scheme' => self::getVar('SERVER_PROTOCOL', 'HTTP/1.1'),
139
                'user_agent' => self::getVar('HTTP_USER_AGENT'),
140
                'type' => self::getVar('CONTENT_TYPE'),
141
                'length' => self::getVar('CONTENT_LENGTH', 0),
142
                'query' => new Collection($_GET),
143
                'data' => new Collection($_POST),
144
                'cookies' => new Collection($_COOKIE),
145
                'files' => new Collection($_FILES),
146
                'secure' => self::getVar('HTTPS', 'off') != 'off',
147
                'accept' => self::getVar('HTTP_ACCEPT'),
148
                'proxy_ip' => self::getProxyIpAddress()
149
            );
150
        }
151
152
        $this->init($config);
153
    }
154
155
    /**
156
     * Initialize request properties.
157
     *
158
     * @param array $properties Array of request properties
159
     */
160
    public function init($properties = array()) {
161
        // Set all the defined properties
162
        foreach ($properties as $name => $value) {
163
            $this->$name = $value;
164
        }
165
166
        // Get the requested URL without the base directory
167
        if ($this->base != '/' && strlen($this->base) > 0 && strpos($this->url, $this->base) === 0) {
168
            $this->url = substr($this->url, strlen($this->base));
169
        }
170
171
        // Default url
172
        if (empty($this->url)) {
173
            $this->url = '/';
174
        }
175
        // Merge URL query parameters with $_GET
176
        else {
177
            $_GET += self::parseQuery($this->url);
178
179
            $this->query->setData($_GET);
180
        }
181
182
        // Check for JSON input
183
        if (strpos($this->type, 'application/json') === 0) {
184
            $body = $this->getBody();
185
            if ($body != '') {
186
                $data = json_decode($body, true);
187
                if ($data != null) {
188
                    $this->data->setData($data);
189
                }
190
            }
191
        }
192
    }
193
194
    /**
195
     * Gets the body of the request.
196
     *
197
     * @return string Raw HTTP request body
198
     */
199
    public static function getBody() {
200
        static $body;
201
202
        if (!is_null($body)) {
203
            return $body;
204
        }
205
206
        $method = self::getMethod();
207
208
        if ($method == 'POST' || $method == 'PUT' || $method == 'PATCH') {
209
            $body = file_get_contents('php://input');
210
        }
211
212
        return $body;
213
    }
214
215
    /**
216
     * Gets the request method.
217
     *
218
     * @return string
219
     */
220
    public static function getMethod() {
221
        $method = self::getVar('REQUEST_METHOD', 'GET');
222
223
        if (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
224
            $method = $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'];
225
        }
226
        elseif (isset($_REQUEST['_method'])) {
227
            $method = $_REQUEST['_method'];
228
        }
229
230
        return strtoupper($method);
231
    }
232
233
    /**
234
     * Gets the real remote IP address.
235
     *
236
     * @return string IP address
237
     */
238
    public static function getProxyIpAddress() {
239
        static $forwarded = array(
240
            'HTTP_CLIENT_IP',
241
            'HTTP_X_FORWARDED_FOR',
242
            'HTTP_X_FORWARDED',
243
            'HTTP_X_CLUSTER_CLIENT_IP',
244
            'HTTP_FORWARDED_FOR',
245
            'HTTP_FORWARDED'
246
        );
247
248
        $flags = \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE;
249
250
        foreach ($forwarded as $key) {
251
            if (array_key_exists($key, $_SERVER)) {
252
                sscanf($_SERVER[$key], '%[^,]', $ip);
253
                if (filter_var($ip, \FILTER_VALIDATE_IP, $flags) !== false) {
254
                    return $ip;
255
                }
256
            }
257
        }
258
259
        return '';
260
    }
261
262
    /**
263
     * Gets a variable from $_SERVER using $default if not provided.
264
     *
265
     * @param string $var Variable name
266
     * @param string $default Default value to substitute
267
     * @return string Server variable value
268
     */
269
    public static function getVar($var, $default = '') {
270
        return isset($_SERVER[$var]) ? $_SERVER[$var] : $default;
271
    }
272
273
    /**
274
     * Parse query parameters from a URL.
275
     *
276
     * @param string $url URL string
277
     * @return array Query parameters
278
     */
279
    public static function parseQuery($url) {
280
        $params = array();
281
282
        $args = parse_url($url);
283
        if (isset($args['query'])) {
284
            parse_str($args['query'], $params);
285
        }
286
287
        return $params;
288
    }
289
}