1 | <?php |
||||||
2 | |||||||
3 | namespace SilverStripe\Control; |
||||||
4 | |||||||
5 | use SilverStripe\CMS\Model\SiteTree; |
||||||
0 ignored issues
–
show
|
|||||||
6 | use SilverStripe\Control\Middleware\CanonicalURLMiddleware; |
||||||
7 | use SilverStripe\Control\Middleware\HTTPMiddlewareAware; |
||||||
8 | use SilverStripe\Core\Config\Configurable; |
||||||
9 | use SilverStripe\Core\Environment; |
||||||
10 | use SilverStripe\Core\Extensible; |
||||||
11 | use SilverStripe\Core\Injector\Injectable; |
||||||
12 | use SilverStripe\Core\Injector\Injector; |
||||||
13 | use SilverStripe\Core\Kernel; |
||||||
14 | use SilverStripe\Core\Path; |
||||||
15 | use SilverStripe\Dev\Deprecation; |
||||||
16 | use SilverStripe\Versioned\Versioned; |
||||||
17 | use SilverStripe\View\Requirements; |
||||||
18 | use SilverStripe\View\Requirements_Backend; |
||||||
19 | use SilverStripe\View\TemplateGlobalProvider; |
||||||
20 | |||||||
21 | /** |
||||||
22 | * Director is responsible for processing URLs, and providing environment information. |
||||||
23 | * |
||||||
24 | * The most important part of director is {@link Director::handleRequest()}, which is passed an HTTPRequest and will |
||||||
25 | * execute the appropriate controller. |
||||||
26 | * |
||||||
27 | * @see Director::handleRequest() |
||||||
28 | * @see Director::$rules |
||||||
29 | * @skipUpgrade |
||||||
30 | */ |
||||||
31 | class Director implements TemplateGlobalProvider |
||||||
32 | { |
||||||
33 | use Configurable; |
||||||
34 | use Extensible; |
||||||
35 | use Injectable; |
||||||
36 | use HTTPMiddlewareAware; |
||||||
37 | |||||||
38 | /** |
||||||
39 | * Specifies this url is relative to the base. |
||||||
40 | * |
||||||
41 | * @var string |
||||||
42 | */ |
||||||
43 | const BASE = 'BASE'; |
||||||
44 | |||||||
45 | /** |
||||||
46 | * Specifies this url is relative to the site root. |
||||||
47 | * |
||||||
48 | * @var string |
||||||
49 | */ |
||||||
50 | const ROOT = 'ROOT'; |
||||||
51 | |||||||
52 | /** |
||||||
53 | * specifies this url is relative to the current request. |
||||||
54 | * |
||||||
55 | * @var string |
||||||
56 | */ |
||||||
57 | const REQUEST = 'REQUEST'; |
||||||
58 | |||||||
59 | /** |
||||||
60 | * @config |
||||||
61 | * @var array |
||||||
62 | */ |
||||||
63 | private static $rules = array(); |
||||||
0 ignored issues
–
show
|
|||||||
64 | |||||||
65 | /** |
||||||
66 | * Set current page |
||||||
67 | * |
||||||
68 | * @internal |
||||||
69 | * @var SiteTree |
||||||
70 | */ |
||||||
71 | private static $current_page; |
||||||
72 | |||||||
73 | /** |
||||||
74 | * @config |
||||||
75 | * @var string |
||||||
76 | */ |
||||||
77 | private static $alternate_base_folder; |
||||||
0 ignored issues
–
show
|
|||||||
78 | |||||||
79 | /** |
||||||
80 | * Override PUBLIC_DIR. Set to a non-null value to override. |
||||||
81 | * Setting to an empty string will disable public dir. |
||||||
82 | * |
||||||
83 | * @config |
||||||
84 | * @var bool|null |
||||||
85 | */ |
||||||
86 | private static $alternate_public_dir = null; |
||||||
0 ignored issues
–
show
|
|||||||
87 | |||||||
88 | /** |
||||||
89 | * Base url to populate if cannot be determined otherwise. |
||||||
90 | * Supports back-ticked vars; E.g. '`SS_BASE_URL`' |
||||||
91 | * |
||||||
92 | * @config |
||||||
93 | * @var string |
||||||
94 | */ |
||||||
95 | private static $default_base_url = '`SS_BASE_URL`'; |
||||||
0 ignored issues
–
show
|
|||||||
96 | |||||||
97 | public function __construct() |
||||||
98 | { |
||||||
99 | } |
||||||
100 | |||||||
101 | /** |
||||||
102 | * Test a URL request, returning a response object. This method is a wrapper around |
||||||
103 | * Director::handleRequest() to assist with functional testing. It will execute the URL given, and |
||||||
104 | * return the result as an HTTPResponse object. |
||||||
105 | * |
||||||
106 | * @param string $url The URL to visit. |
||||||
107 | * @param array $postVars The $_POST & $_FILES variables. |
||||||
108 | * @param array|Session $session The {@link Session} object representing the current session. |
||||||
109 | * By passing the same object to multiple calls of Director::test(), you can simulate a persisted |
||||||
110 | * session. |
||||||
111 | * @param string $httpMethod The HTTP method, such as GET or POST. It will default to POST if |
||||||
112 | * postVars is set, GET otherwise. Overwritten by $postVars['_method'] if present. |
||||||
113 | * @param string $body The HTTP body. |
||||||
114 | * @param array $headers HTTP headers with key-value pairs. |
||||||
115 | * @param array|Cookie_Backend $cookies to populate $_COOKIE. |
||||||
116 | * @param HTTPRequest $request The {@see SS_HTTP_Request} object generated as a part of this request. |
||||||
117 | * |
||||||
118 | * @return HTTPResponse |
||||||
119 | * |
||||||
120 | * @throws HTTPResponse_Exception |
||||||
121 | */ |
||||||
122 | public static function test( |
||||||
123 | $url, |
||||||
124 | $postVars = [], |
||||||
125 | $session = array(), |
||||||
126 | $httpMethod = null, |
||||||
127 | $body = null, |
||||||
128 | $headers = array(), |
||||||
129 | $cookies = array(), |
||||||
130 | &$request = null |
||||||
131 | ) { |
||||||
132 | return static::mockRequest( |
||||||
133 | function (HTTPRequest $request) { |
||||||
134 | return Director::singleton()->handleRequest($request); |
||||||
135 | }, |
||||||
136 | $url, |
||||||
137 | $postVars, |
||||||
138 | $session, |
||||||
139 | $httpMethod, |
||||||
140 | $body, |
||||||
141 | $headers, |
||||||
142 | $cookies, |
||||||
143 | $request |
||||||
144 | ); |
||||||
145 | } |
||||||
146 | |||||||
147 | /** |
||||||
148 | * Mock a request, passing this to the given callback, before resetting. |
||||||
149 | * |
||||||
150 | * @param callable $callback Action to pass the HTTPRequst object |
||||||
151 | * @param string $url The URL to build |
||||||
152 | * @param array $postVars The $_POST & $_FILES variables. |
||||||
153 | * @param array|Session $session The {@link Session} object representing the current session. |
||||||
154 | * By passing the same object to multiple calls of Director::test(), you can simulate a persisted |
||||||
155 | * session. |
||||||
156 | * @param string $httpMethod The HTTP method, such as GET or POST. It will default to POST if |
||||||
157 | * postVars is set, GET otherwise. Overwritten by $postVars['_method'] if present. |
||||||
158 | * @param string $body The HTTP body. |
||||||
159 | * @param array $headers HTTP headers with key-value pairs. |
||||||
160 | * @param array|Cookie_Backend $cookies to populate $_COOKIE. |
||||||
161 | * @param HTTPRequest $request The {@see SS_HTTP_Request} object generated as a part of this request. |
||||||
162 | * @return mixed Result of callback |
||||||
163 | */ |
||||||
164 | public static function mockRequest( |
||||||
165 | $callback, |
||||||
166 | $url, |
||||||
167 | $postVars = [], |
||||||
168 | $session = [], |
||||||
169 | $httpMethod = null, |
||||||
170 | $body = null, |
||||||
171 | $headers = [], |
||||||
172 | $cookies = [], |
||||||
173 | &$request = null |
||||||
174 | ) { |
||||||
175 | // Build list of cleanup promises |
||||||
176 | $finally = []; |
||||||
177 | |||||||
178 | /** @var Kernel $kernel */ |
||||||
179 | $kernel = Injector::inst()->get(Kernel::class); |
||||||
180 | $kernel->nest(); |
||||||
181 | $finally[] = function () use ($kernel) { |
||||||
182 | $kernel->activate(); |
||||||
183 | }; |
||||||
184 | |||||||
185 | // backup existing vars, and create new vars |
||||||
186 | $existingVars = Environment::getVariables(); |
||||||
187 | $finally[] = function () use ($existingVars) { |
||||||
188 | Environment::setVariables($existingVars); |
||||||
189 | }; |
||||||
190 | $newVars = $existingVars; |
||||||
191 | |||||||
192 | // These are needed so that calling Director::test() does not muck with whoever is calling it. |
||||||
193 | // Really, it's some inappropriate coupling and should be resolved by making less use of statics. |
||||||
194 | if (class_exists(Versioned::class)) { |
||||||
195 | $oldReadingMode = Versioned::get_reading_mode(); |
||||||
196 | $finally[] = function () use ($oldReadingMode) { |
||||||
197 | Versioned::set_reading_mode($oldReadingMode); |
||||||
198 | }; |
||||||
199 | } |
||||||
200 | |||||||
201 | // Default httpMethod |
||||||
202 | $newVars['_SERVER']['REQUEST_METHOD'] = $httpMethod ?: ($postVars ? "POST" : "GET"); |
||||||
203 | $newVars['_POST'] = (array)$postVars; |
||||||
204 | |||||||
205 | // Setup session |
||||||
206 | if ($session instanceof Session) { |
||||||
207 | // Note: If passing $session as object, ensure that changes are written back |
||||||
208 | // This is important for classes such as FunctionalTest which emulate cross-request persistence |
||||||
209 | $newVars['_SESSION'] = $sessionArray = $session->getAll() ?: []; |
||||||
210 | $finally[] = function () use ($session, $sessionArray) { |
||||||
211 | if (isset($_SESSION)) { |
||||||
212 | // Set new / updated keys |
||||||
213 | foreach ($_SESSION as $key => $value) { |
||||||
214 | $session->set($key, $value); |
||||||
215 | } |
||||||
216 | // Unset removed keys |
||||||
217 | foreach (array_diff_key($sessionArray, $_SESSION) as $key => $value) { |
||||||
218 | $session->clear($key); |
||||||
219 | } |
||||||
220 | } |
||||||
221 | }; |
||||||
222 | } else { |
||||||
223 | $newVars['_SESSION'] = $session ?: []; |
||||||
224 | } |
||||||
225 | |||||||
226 | // Setup cookies |
||||||
227 | $cookieJar = $cookies instanceof Cookie_Backend |
||||||
228 | ? $cookies |
||||||
229 | : Injector::inst()->createWithArgs(Cookie_Backend::class, array($cookies ?: [])); |
||||||
230 | $newVars['_COOKIE'] = $cookieJar->getAll(false); |
||||||
231 | Cookie::config()->update('report_errors', false); |
||||||
232 | Injector::inst()->registerService($cookieJar, Cookie_Backend::class); |
||||||
233 | |||||||
234 | // Backup requirements |
||||||
235 | $existingRequirementsBackend = Requirements::backend(); |
||||||
236 | Requirements::set_backend(Requirements_Backend::create()); |
||||||
237 | $finally[] = function () use ($existingRequirementsBackend) { |
||||||
238 | Requirements::set_backend($existingRequirementsBackend); |
||||||
239 | }; |
||||||
240 | |||||||
241 | // Strip any hash |
||||||
242 | $url = strtok($url, '#'); |
||||||
243 | |||||||
244 | // Handle absolute URLs |
||||||
245 | // If a port is mentioned in the absolute URL, be sure to add that into the HTTP host |
||||||
246 | $urlHostPort = static::parseHost($url); |
||||||
247 | if ($urlHostPort) { |
||||||
248 | $newVars['_SERVER']['HTTP_HOST'] = $urlHostPort; |
||||||
249 | } |
||||||
250 | |||||||
251 | // Ensure URL is properly made relative. |
||||||
252 | // Example: url passed is "/ss31/my-page" (prefixed with BASE_URL), this should be changed to "my-page" |
||||||
253 | $url = self::makeRelative($url); |
||||||
254 | if (strpos($url, '?') !== false) { |
||||||
255 | list($url, $getVarsEncoded) = explode('?', $url, 2); |
||||||
256 | parse_str($getVarsEncoded, $newVars['_GET']); |
||||||
257 | } else { |
||||||
258 | $newVars['_GET'] = []; |
||||||
259 | } |
||||||
260 | $newVars['_SERVER']['REQUEST_URI'] = Director::baseURL() . ltrim($url, '/'); |
||||||
0 ignored issues
–
show
As per coding style,
self should be used for accessing local static members.
This check looks for accesses to local static members using the fully qualified name instead
of <?php
class Certificate {
const TRIPLEDES_CBC = 'ASDFGHJKL';
private $key;
public function __construct()
{
$this->key = Certificate::TRIPLEDES_CBC;
}
}
While this is perfectly valid, the fully qualified name of
Loading history...
|
|||||||
261 | $newVars['_REQUEST'] = array_merge($newVars['_GET'], $newVars['_POST']); |
||||||
262 | |||||||
263 | // Normalise vars |
||||||
264 | $newVars = HTTPRequestBuilder::cleanEnvironment($newVars); |
||||||
265 | |||||||
266 | // Create new request |
||||||
267 | $request = HTTPRequestBuilder::createFromVariables($newVars, $body, ltrim($url, '/')); |
||||||
268 | if ($headers) { |
||||||
0 ignored issues
–
show
The expression
$headers of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using
Loading history...
|
|||||||
269 | foreach ($headers as $k => $v) { |
||||||
270 | $request->addHeader($k, $v); |
||||||
271 | } |
||||||
272 | } |
||||||
273 | |||||||
274 | // Apply new vars to environment |
||||||
275 | Environment::setVariables($newVars); |
||||||
276 | |||||||
277 | try { |
||||||
278 | // Normal request handling |
||||||
279 | return call_user_func($callback, $request); |
||||||
280 | } finally { |
||||||
281 | // Restore state in reverse order to assignment |
||||||
282 | foreach (array_reverse($finally) as $callback) { |
||||||
0 ignored issues
–
show
|
|||||||
283 | call_user_func($callback); |
||||||
284 | } |
||||||
285 | } |
||||||
286 | } |
||||||
287 | |||||||
288 | /** |
||||||
289 | * Process the given URL, creating the appropriate controller and executing it. |
||||||
290 | * |
||||||
291 | * Request processing is handled as follows: |
||||||
292 | * - Director::handleRequest($request) checks each of the Director rules and identifies a controller |
||||||
293 | * to handle this request. |
||||||
294 | * - Controller::handleRequest($request) is then called. This will find a rule to handle the URL, |
||||||
295 | * and call the rule handling method. |
||||||
296 | * - RequestHandler::handleRequest($request) is recursively called whenever a rule handling method |
||||||
297 | * returns a RequestHandler object. |
||||||
298 | * |
||||||
299 | * In addition to request processing, Director will manage the session, and perform the output of |
||||||
300 | * the actual response to the browser. |
||||||
301 | * |
||||||
302 | * @param HTTPRequest $request |
||||||
303 | * @return HTTPResponse |
||||||
304 | * @throws HTTPResponse_Exception |
||||||
305 | */ |
||||||
306 | public function handleRequest(HTTPRequest $request) |
||||||
307 | { |
||||||
308 | Injector::inst()->registerService($request, HTTPRequest::class); |
||||||
309 | |||||||
310 | $rules = Director::config()->uninherited('rules'); |
||||||
0 ignored issues
–
show
As per coding style,
self should be used for accessing local static members.
This check looks for accesses to local static members using the fully qualified name instead
of <?php
class Certificate {
const TRIPLEDES_CBC = 'ASDFGHJKL';
private $key;
public function __construct()
{
$this->key = Certificate::TRIPLEDES_CBC;
}
}
While this is perfectly valid, the fully qualified name of
Loading history...
|
|||||||
311 | |||||||
312 | $this->extend('updateRules', $rules); |
||||||
313 | |||||||
314 | // Default handler - mo URL rules matched, so return a 404 error. |
||||||
315 | $handler = function () { |
||||||
316 | return new HTTPResponse('No URL rule was matched', 404); |
||||||
317 | }; |
||||||
318 | |||||||
319 | foreach ($rules as $pattern => $controllerOptions) { |
||||||
320 | // Match pattern |
||||||
321 | $arguments = $request->match($pattern, true); |
||||||
322 | if ($arguments == false) { |
||||||
323 | continue; |
||||||
324 | } |
||||||
325 | |||||||
326 | // Normalise route rule |
||||||
327 | if (is_string($controllerOptions)) { |
||||||
328 | if (substr($controllerOptions, 0, 2) == '->') { |
||||||
329 | $controllerOptions = array('Redirect' => substr($controllerOptions, 2)); |
||||||
330 | } else { |
||||||
331 | $controllerOptions = array('Controller' => $controllerOptions); |
||||||
332 | } |
||||||
333 | } |
||||||
334 | $request->setRouteParams($controllerOptions); |
||||||
335 | |||||||
336 | // controllerOptions provide some default arguments |
||||||
337 | $arguments = array_merge($controllerOptions, $arguments); |
||||||
338 | |||||||
339 | // Pop additional tokens from the tokenizer if necessary |
||||||
340 | if (isset($controllerOptions['_PopTokeniser'])) { |
||||||
341 | $request->shift($controllerOptions['_PopTokeniser']); |
||||||
342 | } |
||||||
343 | |||||||
344 | // Handler for redirection |
||||||
345 | if (isset($arguments['Redirect'])) { |
||||||
346 | $handler = function () use ($arguments) { |
||||||
347 | // Redirection |
||||||
348 | $response = new HTTPResponse(); |
||||||
349 | $response->redirect(static::absoluteURL($arguments['Redirect'])); |
||||||
350 | return $response; |
||||||
351 | }; |
||||||
352 | break; |
||||||
353 | } |
||||||
354 | |||||||
355 | // Handler for constructing and calling a controller |
||||||
356 | $handler = function (HTTPRequest $request) use ($arguments) { |
||||||
357 | try { |
||||||
358 | /** @var RequestHandler $controllerObj */ |
||||||
359 | $controllerObj = Injector::inst()->create($arguments['Controller']); |
||||||
360 | return $controllerObj->handleRequest($request); |
||||||
361 | } catch (HTTPResponse_Exception $responseException) { |
||||||
362 | return $responseException->getResponse(); |
||||||
363 | } |
||||||
364 | }; |
||||||
365 | break; |
||||||
366 | } |
||||||
367 | |||||||
368 | // Call the handler with the configured middlewares |
||||||
369 | $response = $this->callMiddleware($request, $handler); |
||||||
370 | |||||||
371 | // Note that if a different request was previously registered, this will now be lost |
||||||
372 | // In these cases it's better to use Kernel::nest() prior to kicking off a nested request |
||||||
373 | Injector::inst()->unregisterNamedObject(HTTPRequest::class); |
||||||
374 | |||||||
375 | return $response; |
||||||
376 | } |
||||||
377 | |||||||
378 | /** |
||||||
379 | * Return the {@link SiteTree} object that is currently being viewed. If there is no SiteTree |
||||||
380 | * object to return, then this will return the current controller. |
||||||
381 | * |
||||||
382 | * @return SiteTree|Controller |
||||||
383 | */ |
||||||
384 | public static function get_current_page() |
||||||
385 | { |
||||||
386 | return self::$current_page ? self::$current_page : Controller::curr(); |
||||||
387 | } |
||||||
388 | |||||||
389 | /** |
||||||
390 | * Set the currently active {@link SiteTree} object that is being used to respond to the request. |
||||||
391 | * |
||||||
392 | * @param SiteTree $page |
||||||
393 | */ |
||||||
394 | public static function set_current_page($page) |
||||||
395 | { |
||||||
396 | self::$current_page = $page; |
||||||
397 | } |
||||||
398 | |||||||
399 | /** |
||||||
400 | * Turns the given URL into an absolute URL. By default non-site root relative urls will be |
||||||
401 | * evaluated relative to the current base_url. |
||||||
402 | * |
||||||
403 | * @param string $url URL To transform to absolute. |
||||||
404 | * @param string $relativeParent Method to use for evaluating relative urls. |
||||||
405 | * Either one of BASE (baseurl), ROOT (site root), or REQUEST (requested page). |
||||||
406 | * Defaults to BASE, which is the same behaviour as template url resolution. |
||||||
407 | * Ignored if the url is absolute or site root. |
||||||
408 | * |
||||||
409 | * @return string |
||||||
410 | */ |
||||||
411 | public static function absoluteURL($url, $relativeParent = self::BASE) |
||||||
412 | { |
||||||
413 | if (is_bool($relativeParent)) { |
||||||
0 ignored issues
–
show
|
|||||||
414 | // Deprecate old boolean second parameter |
||||||
415 | Deprecation::notice('5.0', 'Director::absoluteURL takes an explicit parent for relative url'); |
||||||
416 | $relativeParent = $relativeParent ? self::BASE : self::REQUEST; |
||||||
417 | } |
||||||
418 | |||||||
419 | // Check if there is already a protocol given |
||||||
420 | if (preg_match('/^http(s?):\/\//', $url)) { |
||||||
421 | return $url; |
||||||
422 | } |
||||||
423 | |||||||
424 | // Absolute urls without protocol are added |
||||||
425 | // E.g. //google.com -> http://google.com |
||||||
426 | if (strpos($url, '//') === 0) { |
||||||
427 | return self::protocol() . substr($url, 2); |
||||||
428 | } |
||||||
429 | |||||||
430 | // Determine method for mapping the parent to this relative url |
||||||
431 | if ($relativeParent === self::ROOT || self::is_root_relative_url($url)) { |
||||||
432 | // Root relative urls always should be evaluated relative to the root |
||||||
433 | $parent = self::protocolAndHost(); |
||||||
434 | } elseif ($relativeParent === self::REQUEST) { |
||||||
435 | // Request relative urls rely on the REQUEST_URI param (old default behaviour) |
||||||
436 | if (!isset($_SERVER['REQUEST_URI'])) { |
||||||
437 | return false; |
||||||
438 | } |
||||||
439 | $parent = dirname($_SERVER['REQUEST_URI'] . 'x'); |
||||||
440 | } else { |
||||||
441 | // Default to respecting site base_url |
||||||
442 | $parent = self::absoluteBaseURL(); |
||||||
443 | } |
||||||
444 | |||||||
445 | // Map empty urls to relative slash and join to base |
||||||
446 | if (empty($url) || $url === '.' || $url === './') { |
||||||
447 | $url = '/'; |
||||||
448 | } |
||||||
449 | return Controller::join_links($parent, $url); |
||||||
450 | } |
||||||
451 | |||||||
452 | /** |
||||||
453 | * Return only host (and optional port) part of a url |
||||||
454 | * |
||||||
455 | * @param string $url |
||||||
456 | * @return string|null Hostname, and optional port, or null if not a valid host |
||||||
457 | */ |
||||||
458 | protected static function parseHost($url) |
||||||
459 | { |
||||||
460 | // Get base hostname |
||||||
461 | $host = parse_url($url, PHP_URL_HOST); |
||||||
462 | if (!$host) { |
||||||
463 | return null; |
||||||
464 | } |
||||||
465 | |||||||
466 | // Include port |
||||||
467 | $port = parse_url($url, PHP_URL_PORT); |
||||||
468 | if ($port) { |
||||||
469 | $host .= ':' . $port; |
||||||
470 | } |
||||||
471 | |||||||
472 | return $host; |
||||||
473 | } |
||||||
474 | |||||||
475 | /** |
||||||
476 | * Validate user and password in URL, disallowing slashes |
||||||
477 | * |
||||||
478 | * @param string $url |
||||||
479 | * @return bool |
||||||
480 | */ |
||||||
481 | protected static function validateUserAndPass($url) |
||||||
482 | { |
||||||
483 | $parsedURL = parse_url($url); |
||||||
484 | |||||||
485 | // Validate user (disallow slashes) |
||||||
486 | if (!empty($parsedURL['user']) && strstr($parsedURL['user'], '\\')) { |
||||||
487 | return false; |
||||||
488 | } |
||||||
489 | if (!empty($parsedURL['pass']) && strstr($parsedURL['pass'], '\\')) { |
||||||
490 | return false; |
||||||
491 | } |
||||||
492 | |||||||
493 | return true; |
||||||
494 | } |
||||||
495 | |||||||
496 | /** |
||||||
497 | * A helper to determine the current hostname used to access the site. |
||||||
498 | * The following are used to determine the host (in order) |
||||||
499 | * - Director.alternate_base_url (if it contains a domain name) |
||||||
500 | * - Trusted proxy headers |
||||||
501 | * - HTTP Host header |
||||||
502 | * - SS_BASE_URL env var |
||||||
503 | * - SERVER_NAME |
||||||
504 | * - gethostname() |
||||||
505 | * |
||||||
506 | * @param HTTPRequest $request |
||||||
507 | * @return string Host name, including port (if present) |
||||||
508 | */ |
||||||
509 | public static function host(HTTPRequest $request = null) |
||||||
510 | { |
||||||
511 | // Check if overridden by alternate_base_url |
||||||
512 | if ($baseURL = self::config()->get('alternate_base_url')) { |
||||||
513 | $baseURL = Injector::inst()->convertServiceProperty($baseURL); |
||||||
514 | $host = static::parseHost($baseURL); |
||||||
515 | if ($host) { |
||||||
516 | return $host; |
||||||
517 | } |
||||||
518 | } |
||||||
519 | |||||||
520 | $request = static::currentRequest($request); |
||||||
521 | if ($request && ($host = $request->getHeader('Host'))) { |
||||||
522 | return $host; |
||||||
523 | } |
||||||
524 | |||||||
525 | // Check given header |
||||||
526 | if (isset($_SERVER['HTTP_HOST'])) { |
||||||
527 | return $_SERVER['HTTP_HOST']; |
||||||
528 | } |
||||||
529 | |||||||
530 | // Check base url |
||||||
531 | if ($baseURL = self::config()->uninherited('default_base_url')) { |
||||||
532 | $baseURL = Injector::inst()->convertServiceProperty($baseURL); |
||||||
533 | $host = static::parseHost($baseURL); |
||||||
534 | if ($host) { |
||||||
535 | return $host; |
||||||
536 | } |
||||||
537 | } |
||||||
538 | |||||||
539 | // Fail over to server_name (least reliable) |
||||||
540 | return isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : gethostname(); |
||||||
541 | } |
||||||
542 | |||||||
543 | /** |
||||||
544 | * Return port used for the base URL. |
||||||
545 | * Note, this will be null if not specified, in which case you should assume the default |
||||||
546 | * port for the current protocol. |
||||||
547 | * |
||||||
548 | * @param HTTPRequest $request |
||||||
549 | * @return int|null |
||||||
550 | */ |
||||||
551 | public static function port(HTTPRequest $request = null) |
||||||
552 | { |
||||||
553 | $host = static::host($request); |
||||||
554 | return (int)parse_url($host, PHP_URL_PORT) ?: null; |
||||||
555 | } |
||||||
556 | |||||||
557 | /** |
||||||
558 | * Return host name without port |
||||||
559 | * |
||||||
560 | * @param HTTPRequest|null $request |
||||||
561 | * @return string|null |
||||||
562 | */ |
||||||
563 | public static function hostName(HTTPRequest $request = null) |
||||||
564 | { |
||||||
565 | $host = static::host($request); |
||||||
566 | return parse_url($host, PHP_URL_HOST) ?: null; |
||||||
567 | } |
||||||
568 | |||||||
569 | /** |
||||||
570 | * Returns the domain part of the URL 'http://www.mysite.com'. Returns FALSE is this environment |
||||||
571 | * variable isn't set. |
||||||
572 | * |
||||||
573 | * @param HTTPRequest $request |
||||||
574 | * @return bool|string |
||||||
575 | */ |
||||||
576 | public static function protocolAndHost(HTTPRequest $request = null) |
||||||
577 | { |
||||||
578 | return static::protocol($request) . static::host($request); |
||||||
579 | } |
||||||
580 | |||||||
581 | /** |
||||||
582 | * Return the current protocol that the site is running under. |
||||||
583 | * |
||||||
584 | * @param HTTPRequest $request |
||||||
585 | * @return string |
||||||
586 | */ |
||||||
587 | public static function protocol(HTTPRequest $request = null) |
||||||
588 | { |
||||||
589 | return (self::is_https($request)) ? 'https://' : 'http://'; |
||||||
590 | } |
||||||
591 | |||||||
592 | /** |
||||||
593 | * Return whether the site is running as under HTTPS. |
||||||
594 | * |
||||||
595 | * @param HTTPRequest $request |
||||||
596 | * @return bool |
||||||
597 | */ |
||||||
598 | public static function is_https(HTTPRequest $request = null) |
||||||
599 | { |
||||||
600 | // Check override from alternate_base_url |
||||||
601 | if ($baseURL = self::config()->uninherited('alternate_base_url')) { |
||||||
602 | $baseURL = Injector::inst()->convertServiceProperty($baseURL); |
||||||
603 | $protocol = parse_url($baseURL, PHP_URL_SCHEME); |
||||||
604 | if ($protocol) { |
||||||
605 | return $protocol === 'https'; |
||||||
606 | } |
||||||
607 | } |
||||||
608 | |||||||
609 | // Check the current request |
||||||
610 | $request = static::currentRequest($request); |
||||||
611 | if ($request && ($scheme = $request->getScheme())) { |
||||||
612 | return $scheme === 'https'; |
||||||
613 | } |
||||||
614 | |||||||
615 | // Check default_base_url |
||||||
616 | if ($baseURL = self::config()->uninherited('default_base_url')) { |
||||||
617 | $baseURL = Injector::inst()->convertServiceProperty($baseURL); |
||||||
618 | $protocol = parse_url($baseURL, PHP_URL_SCHEME); |
||||||
619 | if ($protocol) { |
||||||
620 | return $protocol === 'https'; |
||||||
621 | } |
||||||
622 | } |
||||||
623 | |||||||
624 | return false; |
||||||
625 | } |
||||||
626 | |||||||
627 | /** |
||||||
628 | * Return the root-relative url for the baseurl |
||||||
629 | * |
||||||
630 | * @return string Root-relative url with trailing slash. |
||||||
631 | */ |
||||||
632 | public static function baseURL() |
||||||
633 | { |
||||||
634 | // Check override base_url |
||||||
635 | $alternate = self::config()->get('alternate_base_url'); |
||||||
636 | if ($alternate) { |
||||||
637 | $alternate = Injector::inst()->convertServiceProperty($alternate); |
||||||
638 | return rtrim(parse_url($alternate, PHP_URL_PATH), '/') . '/'; |
||||||
0 ignored issues
–
show
It seems like
$alternate can also be of type array ; however, parameter $url of parse_url() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
639 | } |
||||||
640 | |||||||
641 | // Get env base url |
||||||
642 | $baseURL = rtrim(BASE_URL, '/') . '/'; |
||||||
643 | |||||||
644 | // Check if BASE_SCRIPT_URL is defined |
||||||
645 | // e.g. `index.php/` |
||||||
646 | if (defined('BASE_SCRIPT_URL')) { |
||||||
647 | return $baseURL . BASE_SCRIPT_URL; |
||||||
0 ignored issues
–
show
|
|||||||
648 | } |
||||||
649 | |||||||
650 | return $baseURL; |
||||||
651 | } |
||||||
652 | |||||||
653 | /** |
||||||
654 | * Returns the root filesystem folder for the site. It will be automatically calculated unless |
||||||
655 | * it is overridden with {@link setBaseFolder()}. |
||||||
656 | * |
||||||
657 | * @return string |
||||||
658 | */ |
||||||
659 | public static function baseFolder() |
||||||
660 | { |
||||||
661 | $alternate = Director::config()->uninherited('alternate_base_folder'); |
||||||
0 ignored issues
–
show
As per coding style,
self should be used for accessing local static members.
This check looks for accesses to local static members using the fully qualified name instead
of <?php
class Certificate {
const TRIPLEDES_CBC = 'ASDFGHJKL';
private $key;
public function __construct()
{
$this->key = Certificate::TRIPLEDES_CBC;
}
}
While this is perfectly valid, the fully qualified name of
Loading history...
|
|||||||
662 | return $alternate ?: BASE_PATH; |
||||||
663 | } |
||||||
664 | |||||||
665 | /** |
||||||
666 | * Check if using a seperate public dir, and if so return this directory |
||||||
667 | * name. |
||||||
668 | * |
||||||
669 | * This will be removed in 5.0 and fixed to 'public' |
||||||
670 | * |
||||||
671 | * @return string |
||||||
672 | */ |
||||||
673 | public static function publicDir() |
||||||
674 | { |
||||||
675 | $alternate = self::config()->uninherited('alternate_public_dir'); |
||||||
676 | if (isset($alternate)) { |
||||||
677 | return $alternate; |
||||||
678 | } |
||||||
679 | return PUBLIC_DIR; |
||||||
680 | } |
||||||
681 | |||||||
682 | /** |
||||||
683 | * Gets the webroot of the project, which may be a subfolder of {@see baseFolder()} |
||||||
684 | * |
||||||
685 | * @return string |
||||||
686 | */ |
||||||
687 | public static function publicFolder() |
||||||
688 | { |
||||||
689 | $folder = self::baseFolder(); |
||||||
690 | $publicDir = self::publicDir(); |
||||||
691 | if ($publicDir) { |
||||||
692 | return Path::join($folder, $publicDir); |
||||||
693 | } |
||||||
694 | |||||||
695 | return $folder; |
||||||
696 | } |
||||||
697 | |||||||
698 | /** |
||||||
699 | * Turns an absolute URL or folder into one that's relative to the root of the site. This is useful |
||||||
700 | * when turning a URL into a filesystem reference, or vice versa. |
||||||
701 | * |
||||||
702 | * Note: You should check {@link Director::is_site_url()} if making an untrusted url relative prior |
||||||
703 | * to calling this function. |
||||||
704 | * |
||||||
705 | * @param string $url Accepts both a URL or a filesystem path. |
||||||
706 | * @return string |
||||||
707 | */ |
||||||
708 | public static function makeRelative($url) |
||||||
709 | { |
||||||
710 | // Allow for the accidental inclusion whitespace and // in the URL |
||||||
711 | $url = preg_replace('#([^:])//#', '\\1/', trim($url)); |
||||||
712 | |||||||
713 | // If using a real url, remove protocol / hostname / auth / port |
||||||
714 | if (preg_match('#^(?<protocol>https?:)?//(?<hostpart>[^/]*)(?<url>(/.*)?)$#i', $url, $matches)) { |
||||||
715 | $url = $matches['url']; |
||||||
716 | } |
||||||
717 | |||||||
718 | // Empty case |
||||||
719 | if (trim($url, '\\/') === '') { |
||||||
720 | return ''; |
||||||
721 | } |
||||||
722 | |||||||
723 | // Remove base folder or url |
||||||
724 | foreach ([self::publicFolder(), self::baseFolder(), self::baseURL()] as $base) { |
||||||
725 | // Ensure single / doesn't break comparison (unless it would make base empty) |
||||||
726 | $base = rtrim($base, '\\/') ?: $base; |
||||||
727 | if (stripos($url, $base) === 0) { |
||||||
728 | return ltrim(substr($url, strlen($base)), '\\/'); |
||||||
729 | } |
||||||
730 | } |
||||||
731 | |||||||
732 | // Nothing matched, fall back to returning the original URL |
||||||
733 | return $url; |
||||||
734 | } |
||||||
735 | |||||||
736 | /** |
||||||
737 | * Returns true if a given path is absolute. Works under both *nix and windows systems. |
||||||
738 | * |
||||||
739 | * @param string $path |
||||||
740 | * |
||||||
741 | * @return bool |
||||||
742 | */ |
||||||
743 | public static function is_absolute($path) |
||||||
744 | { |
||||||
745 | if (empty($path)) { |
||||||
746 | return false; |
||||||
747 | } |
||||||
748 | if ($path[0] == '/' || $path[0] == '\\') { |
||||||
749 | return true; |
||||||
750 | } |
||||||
751 | return preg_match('/^[a-zA-Z]:[\\\\\/]/', $path) == 1; |
||||||
752 | } |
||||||
753 | |||||||
754 | /** |
||||||
755 | * Determine if the url is root relative (i.e. starts with /, but not with //) SilverStripe |
||||||
756 | * considers root relative urls as a subset of relative urls. |
||||||
757 | * |
||||||
758 | * @param string $url |
||||||
759 | * |
||||||
760 | * @return bool |
||||||
761 | */ |
||||||
762 | public static function is_root_relative_url($url) |
||||||
763 | { |
||||||
764 | return strpos($url, '/') === 0 && strpos($url, '//') !== 0; |
||||||
765 | } |
||||||
766 | |||||||
767 | /** |
||||||
768 | * Checks if a given URL is absolute (e.g. starts with 'http://' etc.). URLs beginning with "//" |
||||||
769 | * are treated as absolute, as browsers take this to mean the same protocol as currently being used. |
||||||
770 | * |
||||||
771 | * Useful to check before redirecting based on a URL from user submissions through $_GET or $_POST, |
||||||
772 | * and avoid phishing attacks by redirecting to an attackers server. |
||||||
773 | * |
||||||
774 | * Note: Can't solely rely on PHP's parse_url() , since it is not intended to work with relative URLs |
||||||
775 | * or for security purposes. filter_var($url, FILTER_VALIDATE_URL) has similar problems. |
||||||
776 | * |
||||||
777 | * @param string $url |
||||||
778 | * |
||||||
779 | * @return bool |
||||||
780 | */ |
||||||
781 | public static function is_absolute_url($url) |
||||||
782 | { |
||||||
783 | // Strip off the query and fragment parts of the URL before checking |
||||||
784 | if (($queryPosition = strpos($url, '?')) !== false) { |
||||||
785 | $url = substr($url, 0, $queryPosition - 1); |
||||||
786 | } |
||||||
787 | if (($hashPosition = strpos($url, '#')) !== false) { |
||||||
788 | $url = substr($url, 0, $hashPosition - 1); |
||||||
789 | } |
||||||
790 | $colonPosition = strpos($url, ':'); |
||||||
791 | $slashPosition = strpos($url, '/'); |
||||||
792 | return ( |
||||||
793 | // Base check for existence of a host on a compliant URL |
||||||
794 | parse_url($url, PHP_URL_HOST) |
||||||
795 | // Check for more than one leading slash without a protocol. |
||||||
796 | // While not a RFC compliant absolute URL, it is completed to a valid URL by some browsers, |
||||||
797 | // and hence a potential security risk. Single leading slashes are not an issue though. |
||||||
798 | || preg_match('%^\s*/{2,}%', $url) |
||||||
799 | || ( |
||||||
800 | // If a colon is found, check if it's part of a valid scheme definition |
||||||
801 | // (meaning its not preceded by a slash). |
||||||
802 | $colonPosition !== false |
||||||
803 | && ($slashPosition === false || $colonPosition < $slashPosition) |
||||||
804 | ) |
||||||
805 | ); |
||||||
806 | } |
||||||
807 | |||||||
808 | /** |
||||||
809 | * Checks if a given URL is relative (or root relative) by checking {@link is_absolute_url()}. |
||||||
810 | * |
||||||
811 | * @param string $url |
||||||
812 | * |
||||||
813 | * @return bool |
||||||
814 | */ |
||||||
815 | public static function is_relative_url($url) |
||||||
816 | { |
||||||
817 | return !static::is_absolute_url($url); |
||||||
818 | } |
||||||
819 | |||||||
820 | /** |
||||||
821 | * Checks if the given URL is belonging to this "site" (not an external link). That's the case if |
||||||
822 | * the URL is relative, as defined by {@link is_relative_url()}, or if the host matches |
||||||
823 | * {@link protocolAndHost()}. |
||||||
824 | * |
||||||
825 | * Useful to check before redirecting based on a URL from user submissions through $_GET or $_POST, |
||||||
826 | * and avoid phishing attacks by redirecting to an attackers server. |
||||||
827 | * |
||||||
828 | * @param string $url |
||||||
829 | * |
||||||
830 | * @return bool |
||||||
831 | */ |
||||||
832 | public static function is_site_url($url) |
||||||
833 | { |
||||||
834 | // Validate user and password |
||||||
835 | if (!static::validateUserAndPass($url)) { |
||||||
836 | return false; |
||||||
837 | } |
||||||
838 | |||||||
839 | // Validate host[:port] |
||||||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
38% 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...
|
|||||||
840 | $urlHost = static::parseHost($url); |
||||||
841 | if ($urlHost && $urlHost === static::host()) { |
||||||
842 | return true; |
||||||
843 | } |
||||||
844 | |||||||
845 | // Relative urls always are site urls |
||||||
846 | return self::is_relative_url($url); |
||||||
847 | } |
||||||
848 | |||||||
849 | /** |
||||||
850 | * Given a filesystem reference relative to the site root, return the full file-system path. |
||||||
851 | * |
||||||
852 | * @param string $file |
||||||
853 | * |
||||||
854 | * @return string |
||||||
855 | */ |
||||||
856 | public static function getAbsFile($file) |
||||||
857 | { |
||||||
858 | // If already absolute |
||||||
859 | if (self::is_absolute($file)) { |
||||||
860 | return $file; |
||||||
861 | } |
||||||
862 | |||||||
863 | // If path is relative to public folder search there first |
||||||
864 | if (self::publicDir()) { |
||||||
865 | $path = Path::join(self::publicFolder(), $file); |
||||||
866 | if (file_exists($path)) { |
||||||
867 | return $path; |
||||||
868 | } |
||||||
869 | } |
||||||
870 | |||||||
871 | // Default to base folder |
||||||
872 | return Path::join(self::baseFolder(), $file); |
||||||
873 | } |
||||||
874 | |||||||
875 | /** |
||||||
876 | * Returns true if the given file exists. Filename should be relative to the site root. |
||||||
877 | * |
||||||
878 | * @param $file |
||||||
879 | * |
||||||
880 | * @return bool |
||||||
881 | */ |
||||||
882 | public static function fileExists($file) |
||||||
883 | { |
||||||
884 | // replace any appended query-strings, e.g. /path/to/foo.php?bar=1 to /path/to/foo.php |
||||||
885 | $file = preg_replace('/([^\?]*)?.*/', '$1', $file); |
||||||
886 | return file_exists(Director::getAbsFile($file)); |
||||||
0 ignored issues
–
show
As per coding style,
self should be used for accessing local static members.
This check looks for accesses to local static members using the fully qualified name instead
of <?php
class Certificate {
const TRIPLEDES_CBC = 'ASDFGHJKL';
private $key;
public function __construct()
{
$this->key = Certificate::TRIPLEDES_CBC;
}
}
While this is perfectly valid, the fully qualified name of
Loading history...
|
|||||||
887 | } |
||||||
888 | |||||||
889 | /** |
||||||
890 | * Returns the Absolute URL of the site root. |
||||||
891 | * |
||||||
892 | * @return string |
||||||
893 | */ |
||||||
894 | public static function absoluteBaseURL() |
||||||
895 | { |
||||||
896 | return self::absoluteURL( |
||||||
897 | self::baseURL(), |
||||||
898 | self::ROOT |
||||||
899 | ); |
||||||
900 | } |
||||||
901 | |||||||
902 | /** |
||||||
903 | * Returns the Absolute URL of the site root, embedding the current basic-auth credentials into |
||||||
904 | * the URL. |
||||||
905 | * |
||||||
906 | * @param HTTPRequest|null $request |
||||||
907 | * @return string |
||||||
908 | */ |
||||||
909 | public static function absoluteBaseURLWithAuth(HTTPRequest $request = null) |
||||||
910 | { |
||||||
911 | // Detect basic auth |
||||||
912 | $user = $request->getHeader('PHP_AUTH_USER'); |
||||||
0 ignored issues
–
show
The method
getHeader() does not exist on null .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed.
Loading history...
|
|||||||
913 | if ($user) { |
||||||
914 | $password = $request->getHeader('PHP_AUTH_PW'); |
||||||
915 | $login = sprintf("%s:%s@", $user, $password) ; |
||||||
916 | } else { |
||||||
917 | $login = ''; |
||||||
918 | } |
||||||
919 | |||||||
920 | return Director::protocol($request) . $login . static::host($request) . Director::baseURL(); |
||||||
0 ignored issues
–
show
As per coding style,
self should be used for accessing local static members.
This check looks for accesses to local static members using the fully qualified name instead
of <?php
class Certificate {
const TRIPLEDES_CBC = 'ASDFGHJKL';
private $key;
public function __construct()
{
$this->key = Certificate::TRIPLEDES_CBC;
}
}
While this is perfectly valid, the fully qualified name of
Loading history...
|
|||||||
921 | } |
||||||
922 | |||||||
923 | /** |
||||||
924 | * Skip any further processing and immediately respond with a redirect to the passed URL. |
||||||
925 | * |
||||||
926 | * @param string $destURL |
||||||
927 | * @throws HTTPResponse_Exception |
||||||
928 | */ |
||||||
929 | protected static function force_redirect($destURL) |
||||||
930 | { |
||||||
931 | // Redirect to installer |
||||||
932 | $response = new HTTPResponse(); |
||||||
933 | $response->redirect($destURL, 301); |
||||||
934 | throw new HTTPResponse_Exception($response); |
||||||
935 | } |
||||||
936 | |||||||
937 | /** |
||||||
938 | * Force the site to run on SSL. |
||||||
939 | * |
||||||
940 | * To use, call from the init() method of your PageController. For example: |
||||||
941 | * <code> |
||||||
942 | * if (Director::isLive()) Director::forceSSL(); |
||||||
943 | * </code> |
||||||
944 | * |
||||||
945 | * If you don't want your entire site to be on SSL, you can pass an array of PCRE regular expression |
||||||
946 | * patterns for matching relative URLs. For example: |
||||||
947 | * <code> |
||||||
948 | * if (Director::isLive()) Director::forceSSL(array('/^admin/', '/^Security/')); |
||||||
949 | * </code> |
||||||
950 | * |
||||||
951 | * If you want certain parts of your site protected under a different domain, you can specify |
||||||
952 | * the domain as an argument: |
||||||
953 | * <code> |
||||||
954 | * if (Director::isLive()) Director::forceSSL(array('/^admin/', '/^Security/'), 'secure.mysite.com'); |
||||||
955 | * </code> |
||||||
956 | * |
||||||
957 | * Note that the session data will be lost when moving from HTTP to HTTPS. It is your responsibility |
||||||
958 | * to ensure that this won't cause usability problems. |
||||||
959 | * |
||||||
960 | * CAUTION: This does not respect the site environment mode. You should check this |
||||||
961 | * as per the above examples using Director::isLive() or Director::isTest() for example. |
||||||
962 | * |
||||||
963 | * @param array $patterns Array of regex patterns to match URLs that should be HTTPS. |
||||||
964 | * @param string $secureDomain Secure domain to redirect to. Defaults to the current domain. |
||||||
965 | * Can include port number. |
||||||
966 | * @param HTTPRequest|null $request Request object to check |
||||||
967 | */ |
||||||
968 | public static function forceSSL($patterns = null, $secureDomain = null, HTTPRequest $request = null) |
||||||
969 | { |
||||||
970 | $handler = CanonicalURLMiddleware::singleton()->setForceSSL(true); |
||||||
971 | if ($patterns) { |
||||||
972 | $handler->setForceSSLPatterns($patterns); |
||||||
973 | } |
||||||
974 | if ($secureDomain) { |
||||||
975 | $handler->setForceSSLDomain($secureDomain); |
||||||
976 | } |
||||||
977 | $handler->throwRedirectIfNeeded($request); |
||||||
978 | } |
||||||
979 | |||||||
980 | /** |
||||||
981 | * Force a redirect to a domain starting with "www." |
||||||
982 | * |
||||||
983 | * @param HTTPRequest $request |
||||||
984 | */ |
||||||
985 | public static function forceWWW(HTTPRequest $request = null) |
||||||
986 | { |
||||||
987 | $handler = CanonicalURLMiddleware::singleton()->setForceWWW(true); |
||||||
988 | $handler->throwRedirectIfNeeded($request); |
||||||
989 | } |
||||||
990 | |||||||
991 | /** |
||||||
992 | * Checks if the current HTTP-Request is an "Ajax-Request" by checking for a custom header set by |
||||||
993 | * jQuery or whether a manually set request-parameter 'ajax' is present. |
||||||
994 | * |
||||||
995 | * Note that if you plan to use this to alter your HTTP response on a cached page, |
||||||
996 | * you should add X-Requested-With to the Vary header. |
||||||
997 | * |
||||||
998 | * @param HTTPRequest $request |
||||||
999 | * @return bool |
||||||
1000 | */ |
||||||
1001 | public static function is_ajax(HTTPRequest $request = null) |
||||||
1002 | { |
||||||
1003 | $request = self::currentRequest($request); |
||||||
1004 | if ($request) { |
||||||
0 ignored issues
–
show
|
|||||||
1005 | return $request->isAjax(); |
||||||
1006 | } |
||||||
1007 | |||||||
1008 | return ( |
||||||
1009 | isset($_REQUEST['ajax']) || |
||||||
1010 | (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == "XMLHttpRequest") |
||||||
1011 | ); |
||||||
1012 | } |
||||||
1013 | |||||||
1014 | /** |
||||||
1015 | * Returns true if this script is being run from the command line rather than the web server. |
||||||
1016 | * |
||||||
1017 | * @return bool |
||||||
1018 | */ |
||||||
1019 | public static function is_cli() |
||||||
1020 | { |
||||||
1021 | return in_array(php_sapi_name(), ['cli', 'phpdbg']); |
||||||
1022 | } |
||||||
1023 | |||||||
1024 | /** |
||||||
1025 | * Can also be checked with {@link Director::isDev()}, {@link Director::isTest()}, and |
||||||
1026 | * {@link Director::isLive()}. |
||||||
1027 | * |
||||||
1028 | * @return string |
||||||
1029 | */ |
||||||
1030 | public static function get_environment_type() |
||||||
1031 | { |
||||||
1032 | /** @var Kernel $kernel */ |
||||||
1033 | $kernel = Injector::inst()->get(Kernel::class); |
||||||
1034 | return $kernel->getEnvironment(); |
||||||
1035 | } |
||||||
1036 | |||||||
1037 | /** |
||||||
1038 | * This function will return true if the site is in a live environment. For information about |
||||||
1039 | * environment types, see {@link Director::set_environment_type()}. |
||||||
1040 | * |
||||||
1041 | * @return bool |
||||||
1042 | */ |
||||||
1043 | public static function isLive() |
||||||
1044 | { |
||||||
1045 | return self::get_environment_type() === 'live'; |
||||||
1046 | } |
||||||
1047 | |||||||
1048 | /** |
||||||
1049 | * This function will return true if the site is in a development environment. For information about |
||||||
1050 | * environment types, see {@link Director::set_environment_type()}. |
||||||
1051 | * |
||||||
1052 | * @return bool |
||||||
1053 | */ |
||||||
1054 | public static function isDev() |
||||||
1055 | { |
||||||
1056 | return self::get_environment_type() === 'dev'; |
||||||
1057 | } |
||||||
1058 | |||||||
1059 | /** |
||||||
1060 | * This function will return true if the site is in a test environment. For information about |
||||||
1061 | * environment types, see {@link Director::set_environment_type()}. |
||||||
1062 | * |
||||||
1063 | * @return bool |
||||||
1064 | */ |
||||||
1065 | public static function isTest() |
||||||
1066 | { |
||||||
1067 | return self::get_environment_type() === 'test'; |
||||||
1068 | } |
||||||
1069 | |||||||
1070 | /** |
||||||
1071 | * Returns an array of strings of the method names of methods on the call that should be exposed |
||||||
1072 | * as global variables in the templates. |
||||||
1073 | * |
||||||
1074 | * @return array |
||||||
1075 | */ |
||||||
1076 | public static function get_template_global_variables() |
||||||
1077 | { |
||||||
1078 | return array( |
||||||
1079 | 'absoluteBaseURL', |
||||||
1080 | 'baseURL', |
||||||
1081 | 'is_ajax', |
||||||
1082 | 'isAjax' => 'is_ajax', |
||||||
1083 | 'BaseHref' => 'absoluteBaseURL', //@deprecated 3.0 |
||||||
1084 | ); |
||||||
1085 | } |
||||||
1086 | |||||||
1087 | /** |
||||||
1088 | * Helper to validate or check the current request object |
||||||
1089 | * |
||||||
1090 | * @param HTTPRequest $request |
||||||
1091 | * @return HTTPRequest Request object if one is both current and valid |
||||||
1092 | */ |
||||||
1093 | protected static function currentRequest(HTTPRequest $request = null) |
||||||
1094 | { |
||||||
1095 | // Ensure we only use a registered HTTPRequest and don't |
||||||
1096 | // incidentally construct a singleton |
||||||
1097 | if (!$request && Injector::inst()->has(HTTPRequest::class)) { |
||||||
1098 | $request = Injector::inst()->get(HTTPRequest::class); |
||||||
1099 | } |
||||||
1100 | return $request; |
||||||
1101 | } |
||||||
1102 | } |
||||||
1103 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths