1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
|
<?php defined('SYSPATH') OR die('No direct access allowed.');
/**
* Request helper class.
*
* $Id$
*
* @package Core
* @author Kohana Team
* @copyright (c) 2007-2008 Kohana Team
* @license http://kohanaphp.com/license.html
*/
class request_Core {
// Possible HTTP methods
protected static $http_methods = array('get', 'head', 'options', 'post', 'put', 'delete');
// Content types from client's HTTP Accept request header (array)
protected static $accept_types;
/**
* Returns the HTTP referrer, or the default if the referrer is not set.
*
* @param mixed default to return
* @return string
*/
public static function referrer($default = FALSE)
{
if ( ! empty($_SERVER['HTTP_REFERER']))
{
// Set referrer
$ref = $_SERVER['HTTP_REFERER'];
if (strpos($ref, url::base(FALSE)) === 0)
{
// Remove the base URL from the referrer
$ref = substr($ref, strlen(url::base(TRUE)));
}
}
return isset($ref) ? $ref : $default;
}
/**
* Returns the current request protocol, based on $_SERVER['https']. In CLI
* mode, NULL will be returned.
*
* @return string
*/
public static function protocol()
{
if (PHP_SAPI === 'cli')
{
return NULL;
}
elseif ( ! empty($_SERVER['HTTPS']) AND $_SERVER['HTTPS'] === 'on')
{
return 'https';
}
else
{
return 'http';
}
}
/**
* Tests if the current request is an AJAX request by checking the X-Requested-With HTTP
* request header that most popular JS frameworks now set for AJAX calls.
*
* @return boolean
*/
public static function is_ajax()
{
return (isset($_SERVER['HTTP_X_REQUESTED_WITH']) AND strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest');
}
/**
* Returns current request method.
*
* @throws Kohana_Exception in case of an unknown request method
* @return string
*/
public static function method()
{
$method = strtolower($_SERVER['REQUEST_METHOD']);
if ( ! in_array($method, request::$http_methods))
throw new Kohana_Exception('request.unknown_method', $method);
return $method;
}
/**
* Returns boolean of whether client accepts content type.
*
* @param string content type
* @param boolean set to TRUE to disable wildcard checking
* @return boolean
*/
public static function accepts($type = NULL, $explicit_check = FALSE)
{
request::parse_accept_header();
if ($type === NULL)
return request::$accept_types;
return (request::accepts_at_quality($type, $explicit_check) > 0);
}
/**
* Compare the q values for given array of content types and return the one with the highest value.
* If items are found to have the same q value, the first one encountered in the given array wins.
* If all items in the given array have a q value of 0, FALSE is returned.
*
* @param array content types
* @param boolean set to TRUE to disable wildcard checking
* @return mixed string mime type with highest q value, FALSE if none of the given types are accepted
*/
public static function preferred_accept($types, $explicit_check = FALSE)
{
// Initialize
$mime_types = array();
$max_q = 0;
$preferred = FALSE;
// Load q values for all given content types
foreach (array_unique($types) as $type)
{
$mime_types[$type] = request::accepts_at_quality($type, $explicit_check);
}
// Look for the highest q value
foreach ($mime_types as $type => $q)
{
if ($q > $max_q)
{
$max_q = $q;
$preferred = $type;
}
}
return $preferred;
}
/**
* Returns quality factor at which the client accepts content type.
*
* @param string content type (e.g. "image/jpg", "jpg")
* @param boolean set to TRUE to disable wildcard checking
* @return integer|float
*/
public static function accepts_at_quality($type = NULL, $explicit_check = FALSE)
{
request::parse_accept_header();
// Normalize type
$type = strtolower((string) $type);
// General content type (e.g. "jpg")
if (strpos($type, '/') === FALSE)
{
// Don't accept anything by default
$q = 0;
// Look up relevant mime types
foreach ((array) Kohana::config('mimes.'.$type) as $type)
{
$q2 = request::accepts_at_quality($type, $explicit_check);
$q = ($q2 > $q) ? $q2 : $q;
}
return $q;
}
// Content type with subtype given (e.g. "image/jpg")
$type = explode('/', $type, 2);
// Exact match
if (isset(request::$accept_types[$type[0]][$type[1]]))
return request::$accept_types[$type[0]][$type[1]];
// Wildcard match (if not checking explicitly)
if ($explicit_check === FALSE AND isset(request::$accept_types[$type[0]]['*']))
return request::$accept_types[$type[0]]['*'];
// Catch-all wildcard match (if not checking explicitly)
if ($explicit_check === FALSE AND isset(request::$accept_types['*']['*']))
return request::$accept_types['*']['*'];
// Content type not accepted
return 0;
}
/**
* Parses client's HTTP Accept request header, and builds array structure representing it.
*
* @return void
*/
protected static function parse_accept_header()
{
// Run this function just once
if (request::$accept_types !== NULL)
return;
// Initialize accept_types array
request::$accept_types = array();
// No HTTP Accept header found
if (empty($_SERVER['HTTP_ACCEPT']))
{
// Accept everything
request::$accept_types['*']['*'] = 1;
return;
}
// Remove linebreaks and parse the HTTP Accept header
foreach (explode(',', str_replace(array("\r", "\n"), '', $_SERVER['HTTP_ACCEPT'])) as $accept_entry)
{
// Explode each entry in content type and possible quality factor
$accept_entry = explode(';', trim($accept_entry), 2);
// Explode each content type (e.g. "text/html")
$type = explode('/', $accept_entry[0], 2);
// Skip invalid content types
if ( ! isset($type[1]))
continue;
// Assume a default quality factor of 1 if no custom q value found
$q = (isset($accept_entry[1]) AND preg_match('~\bq\s*+=\s*+([.0-9]+)~', $accept_entry[1], $match)) ? (float) $match[1] : 1;
// Populate accept_types array
if ( ! isset(request::$accept_types[$type[0]][$type[1]]) OR $q > request::$accept_types[$type[0]][$type[1]])
{
request::$accept_types[$type[0]][$type[1]] = $q;
}
}
}
} // End request
|