This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace Agavi\Request; |
||
3 | |||
4 | // +---------------------------------------------------------------------------+ |
||
5 | // | This file is part of the Agavi package. | |
||
6 | // | Copyright (c) 2005-2011 the Agavi Project. | |
||
7 | // | Based on the Mojavi3 MVC Framework, Copyright (c) 2003-2005 Sean Kerr. | |
||
8 | // | | |
||
9 | // | For the full copyright and license information, please view the LICENSE | |
||
10 | // | file that was distributed with this source code. You can also view the | |
||
11 | // | LICENSE file online at http://www.agavi.org/LICENSE.txt | |
||
12 | // | vi: set noexpandtab: | |
||
13 | // | Local Variables: | |
||
14 | // | indent-tabs-mode: t | |
||
15 | // | End: | |
||
16 | // +---------------------------------------------------------------------------+ |
||
17 | use Agavi\Core\Context; |
||
18 | use Agavi\Exception\AgaviException; |
||
19 | use Agavi\Util\ArrayPathDefinition; |
||
20 | use Agavi\Util\Toolkit; |
||
21 | |||
22 | /** |
||
23 | * AgaviWebRequest provides additional support for web-only client requests |
||
24 | * such as cookie and file manipulation. |
||
25 | * |
||
26 | * @package agavi |
||
27 | * @subpackage request |
||
28 | * |
||
29 | * @author Sean Kerr <[email protected]> |
||
30 | * @author Veikko Mäkinen <[email protected]> |
||
31 | * @author David Zülke <[email protected]> |
||
32 | * @copyright Authors |
||
33 | * @copyright The Agavi Project |
||
34 | * |
||
35 | * @since 0.9.0 |
||
36 | * |
||
37 | * @version $Id$ |
||
38 | */ |
||
39 | class WebRequest extends Request |
||
40 | { |
||
41 | /** |
||
42 | * @var string The protocol information of this request. |
||
43 | */ |
||
44 | protected $protocol = null; |
||
45 | |||
46 | /** |
||
47 | * @var string The current URL scheme. |
||
48 | */ |
||
49 | protected $urlScheme = ''; |
||
50 | |||
51 | /** |
||
52 | * @var string The current URL authority. |
||
53 | */ |
||
54 | protected $urlHost = ''; |
||
55 | |||
56 | /** |
||
57 | * @var string The current URL authority. |
||
58 | */ |
||
59 | protected $urlPort = 0; |
||
60 | |||
61 | /** |
||
62 | * @var string The current URL path. |
||
63 | */ |
||
64 | protected $urlPath = ''; |
||
65 | |||
66 | /** |
||
67 | * @var string The current URL query. |
||
68 | */ |
||
69 | protected $urlQuery = ''; |
||
70 | |||
71 | /** |
||
72 | * @var string The current request URL (path and query). |
||
73 | */ |
||
74 | protected $requestUri = ''; |
||
75 | |||
76 | /** |
||
77 | * @var string The current URL. |
||
78 | */ |
||
79 | protected $url = ''; |
||
80 | |||
81 | /** |
||
82 | * Get the request protocol information, e.g. "HTTP/1.1". |
||
83 | * |
||
84 | * @return string The protocol information. |
||
85 | * |
||
86 | * @author David Zülke <[email protected]> |
||
87 | * @since 0.11.0 |
||
88 | */ |
||
89 | public function getProtocol() |
||
90 | { |
||
91 | return $this->protocol; |
||
92 | } |
||
93 | |||
94 | /** |
||
95 | * Retrieve the scheme part of a request URL, typically the protocol. |
||
96 | * Example: "http". |
||
97 | * |
||
98 | * @return string The request URL scheme. |
||
99 | * |
||
100 | * @author David Zülke <[email protected]> |
||
101 | * @since 0.11.0 |
||
102 | */ |
||
103 | public function getUrlScheme() |
||
104 | { |
||
105 | return $this->urlScheme; |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * Retrieve the hostname part of a request URL. |
||
110 | * |
||
111 | * @return string The request URL hostname. |
||
112 | * |
||
113 | * @author David Zülke <[email protected]> |
||
114 | * @since 0.11.0 |
||
115 | */ |
||
116 | public function getUrlHost() |
||
117 | { |
||
118 | return $this->urlHost; |
||
119 | } |
||
120 | |||
121 | /** |
||
122 | * Retrieve the hostname part of a request URL. |
||
123 | * |
||
124 | * @return string The request URL hostname. |
||
125 | * |
||
126 | * @author David Zülke <[email protected]> |
||
127 | * @since 0.11.0 |
||
128 | */ |
||
129 | public function getUrlPort() |
||
130 | { |
||
131 | return $this->urlPort; |
||
132 | } |
||
133 | |||
134 | /** |
||
135 | * Retrieve the request URL authority, typically host and port. |
||
136 | * Example: "foo.example.com:8080". |
||
137 | * |
||
138 | * @param bool $forcePort Whether or not ports 80 (for HTTP) and 433 (for HTTPS) |
||
139 | * should be included in the return string. |
||
140 | * |
||
141 | * @return string The request URL authority. |
||
142 | * |
||
143 | * @author David Zülke <[email protected]> |
||
144 | * @since 0.11.0 |
||
145 | */ |
||
146 | public function getUrlAuthority($forcePort = false) |
||
147 | { |
||
148 | $port = $this->getUrlPort(); |
||
149 | $scheme = $this->getUrlScheme(); |
||
150 | return $this->getUrlHost() . ($forcePort || Toolkit::isPortNecessary($scheme, $port) ? ':' . $port : ''); |
||
151 | } |
||
152 | |||
153 | /** |
||
154 | * Retrieve the relative part of the request URL, i.e. path and query. |
||
155 | * Example: "/foo/bar/baz?id=4815162342". |
||
156 | * |
||
157 | * @return string The relative URL of the current request. |
||
158 | * |
||
159 | * @author David Zülke <[email protected]> |
||
160 | * @since 0.11.0 |
||
161 | */ |
||
162 | public function getRequestUri() |
||
163 | { |
||
164 | return $this->requestUri; |
||
165 | } |
||
166 | |||
167 | /** |
||
168 | * Retrieve the path part of the URL. |
||
169 | * Example: "/foo/bar/baz". |
||
170 | * |
||
171 | * @return string The path part of the URL. |
||
172 | * |
||
173 | * @author David Zülke <[email protected]> |
||
174 | * @since 0.11.0 |
||
175 | */ |
||
176 | public function getUrlPath() |
||
177 | { |
||
178 | return $this->urlPath; |
||
179 | } |
||
180 | |||
181 | /** |
||
182 | * Retrieve the query part of the URL. |
||
183 | * Example: "id=4815162342". |
||
184 | * |
||
185 | * @return string The query part of the URL, or an empty string. |
||
186 | * |
||
187 | * @author David Zülke <[email protected]> |
||
188 | * @since 0.11.0 |
||
189 | */ |
||
190 | public function getUrlQuery() |
||
191 | { |
||
192 | return $this->urlQuery; |
||
193 | } |
||
194 | |||
195 | /** |
||
196 | * Retrieve the full request URL, including protocol, server name, port (if |
||
197 | * necessary), and request URI. |
||
198 | * Example: "http://foo.example.com:8080/foo/bar/baz?id=4815162342". |
||
199 | * |
||
200 | * @return string The URL of the current request. |
||
201 | * |
||
202 | * @author David Zülke <[email protected]> |
||
203 | * @since 0.11.0 |
||
204 | */ |
||
205 | public function getUrl() |
||
206 | { |
||
207 | return |
||
208 | $this->getUrlScheme() . '://' . |
||
209 | $this->getUrlAuthority() . |
||
210 | $this->getRequestUri(); |
||
211 | } |
||
212 | |||
213 | /** |
||
214 | * Whether or not HTTPS was used for this request. |
||
215 | * |
||
216 | * @return bool True, if it's an HTTPS request, false otherwise. |
||
217 | * |
||
218 | * @author David Zülke <[email protected]> |
||
219 | * @since 0.11.6 |
||
220 | */ |
||
221 | public function isHttps() |
||
222 | { |
||
223 | return $this->getUrlScheme() == 'https'; |
||
224 | } |
||
225 | |||
226 | /** |
||
227 | * Constructor. |
||
228 | * |
||
229 | * @author David Zülke <[email protected]> |
||
230 | * @since 0.11.0 |
||
231 | */ |
||
232 | public function __construct() |
||
233 | { |
||
234 | parent::__construct(); |
||
235 | $this->setParameters(array( |
||
236 | 'request_data_holder_class' => 'Agavi\\Request\\WebRequestDataHolder', |
||
237 | )); |
||
238 | } |
||
239 | |||
240 | /** |
||
241 | * Clear magic quotes. Properly. That means keys are cleared, too. |
||
242 | * |
||
243 | * @param array $input An array of data to be put out of it's misery. |
||
244 | * |
||
245 | * @return array An array delivered from magic quotes. |
||
246 | * |
||
247 | * @author David Zülke <[email protected]> |
||
248 | * @since 0.11.0 |
||
249 | */ |
||
250 | final public static function clearMagicQuotes($input) |
||
251 | { |
||
252 | // this method only works with PHP 5.2.7+ |
||
253 | // there used to be special code for versions < 5.2.2 |
||
254 | // http://bugs.php.net/bug.php?id=41093 |
||
255 | // but we now require 5.2.8 anyway in combination with magic_quotes_gpc, see initialize() |
||
256 | // http://trac.agavi.org/ticket/953 |
||
257 | // http://trac.agavi.org/ticket/944 |
||
258 | // http://bugs.php.net/bug.php?id=41093 |
||
259 | |||
260 | $retval = array(); |
||
261 | |||
262 | foreach ($input as $key => $value) { |
||
263 | $key = stripslashes($key); |
||
264 | |||
265 | if (is_array($value)) { |
||
266 | $retval[$key] = self::clearMagicQuotes($value); |
||
267 | } elseif (is_string($value)) { |
||
268 | $retval[$key] = stripslashes($value); |
||
269 | } else { |
||
270 | $retval[$key] = $value; |
||
271 | } |
||
272 | } |
||
273 | |||
274 | return $retval; |
||
275 | } |
||
276 | |||
277 | /** |
||
278 | * Initialize this Request. |
||
279 | * |
||
280 | * @param Context $context An Context instance. |
||
281 | * @param array $parameters An associative array of initialization parameters. |
||
282 | * |
||
283 | * @throws <b>AgaviInitializationException</b> If an error occurs while |
||
284 | * initializing this Request. |
||
285 | * |
||
286 | * @author Veikko Mäkinen <[email protected]> |
||
287 | * @author David Zülke <[email protected]> |
||
288 | * @since 0.9.0 |
||
289 | */ |
||
290 | public function initialize(Context $context, array $parameters = array()) |
||
0 ignored issues
–
show
initialize 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);
}
}
![]() initialize 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);
}
}
![]() initialize uses the super-global variable $_REQUEST 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);
}
}
![]() initialize 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);
}
}
![]() initialize uses the super-global variable $GLOBALS 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);
}
}
![]() initialize 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);
}
}
![]() |
|||
291 | { |
||
292 | parent::initialize($context, $parameters); |
||
293 | |||
294 | $rla = ini_get('register_long_arrays'); |
||
295 | |||
296 | // very first thing to do: remove magic quotes |
||
297 | if (get_magic_quotes_gpc()) { |
||
298 | trigger_error('Support for php.ini directive "magic_quotes_gpc" is deprecated and will be dropped in Agavi 1.2. The setting is deprecated in PHP 5.3 and will be removed in PHP 5.4. Please refer to the PHP manual for details.', E_USER_DEPRECATED); |
||
299 | $_GET = self::clearMagicQuotes($_GET); |
||
300 | $_POST = self::clearMagicQuotes($_POST); |
||
301 | $_COOKIE = self::clearMagicQuotes($_COOKIE); |
||
302 | $_REQUEST = self::clearMagicQuotes($_REQUEST); |
||
303 | $_FILES = self::clearMagicQuotes($_FILES); |
||
304 | if ($rla) { |
||
305 | $GLOBALS['HTTP_GET_VARS'] = $_GET; |
||
306 | $GLOBALS['HTTP_POST_VARS'] = $_POST; |
||
307 | $GLOBALS['HTTP_COOKIE_VARS'] = $_COOKIE; |
||
308 | $GLOBALS['HTTP_POST_FILES'] = $_FILES; |
||
309 | } |
||
310 | } |
||
311 | |||
312 | $sources = array_merge(array( |
||
313 | 'HTTPS' => 'HTTPS', |
||
314 | 'REQUEST_METHOD' => 'REQUEST_METHOD', |
||
315 | 'SERVER_NAME' => 'SERVER_NAME', |
||
316 | 'SERVER_PORT' => 'SERVER_PORT', |
||
317 | 'SERVER_PROTOCOL' => 'SERVER_PROTOCOL', |
||
318 | 'SERVER_SOFTWARE' => 'SERVER_SOFTWARE', |
||
319 | ), (array)$this->getParameter('sources')); |
||
320 | $this->setParameter('sources', $sources); |
||
321 | |||
322 | // this is correct: if a user-supplied parameter was set, then null is used as the default return value, which means getSourceValue() returns the user-supplied parameter as a last resort if a key of the same name could not be found. allows setting of static values for any of those below |
||
323 | $sourceDefaults = array( |
||
324 | 'HTTPS' => isset($parameters['sources']['HTTPS']) ? null : 'off', |
||
325 | 'REQUEST_METHOD' => isset($parameters['sources']['REQUEST_METHOD']) ? null : 'GET', |
||
326 | 'SERVER_NAME' => null, |
||
327 | 'SERVER_PORT' => isset($parameters['sources']['SERVER_PORT']) ? null : $this->urlPort, |
||
328 | 'SERVER_PROTOCOL' => isset($parameters['sources']['SERVER_PROTOCOL']) ? null : 'HTTP/1.0', |
||
329 | 'SERVER_SOFTWARE' => null, |
||
330 | ); |
||
331 | |||
332 | $methods = array_merge(array( |
||
333 | 'GET' => 'read', |
||
334 | 'POST' => 'write', |
||
335 | 'PUT' => 'create', |
||
336 | 'DELETE' => 'remove', |
||
337 | ), (array)$this->getParameter('method_names')); |
||
338 | $this->setParameter('method_names', $methods); |
||
339 | |||
340 | $REQUEST_METHOD = self::getSourceValue($sources['REQUEST_METHOD'], $sourceDefaults['REQUEST_METHOD']); |
||
341 | |||
342 | // map REQUEST_METHOD value to a method name, or fall back to the default in $sourceDefaults. |
||
343 | // if someone set a static value as default for a source that does not have a mapping, then he's really asking for it, and thus out of luck |
||
344 | $this->setMethod($this->getParameter(sprintf('method_names[%s]', $REQUEST_METHOD), $this->getParameter(sprintf('method_names[%s]', $sourceDefaults['REQUEST_METHOD'])))); |
||
345 | |||
346 | $this->protocol = self::getSourceValue($sources['SERVER_PROTOCOL'], $sourceDefaults['SERVER_PROTOCOL']); |
||
347 | |||
348 | // "on" (e.g. Apache or IIS) or "https" (e.g. Amazon EC2 Elastic Load Balancer) or "1" or integer 1 or true (e.g. statically set from a config file) |
||
349 | $HTTPS = (bool)preg_match('/^(on|https|1)$/i', self::getSourceValue($sources['HTTPS'], $sourceDefaults['HTTPS'])); |
||
350 | |||
351 | $this->urlScheme = 'http' . ($HTTPS ? 's' : ''); |
||
352 | |||
353 | $this->urlPort = (int)self::getSourceValue($sources['SERVER_PORT'], $sourceDefaults['SERVER_PORT']); |
||
0 ignored issues
–
show
The property
$urlPort was declared of type string , but (int) self::getSourceVal...efaults['SERVER_PORT']) is of type integer . Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
![]() |
|||
354 | |||
355 | $SERVER_NAME = self::getSourceValue($sources['SERVER_NAME'], $sourceDefaults['SERVER_NAME']); |
||
356 | $port = $this->getUrlPort(); |
||
357 | if (preg_match_all('/\:/', $SERVER_NAME, $m) > 1) { |
||
358 | $this->urlHost = preg_replace('/\]\:' . preg_quote($port, '/') . '$/', '', $SERVER_NAME); |
||
0 ignored issues
–
show
It seems like
preg_replace('/\\]\\:' ....'$/', '', $SERVER_NAME) can also be of type array<integer,string> . However, the property $urlHost is declared as type string . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
359 | } else { |
||
360 | $this->urlHost = preg_replace('/\:' . preg_quote($port, '/') . '$/', '', $SERVER_NAME); |
||
0 ignored issues
–
show
It seems like
preg_replace('/\\:' . pr...'$/', '', $SERVER_NAME) can also be of type array<integer,string> . However, the property $urlHost is declared as type string . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
361 | } |
||
362 | |||
363 | $_SERVER['SERVER_SOFTWARE'] = self::getSourceValue($sources['SERVER_SOFTWARE'], $sourceDefaults['SERVER_SOFTWARE']); |
||
364 | |||
365 | if (isset($_SERVER['SERVER_SOFTWARE']) && preg_match('#^Apache(/\d+(\.\d+)?)?\.?$#', $_SERVER['SERVER_SOFTWARE'])) { |
||
366 | throw new AgaviException( |
||
367 | "You are running the Apache HTTP Server with a 'ServerTokens' configuration directive value of 'Minor' or lower.\n" . |
||
368 | "This directive controls the amount of version information Apache exposes about itself.\n" . |
||
369 | "Agavi needs detailed Apache version information to apply URL decoding and parsing workarounds specific to certain versions of Apache that exhibit buggy behavior.\n\n" . |
||
370 | "Please take one of the following measures to fix this problem:\n" . |
||
371 | "- raise your 'ServerTokens' level to 'Min' or higher in httpd.conf\n" . |
||
372 | "- set a static value for the request source 'SERVER_SOFTWARE' in factories.xml (for your environment)\n" . |
||
373 | "- set a value for \$_SERVER['SERVER_SOFTWARE'], e.g. in your pub/index.php\n\n" . |
||
374 | "For detailed instructions and examples on fixing this problem, especially for the factories.xml method which is recommended in case you do not have control over your server's httpd.conf, please refer to:\n" . |
||
375 | "http://trac.agavi.org/ticket/1029\n\n" . |
||
376 | "For more information on the 'ServerTokens' directive, please refer to:\n" . |
||
377 | "http://httpd.apache.org/docs/2.2/en/mod/core.html#servertokens\n\n" . |
||
378 | "For your reference, your SERVER_SOFTWARE string is currently '$_SERVER[SERVER_SOFTWARE]'." |
||
379 | ); |
||
380 | } |
||
381 | |||
382 | if (isset($_SERVER['UNENCODED_URL']) && isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false) { |
||
383 | // Microsoft IIS 7 with URL Rewrite Module |
||
384 | $this->requestUri = $_SERVER['UNENCODED_URL']; |
||
385 | } elseif (isset($_SERVER['HTTP_X_REWRITE_URL']) && isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false) { |
||
386 | // Microsoft IIS with ISAPI_Rewrite |
||
387 | $this->requestUri = $_SERVER['HTTP_X_REWRITE_URL']; |
||
388 | } elseif (!isset($_SERVER['REQUEST_URI']) && isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false) { |
||
389 | // Microsoft IIS with PHP in CGI mode |
||
390 | $this->requestUri = $_SERVER['ORIG_PATH_INFO'] . (isset($_SERVER['QUERY_STRING']) && $_SERVER['QUERY_STRING'] != '' ? '?' . $_SERVER['QUERY_STRING'] : ''); |
||
391 | } elseif (isset($_SERVER['REQUEST_URI'])) { |
||
392 | $this->requestUri = $_SERVER['REQUEST_URI']; |
||
393 | } |
||
394 | |||
395 | // Microsoft IIS with PHP in CGI mode |
||
396 | if (!isset($_SERVER['QUERY_STRING'])) { |
||
397 | $_SERVER['QUERY_STRING'] = ''; |
||
398 | } |
||
399 | if (!isset($_SERVER['REQUEST_URI'])) { |
||
400 | $_SERVER['REQUEST_URI'] = $this->getRequestUri(); |
||
401 | } |
||
402 | |||
403 | // okay, this is really bad |
||
404 | // Internet Explorer (many versions, many OSes) seem to be sending improperly urlencoded URLs to the server, in violation of the HTTP RFC |
||
405 | // this can cause a number of problems, most notably html special chars not being escaped and potentially ending up this way in the output |
||
406 | // the result is an XSS attack vector, e.g. on WebRouting::gen(null) |
||
407 | // so we escape those. but not the ampersand, or the query string gets messed up |
||
408 | // we also encode the backtick (Suhosin does this, too), and the space character |
||
409 | // in theory, we shouldn't encode the single quote either, since it's a reserved sub-delimiter as per RFC 3986 - however, that would allow injection again in documents that use single quotes as attribute delimiters, and it's up to implementations to encode sub-delimiters if they deem it necessary |
||
410 | // great, huh? |
||
411 | // more details: |
||
412 | // http://trac.agavi.org/ticket/1019 |
||
413 | // http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-0417 |
||
414 | list($this->requestUri, $_SERVER['REQUEST_URI']) = str_replace( |
||
415 | array(' ', '"', '\'', '<', '>', '`', /*'&'*/), |
||
416 | array('%20', '%22', '%27', '%3C', '%3E', '%60', /*'%26'*/), |
||
417 | array($this->requestUri, $_SERVER['REQUEST_URI']) |
||
418 | ); |
||
419 | if ($rla) { |
||
420 | $GLOBALS['HTTP_SERVER_VARS']['REQUEST_URI'] = $this->getRequestUri(); |
||
421 | } |
||
422 | |||
423 | // 'scheme://authority' is necessary so parse_url doesn't stumble over '://' in the request URI |
||
424 | $parts = array_merge(array('path' => '', 'query' => ''), parse_url('scheme://authority' . $this->getRequestUri())); |
||
425 | $this->urlPath = $parts['path']; |
||
426 | $this->urlQuery = $parts['query']; |
||
427 | unset($parts); |
||
428 | |||
429 | $files = array(); |
||
430 | $ufc = $this->getParameter('uploaded_file_class', 'Agavi\Request\UploadedFile'); |
||
431 | |||
432 | if ($this->getMethod() == $methods['PUT']) { |
||
433 | if (isset($_SERVER['CONTENT_TYPE']) && $this->getParameter('http_put_decode_urlencoded', true) && preg_match('#^application/x-www-form-urlencoded(;[^;]+)*?$#', $_SERVER['CONTENT_TYPE'])) { |
||
434 | // urlencoded data was sent, we can decode that |
||
435 | parse_str(file_get_contents('php://input'), $_POST); |
||
436 | if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) { |
||
437 | $_POST = self::clearMagicQuotes($_POST); |
||
0 ignored issues
–
show
It seems like
$_POST can also be of type null ; however, Agavi\Request\WebRequest::clearMagicQuotes() does only seem to accept array , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
438 | } |
||
439 | } else { |
||
440 | // some other data via PUT. we need to populate $_FILES manually |
||
441 | $httpBody = file_get_contents('php://input'); |
||
442 | |||
443 | $files = array( |
||
444 | $this->getParameter('http_put_file_name', 'put_file') => new $ufc(array( |
||
445 | 'name' => $this->getMethod(), |
||
446 | 'type' => isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : 'application/octet-stream', |
||
447 | 'size' => strlen($httpBody), |
||
448 | 'contents' => $httpBody, |
||
449 | 'error' => UPLOAD_ERR_OK, |
||
450 | 'is_uploaded_file' => false, |
||
451 | )) |
||
452 | ); |
||
453 | } |
||
454 | } elseif ($this->getMethod() == $methods['POST'] && (!isset($_SERVER['CONTENT_TYPE']) || (isset($_SERVER['CONTENT_TYPE']) && !preg_match('#^(application/x-www-form-urlencoded|multipart/form-data)(;[^;]+)*?$#', $_SERVER['CONTENT_TYPE'])))) { |
||
455 | // POST, but no regular urlencoded data or file upload. lets put the request payload into a file |
||
456 | $httpBody = file_get_contents('php://input'); |
||
457 | |||
458 | $files = array( |
||
459 | $this->getParameter('http_post_file_name', 'post_file') => new $ufc(array( |
||
460 | 'name' => $this->getMethod(), |
||
461 | 'type' => isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : 'application/octet-stream', |
||
462 | 'size' => strlen($httpBody), |
||
463 | 'contents' => $httpBody, |
||
464 | 'error' => UPLOAD_ERR_OK, |
||
465 | 'is_uploaded_file' => false, |
||
466 | )) |
||
467 | ); |
||
468 | } elseif ($this->getMethod() == $methods['POST'] && isset($_SERVER['CONTENT_TYPE']) && preg_match('#^multipart/form-data(;[^;]+)*?$#', $_SERVER['CONTENT_TYPE'])) { |
||
469 | $files = static::fixFilesArray($_FILES, $ufc); |
||
470 | } |
||
471 | |||
472 | $headers = array(); |
||
473 | foreach ($_SERVER as $key => $value) { |
||
474 | if (substr($key, 0, 5) == 'HTTP_') { |
||
475 | $headers[substr($key, 5)] = $value; |
||
476 | } elseif ($key == 'CONTENT_TYPE' || $key == 'CONTENT_LENGTH') { |
||
477 | // yeah, whatever, PHP... |
||
478 | $headers[$key] = $value; |
||
479 | } |
||
480 | } |
||
481 | |||
482 | $rdhc = $this->getParameter('request_data_holder_class'); |
||
483 | $this->setRequestData(new $rdhc(array( |
||
484 | constant("$rdhc::SOURCE_PARAMETERS") => array_merge($_GET, $_POST), |
||
485 | constant("$rdhc::SOURCE_COOKIES") => $_COOKIE, |
||
486 | constant("$rdhc::SOURCE_FILES") => $files, |
||
487 | constant("$rdhc::SOURCE_HEADERS") => $headers, |
||
488 | ))); |
||
489 | } |
||
490 | |||
491 | /** |
||
492 | * Corrects the order of $_FILES for arrays of files. |
||
493 | * The cleaned up array of AgaviUploadedFile objects is returned. |
||
494 | * |
||
495 | * @param array $input The array to work on. |
||
496 | * @param string $uploadedFileClass Name of the wrapper uploaded file class to instantiate. |
||
497 | * @param array $input Array of indices used during recursion, initially empty. |
||
498 | * @param array $output Output buffer used during recursion, initially empty. |
||
499 | * |
||
500 | * @author David Zülke <[email protected]> |
||
501 | * @since 1.1.0 |
||
502 | */ |
||
503 | protected static function fixFilesArray($input, $uploadedFileClass = 'UploadedFile', $index = array(), &$output = array()) |
||
504 | { |
||
505 | $fromIndex = $index; |
||
506 | if (count($fromIndex) > 0) { |
||
507 | $first = array_shift($fromIndex); |
||
508 | array_unshift($fromIndex, $first, 'error'); |
||
509 | } |
||
510 | $sub = ArrayPathDefinition::getValue($fromIndex, $input); |
||
511 | $theIndices = array(); |
||
512 | foreach (array('name', 'type', 'size', 'tmp_name', 'error', 'is_uploaded_file') as $name) { |
||
513 | $theIndex = $fromIndex; |
||
514 | $first = array_shift($theIndex); |
||
515 | array_shift($theIndex); |
||
516 | array_unshift($theIndex, $first, $name); |
||
517 | $theIndices[$name] = $theIndex; |
||
518 | } |
||
519 | if (is_array($sub)) { |
||
520 | foreach ($sub as $key => $value) { |
||
521 | $toIndex = array_merge($index, array($key)); |
||
522 | if (is_array($value)) { |
||
523 | static::fixFilesArray($input, $uploadedFileClass, $toIndex, $output); |
||
524 | View Code Duplication | } else { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
525 | $data = array(); |
||
526 | foreach ($theIndices as $name => $theIndex) { |
||
527 | $data[$name] = ArrayPathDefinition::getValue(array_merge($theIndex, array($key)), $input, $name == 'is_uploaded_file' ? true : null); |
||
528 | } |
||
529 | $data = new $uploadedFileClass($data); |
||
530 | ArrayPathDefinition::setValue($toIndex, $output, $data); |
||
531 | } |
||
532 | } |
||
533 | View Code Duplication | } else { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
534 | $data = array(); |
||
535 | foreach ($theIndices as $name => $theIndex) { |
||
536 | $data[$name] = ArrayPathDefinition::getValue($theIndex, $input, $name == 'is_uploaded_file' ? true : null); |
||
537 | } |
||
538 | $data = new $uploadedFileClass($data); |
||
539 | ArrayPathDefinition::setValue($index, $output, $data); |
||
540 | } |
||
541 | |||
542 | return $output; |
||
543 | } |
||
544 | |||
545 | /** |
||
546 | * Do any necessary startup work after initialization. |
||
547 | * |
||
548 | * This method is not called directly after initialize(). |
||
549 | * |
||
550 | * @author David Zülke <[email protected]> |
||
551 | * @since 0.11.0 |
||
552 | */ |
||
553 | public function startup() |
||
0 ignored issues
–
show
startup 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);
}
}
![]() startup 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);
}
}
![]() startup 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);
}
}
![]() startup uses the super-global variable $_REQUEST 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);
}
}
![]() startup 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);
}
}
![]() startup uses the super-global variable $GLOBALS 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);
}
}
![]() startup 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);
}
}
![]() startup uses the super-global variable $_ENV 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);
}
}
![]() |
|||
554 | { |
||
555 | parent::startup(); |
||
556 | |||
557 | if ($this->getParameter('unset_input', true)) { |
||
558 | $rla = ini_get('register_long_arrays'); |
||
559 | |||
560 | $_GET = $_POST = $_COOKIE = $_REQUEST = $_FILES = array(); |
||
561 | if ($rla) { |
||
562 | // clean long arrays, too! |
||
563 | $GLOBALS['HTTP_GET_VARS'] = $GLOBALS['HTTP_POST_VARS'] = $GLOBALS['HTTP_COOKIE_VARS'] = $GLOBALS['HTTP_POST_FILES'] = array(); |
||
564 | } |
||
565 | |||
566 | foreach ($_SERVER as $key => $value) { |
||
567 | if (substr($key, 0, 5) == 'HTTP_' || $key == 'CONTENT_TYPE' || $key == 'CONTENT_LENGTH') { |
||
568 | unset($_SERVER[$key]); |
||
569 | unset($_ENV[$key]); |
||
570 | if ($rla) { |
||
571 | unset($GLOBALS['HTTP_SERVER_VARS'][$key]); |
||
572 | unset($GLOBALS['HTTP_ENV_VARS'][$key]); |
||
573 | } |
||
574 | } |
||
575 | } |
||
576 | } |
||
577 | } |
||
578 | } |
||
579 |
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: