Upgrade to 3.7.0

This commit is contained in:
Bastian Allgeier
2022-06-27 10:02:22 +02:00
parent 0751a6510d
commit 1c22148d7b
674 changed files with 5052 additions and 3082 deletions

28
kirby/src/Http/Cookie.php Normal file → Executable file
View File

@@ -2,6 +2,7 @@
namespace Kirby\Http;
use Kirby\Cms\App;
use Kirby\Toolkit\Str;
/**
@@ -41,6 +42,9 @@ class Cookie
*/
public static function set(string $key, string $value, array $options = []): bool
{
// modify CMS caching behavior
static::trackUsage($key);
// extract options
$expires = static::lifetime($options['lifetime'] ?? 0);
$path = $options['path'] ?? '/';
@@ -123,6 +127,10 @@ class Cookie
if ($key === null) {
return $_COOKIE;
}
// modify CMS caching behavior
static::trackUsage($key);
$value = $_COOKIE[$key] ?? null;
return empty($value) ? $default : static::parse($value);
}
@@ -206,4 +214,24 @@ class Cookie
return false;
}
/**
* Tells the CMS responder that the response relies on a cookie and
* its value (even if the cookie isn't set in the current request);
* this ensures that the response is only cached for visitors who don't
* have this cookie set;
* https://github.com/getkirby/kirby/issues/4423#issuecomment-1166300526
*
* @param string $key
* @return void
*/
protected static function trackUsage(string $key): void
{
// lazily request the instance for non-CMS use cases
$kirby = App::instance(null, true);
if ($kirby) {
$kirby->response()->usesCookie($key);
}
}
}

1039
kirby/src/Http/Environment.php Executable file

File diff suppressed because it is too large Load Diff

0
kirby/src/Http/Exceptions/NextRouteException.php Normal file → Executable file
View File

2
kirby/src/Http/Header.php Normal file → Executable file
View File

@@ -130,7 +130,7 @@ class Header
public static function status($code = null, bool $send = true)
{
$codes = static::$codes;
$protocol = $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.1';
$protocol = Environment::getGlobally('SERVER_PROTOCOL', 'HTTP/1.1');
// allow full control over code and message
if (is_string($code) === true && preg_match('/^\d{3} \w.+$/', $code) === 1) {

0
kirby/src/Http/Idn.php Normal file → Executable file
View File

0
kirby/src/Http/Params.php Normal file → Executable file
View File

0
kirby/src/Http/Path.php Normal file → Executable file
View File

0
kirby/src/Http/Query.php Normal file → Executable file
View File

0
kirby/src/Http/Remote.php Normal file → Executable file
View File

70
kirby/src/Http/Request.php Normal file → Executable file
View File

@@ -2,8 +2,7 @@
namespace Kirby\Http;
use Kirby\Http\Request\Auth\BasicAuth;
use Kirby\Http\Request\Auth\BearerAuth;
use Kirby\Cms\App;
use Kirby\Http\Request\Body;
use Kirby\Http\Request\Files;
use Kirby\Http\Request\Query;
@@ -23,10 +22,16 @@ use Kirby\Toolkit\Str;
*/
class Request
{
public static $authTypes = [
'basic' => 'Kirby\Http\Request\Auth\BasicAuth',
'bearer' => 'Kirby\Http\Request\Auth\BearerAuth',
'session' => 'Kirby\Http\Request\Auth\SessionAuth',
];
/**
* The auth object if available
*
* @var BearerAuth|BasicAuth|false|null
* @var \Kirby\Http\Request\Auth|false|null
*/
protected $auth;
@@ -109,19 +114,19 @@ class Request
$this->method = $this->detectRequestMethod($options['method'] ?? null);
if (isset($options['body']) === true) {
$this->body = new Body($options['body']);
$this->body = is_a($options['body'], Body::class) ? $options['body'] : new Body($options['body']);
}
if (isset($options['files']) === true) {
$this->files = new Files($options['files']);
$this->files = is_a($options['files'], Files::class) ? $options['files'] : new Files($options['files']);
}
if (isset($options['query']) === true) {
$this->query = new Query($options['query']);
$this->query = is_a($options['query'], Query::class) === true ? $options['query'] : new Query($options['query']);
}
if (isset($options['url']) === true) {
$this->url = new Uri($options['url']);
$this->url = is_a($options['url'], Uri::class) === true ? $options['url'] : new Uri($options['url']);
}
}
@@ -144,7 +149,7 @@ class Request
/**
* Returns the Auth object if authentication is set
*
* @return \Kirby\Http\Request\Auth\BasicAuth|\Kirby\Http\Request\Auth\BearerAuth|null
* @return \Kirby\Http\Request\Auth|null
*/
public function auth()
{
@@ -152,16 +157,31 @@ class Request
return $this->auth;
}
if ($auth = $this->options['auth'] ?? $this->header('authorization')) {
$type = Str::before($auth, ' ');
$token = Str::after($auth, ' ');
$class = 'Kirby\\Http\\Request\\Auth\\' . ucfirst($type) . 'Auth';
// lazily request the instance for non-CMS use cases
$kirby = App::instance(null, true);
if (class_exists($class) === false) {
// tell the CMS responder that the response relies on
// the `Authorization` header and its value (even if
// the header isn't set in the current request);
// this ensures that the response is only cached for
// unauthenticated visitors;
// https://github.com/getkirby/kirby/issues/4423#issuecomment-1166300526
if ($kirby) {
$kirby->response()->usesAuth(true);
}
if ($auth = $this->options['auth'] ?? $this->header('authorization')) {
$type = Str::lower(Str::before($auth, ' '));
$data = Str::after($auth, ' ');
$class = static::$authTypes[$type] ?? null;
if (!$class || class_exists($class) === false) {
return $this->auth = false;
}
return $this->auth = new $class($token);
$object = new $class($data);
return $this->auth = $object;
}
return $this->auth = false;
@@ -184,7 +204,7 @@ class Request
*/
public function cli(): bool
{
return Server::cli();
return $this->options['cli'] ?? (new Environment())->cli();
}
/**
@@ -220,14 +240,14 @@ class Request
$methods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH'];
// the request method can be overwritten with a header
$methodOverride = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] ?? '');
$methodOverride = strtoupper(Environment::getGlobally('HTTP_X_HTTP_METHOD_OVERRIDE', ''));
if ($method === null && in_array($methodOverride, $methods) === true) {
$method = $methodOverride;
}
// final chain of options to detect the method
$method = $method ?? $_SERVER['REQUEST_METHOD'] ?? 'GET';
$method = $method ?? Environment::getGlobally('REQUEST_METHOD', 'GET');
// uppercase the shit out of it
$method = strtoupper($method);
@@ -285,6 +305,20 @@ class Request
return A::get($this->data(), $key, $fallback);
}
/**
* Returns whether the request contains
* the `Authorization` header
* @since 3.7.0
*
* @return bool
*/
public function hasAuth(): bool
{
$header = $this->options['auth'] ?? $this->header('authorization');
return $header !== null;
}
/**
* Returns a header by key if it exists
*
@@ -308,7 +342,7 @@ class Request
{
$headers = [];
foreach ($_SERVER as $key => $value) {
foreach (Environment::getGlobally() as $key => $value) {
if (substr($key, 0, 5) !== 'HTTP_' && substr($key, 0, 14) !== 'REDIRECT_HTTP_') {
continue;
}

61
kirby/src/Http/Request/Auth.php Executable file
View File

@@ -0,0 +1,61 @@
<?php
namespace Kirby\Http\Request;
/**
* Base class for auth types
*
* @package Kirby Http
* @author Lukas Bestle <lukas@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
*/
abstract class Auth
{
/**
* Raw authentication data after the first space
* in the `Authorization` header
*
* @var string
*/
protected $data;
/**
* Constructor
*
* @param string $data
*/
public function __construct(string $data)
{
$this->data = $data;
}
/**
* Converts the object to a string
*
* @return string
*/
public function __toString(): string
{
return ucfirst($this->type()) . ' ' . $this->data();
}
/**
* Returns the raw authentication data after the
* first space in the `Authorization` header
*
* @return string
*/
public function data(): string
{
return $this->data;
}
/**
* Returns the name of the auth type (lowercase)
*
* @return string
*/
abstract public function type(): string;
}

17
kirby/src/Http/Request/Auth/BasicAuth.php Normal file → Executable file
View File

@@ -2,12 +2,19 @@
namespace Kirby\Http\Request\Auth;
use Kirby\Http\Request\Auth;
use Kirby\Toolkit\Str;
/**
* Basic Authentication
* HTTP basic authentication data
*
* @package Kirby Http
* @author Bastian Allgeier <bastian@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
*/
class BasicAuth extends BearerAuth
class BasicAuth extends Auth
{
/**
* @var string
@@ -27,11 +34,11 @@ class BasicAuth extends BearerAuth
/**
* @param string $token
*/
public function __construct(string $token)
public function __construct(string $data)
{
parent::__construct($token);
parent::__construct($data);
$this->credentials = base64_decode($token);
$this->credentials = base64_decode($data);
$this->username = Str::before($this->credentials, ':');
$this->password = Str::after($this->credentials, ':');
}

39
kirby/src/Http/Request/Auth/BearerAuth.php Normal file → Executable file
View File

@@ -2,36 +2,19 @@
namespace Kirby\Http\Request\Auth;
use Kirby\Http\Request\Auth;
/**
* Bearer Auth
* Bearer token authentication data
*
* @package Kirby Http
* @author Bastian Allgeier <bastian@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
*/
class BearerAuth
class BearerAuth extends Auth
{
/**
* @var string
*/
protected $token;
/**
* Creates a new Bearer Auth object
*
* @param string $token
*/
public function __construct(string $token)
{
$this->token = $token;
}
/**
* Converts the object to a string
*
* @return string
*/
public function __toString(): string
{
return ucfirst($this->type()) . ' ' . $this->token();
}
/**
* Returns the authentication token
*
@@ -39,7 +22,7 @@ class BearerAuth
*/
public function token(): string
{
return $this->token;
return $this->data;
}
/**

View File

@@ -0,0 +1,48 @@
<?php
namespace Kirby\Http\Request\Auth;
use Kirby\Cms\App;
use Kirby\Http\Request\Auth;
/**
* Authentication data using Kirby's session
*
* @package Kirby Http
* @author Lukas Bestle <lukas@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
*/
class SessionAuth extends Auth
{
/**
* Tries to return the session object
*
* @return \Kirby\Session\Session
*/
public function session()
{
return App::instance()->sessionHandler()->getManually($this->data);
}
/**
* Returns the session token
*
* @return string
*/
public function token(): string
{
return $this->data;
}
/**
* Returns the authentication type
*
* @return string
*/
public function type(): string
{
return 'session';
}
}

0
kirby/src/Http/Request/Body.php Normal file → Executable file
View File

0
kirby/src/Http/Request/Data.php Normal file → Executable file
View File

0
kirby/src/Http/Request/Files.php Normal file → Executable file
View File

0
kirby/src/Http/Request/Query.php Normal file → Executable file
View File

17
kirby/src/Http/Response.php Normal file → Executable file
View File

@@ -200,6 +200,23 @@ class Response
return new static($props);
}
/**
* Redirects to the given Urls
* Urls can be relative or absolute.
* @since 3.7.0
*
* @param string $url
* @param int $code
* @return void
*
* @codeCoverageIgnore
*/
public static function go(string $url = '/', int $code = 302)
{
die(static::redirect($url, $code));
}
/**
* Getter for single headers
*

0
kirby/src/Http/Route.php Normal file → Executable file
View File

54
kirby/src/Http/Router.php Normal file → Executable file
View File

@@ -16,14 +16,25 @@ use Kirby\Toolkit\A;
*/
class Router
{
public static $beforeEach;
public static $afterEach;
/**
* Hook that is called after each route
*
* @var \Closure
*/
protected $afterEach;
/**
* Hook that is called before each route
*
* @var \Closure
*/
protected $beforeEach;
/**
* Store for the current route,
* if one can be found
*
* @var Route|null
* @var \Kirby\Http\Route|null
*/
protected $route;
@@ -52,9 +63,13 @@ class Router
* registers all the given routes
*
* @param array $routes
* @param array<string, \Closure> $hooks Optional `beforeEach` and `afterEach` hooks
*/
public function __construct(array $routes = [])
public function __construct(array $routes = [], array $hooks = [])
{
$this->beforeEach = $hooks['beforeEach'] ?? null;
$this->afterEach = $hooks['afterEach'] ?? null;
foreach ($routes as $props) {
if (isset($props['pattern'], $props['action']) === false) {
throw new InvalidArgumentException('Invalid route parameters');
@@ -72,7 +87,12 @@ class Router
foreach ($methods as $method) {
foreach ($patterns as $pattern) {
$this->routes[$method][] = new Route($pattern, $method, $props['action'], $props);
$this->routes[$method][] = new Route(
$pattern,
$method,
$props['action'],
$props
);
}
}
}
@@ -100,8 +120,8 @@ class Router
while ($loop === true) {
$route = $this->find($path, $method, $ignore);
if (is_a(static::$beforeEach, 'Closure') === true) {
(static::$beforeEach)($route, $path, $method);
if (is_a($this->beforeEach, 'Closure') === true) {
($this->beforeEach)($route, $path, $method);
}
try {
@@ -116,15 +136,31 @@ class Router
$ignore[] = $route;
}
if (is_a(static::$afterEach, 'Closure') === true) {
if (is_a($this->afterEach, 'Closure') === true) {
$final = $loop === false;
$result = (static::$afterEach)($route, $path, $method, $result, $final);
$result = ($this->afterEach)($route, $path, $method, $result, $final);
}
}
return $result;
}
/**
* Creates a micro-router and executes
* the routing action immediately
* @since 3.7.0
*
* @param string|null $path
* @param string $method
* @param array $routes
* @param \Closure|null $callback
* @return mixed
*/
public static function execute(?string $path = null, string $method = 'GET', array $routes = [], ?Closure $callback = null)
{
return (new static($routes))->call($path, $method, $callback);
}
/**
* Finds a Route object by path and method
* The Route's arguments method is used to

339
kirby/src/Http/Server.php Normal file → Executable file
View File

@@ -2,7 +2,7 @@
namespace Kirby\Http;
use Kirby\Toolkit\A;
use Kirby\Toolkit\Facade;
/**
* A set of methods that make it more convenient to get variables
@@ -13,343 +13,26 @@ use Kirby\Toolkit\A;
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
* @deprecated 3.7.0 Use `Kirby\Http\Environment` instead
* @todo Remove in 3.8.0
*/
class Server
class Server extends Facade
{
public const HOST_FROM_SERVER = 1;
public const HOST_FROM_HEADER = 2;
public const HOST_ALLOW_EMPTY = 4;
/**
* Cache for the cli status
*
* @var bool|null
*/
public static $cli;
public static $hosts;
/**
* List of trusted hosts
*
* @var array
* @return \Kirby\Http\Environment
*/
public static $hosts = [];
/**
* Returns the server's IP address
*
* @return string
*/
public static function address(): string
public static function instance()
{
return static::get('SERVER_ADDR', '');
}
/**
* Checks if the request is being served by the CLI
*
* @return bool
*/
public static function cli(): bool
{
if (static::$cli !== null) {
return static::$cli;
}
if (defined('STDIN') === true) {
return static::$cli = true;
}
$term = getenv('TERM');
if (substr(PHP_SAPI, 0, 3) === 'cgi' && $term && $term !== 'unknown') {
return static::$cli = true;
}
return static::$cli = false;
}
/**
* Gets a value from the _SERVER array
*
* <code>
* Server::get('document_root');
* // sample output: /var/www/kirby
*
* Server::get();
* // returns the whole server array
* </code>
*
* @param mixed $key The key to look for. Pass false or null to
* return the entire server array.
* @param mixed $default Optional default value, which should be
* returned if no element has been found
* @return mixed
*/
public static function get($key = null, $default = null)
{
if ($key === null) {
return $_SERVER;
}
$key = strtoupper($key);
$value = $_SERVER[$key] ?? $default;
return static::sanitize($key, $value);
}
/**
* Returns the correct host
*
* @param bool $forwarded Deprecated. Todo: remove in 3.7.0
* @return string
*/
public static function host(bool $forwarded = false): string
{
$hosts[] = static::get('SERVER_NAME');
$hosts[] = static::get('SERVER_ADDR');
// insecure host parameters are only allowed when hosts
// are validated against set of host patterns
if (empty(static::$hosts) === false) {
$hosts[] = static::get('HTTP_HOST');
$hosts[] = static::get('HTTP_X_FORWARDED_HOST');
}
// remove empty hosts
$hosts = array_filter($hosts);
foreach ($hosts as $host) {
if (static::isAllowedHost($host) === true) {
return explode(':', $host)[0];
}
}
return '';
}
/**
* Setter and getter for the the static $hosts property
*
* $hosts = null -> return all defined hosts
* $hosts = Server::HOST_FROM_SERVER -> []
* $hosts = Server::HOST_FROM_HEADER -> ['*']
* $hosts = array -> [array of trusted hosts]
* $hosts = string -> [single trusted host]
*
* @param string|array|int|null $hosts
* @return array
*/
public static function hosts($hosts = null): array
{
if ($hosts === null) {
return static::$hosts;
}
if (is_int($hosts) && $hosts & static::HOST_FROM_SERVER) {
return static::$hosts = [];
}
if (is_int($hosts) && $hosts & static::HOST_FROM_HEADER) {
return static::$hosts = ['*'];
}
// make sure hosts are always an array
$hosts = A::wrap($hosts);
// return unique hosts
return static::$hosts = array_unique($hosts);
}
/**
* Checks for a https request
*
* @return bool
*/
public static function https(): bool
{
$https = $_SERVER['HTTPS'] ?? null;
$off = ['off', null, '', 0, '0', false, 'false', -1, '-1'];
// check for various options to send a negative HTTPS header
if (in_array($https, $off, true) === false) {
return true;
}
// check for the port
if (static::port() === 443) {
return true;
}
return false;
}
/**
* Checks for allowed host names
*
* @param string $host
* @return bool
*/
public static function isAllowedHost(string $host): bool
{
if (empty(static::$hosts) === true) {
return true;
}
foreach (static::$hosts as $pattern) {
if (empty($pattern) === true) {
continue;
}
if (fnmatch($pattern, $host) === true) {
return true;
}
}
return false;
}
/**
* Checks if the server is behind a
* proxy server.
*
* @return bool
*/
public static function isBehindProxy(): bool
{
return empty($_SERVER['HTTP_X_FORWARDED_HOST']) === false;
}
/**
* Returns the correct port number
*
* @param bool $forwarded Deprecated. Todo: remove in 3.7.0
* @return int
*/
public static function port(bool $forwarded = false): int
{
$port = null;
// handle reverse proxy setups
if (static::isBehindProxy() === true) {
// based on forwarded port
$port = static::get('HTTP_X_FORWARDED_PORT');
// based on the forwarded host
if (empty($port) === true) {
$port = (int)parse_url(static::get('HTTP_X_FORWARDED_HOST'), PHP_URL_PORT);
}
// based on the forwarded proto
if (empty($port) === true) {
if (in_array($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? null, ['https', 'https, http']) === true) {
$port = 443;
}
}
}
// based on the host
if (empty($port) === true) {
$port = (int)parse_url(static::get('HTTP_HOST'), PHP_URL_PORT);
}
// based on server port
if (empty($port) === true) {
$port = static::get('SERVER_PORT');
}
return $port ?? 0;
}
/**
* Returns an array with path and query
* from the REQUEST_URI
*
* @return array
*/
public static function requestUri(): array
{
$uri = static::get('REQUEST_URI', '');
if (Url::isAbsolute($uri) === true) {
$uri = parse_url($uri);
} else {
// the fake domain is needed to make sure the URL parsing is
// always correct. Even if there's a colon in the path for params
$uri = parse_url('http://getkirby.com' . $uri);
}
return [
'path' => $uri['path'] ?? null,
'query' => $uri['query'] ?? null,
];
}
/**
* Help to sanitize some _SERVER keys
*
* @param string $key
* @param mixed $value
* @return mixed
*/
public static function sanitize(string $key, $value)
{
switch ($key) {
case 'SERVER_ADDR':
case 'SERVER_NAME':
case 'HTTP_HOST':
case 'HTTP_X_FORWARDED_HOST':
$value ??= '';
$value = strtolower($value);
$value = strip_tags($value);
$value = basename($value);
$value = preg_replace('![^\w.:-]+!iu', '', $value);
$value = htmlspecialchars($value, ENT_COMPAT);
$value = trim($value, '-');
$value = trim($value, '.');
break;
case 'SERVER_PORT':
case 'HTTP_X_FORWARDED_PORT':
$value ??= '';
$value = (int)(preg_replace('![^0-9]+!', '', $value));
break;
}
return $value;
}
/**
* Returns the path to the php script
* within the document root without the
* filename of the script.
*
* i.e. /subfolder/index.php -> subfolder
*
* This can be used to build the base url
* for subfolder installations
*
* @return string
*/
public static function scriptPath(): string
{
if (static::cli() === true) {
return '';
}
$path = $_SERVER['SCRIPT_NAME'] ?? '';
// replace Windows backslashes
$path = str_replace('\\', '/', $path);
// remove the script
$path = dirname($path);
// replace those fucking backslashes again
$path = str_replace('\\', '/', $path);
// remove the leading and trailing slashes
$path = trim($path, '/');
// top-level scripts don't have a path
// and dirname() will return '.'
if ($path === '.') {
$path = '';
}
return $path;
return new Environment([
'cli' => static::$cli,
'allowed' => static::$hosts
]);
}
}

45
kirby/src/Http/Uri.php Normal file → Executable file
View File

@@ -2,6 +2,7 @@
namespace Kirby\Http;
use Kirby\Cms\App;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Toolkit\Properties;
use Throwable;
@@ -234,25 +235,21 @@ class Uri
/**
* @param array $props
* @param bool $forwarded Deprecated! Todo: remove in 3.7.0
* @return static
*/
public static function current(array $props = [], bool $forwarded = false)
public static function current(array $props = [])
{
if (static::$current !== null) {
return static::$current;
}
$uri = Server::requestUri();
$url = new static(array_merge([
'scheme' => Server::https() === true ? 'https' : 'http',
'host' => Server::host(),
'port' => Server::port(),
'path' => $uri['path'],
'query' => $uri['query'],
], $props));
if ($app = App::instance(null, true)) {
$url = $app->url('current');
} else {
$url = (new Environment())->requestUrl();
}
return $url;
return new static($url, $props);
}
/**
@@ -306,6 +303,14 @@ class Uri
return $this->query()->isNotEmpty();
}
/**
* @return bool
*/
public function https(): bool
{
return $this->scheme() === 'https';
}
/**
* Tries to convert the internationalized host
* name to the human-readable UTF8 representation
@@ -325,18 +330,18 @@ class Uri
* or any other executed script.
*
* @param array $props
* @param bool $forwarded Deprecated! Todo: remove in 3.7.0
* @return string
* @return static
*/
public static function index(array $props = [], bool $forwarded = false)
public static function index(array $props = [])
{
return static::current(array_merge($props, [
'path' => Server::scriptPath(),
'query' => null,
'fragment' => null,
]));
}
if ($app = App::instance(null, true)) {
$url = $app->url('index');
} else {
$url = (new Environment())->baseUrl();
}
return new static($url, $props);
}
/**
* Checks if the host exists

5
kirby/src/Http/Url.php Normal file → Executable file
View File

@@ -100,10 +100,9 @@ class Url
* Returns the url to the executed script
*
* @param array $props
* @param bool $forwarded Deprecated! Todo: remove in 3.7.0
* @return string
*/
public static function index(array $props = [], bool $forwarded = false): string
public static function index(array $props = []): string
{
return Uri::index($props)->toString();
}
@@ -186,7 +185,7 @@ class Url
*/
public static function last(): string
{
return $_SERVER['HTTP_REFERER'] ?? '';
return Environment::getGlobally('HTTP_REFERER', '');
}
/**

8
kirby/src/Http/Visitor.php Normal file → Executable file
View File

@@ -55,10 +55,10 @@ class Visitor
*/
public function __construct(array $arguments = [])
{
$this->ip($arguments['ip'] ?? $_SERVER['REMOTE_ADDR'] ?? '');
$this->userAgent($arguments['userAgent'] ?? $_SERVER['HTTP_USER_AGENT'] ?? '');
$this->acceptedLanguage($arguments['acceptedLanguage'] ?? $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '');
$this->acceptedMimeType($arguments['acceptedMimeType'] ?? $_SERVER['HTTP_ACCEPT'] ?? '');
$this->ip($arguments['ip'] ?? Environment::getGlobally('REMOTE_ADDR', ''));
$this->userAgent($arguments['userAgent'] ?? Environment::getGlobally('HTTP_USER_AGENT', ''));
$this->acceptedLanguage($arguments['acceptedLanguage'] ?? Environment::getGlobally('HTTP_ACCEPT_LANGUAGE', ''));
$this->acceptedMimeType($arguments['acceptedMimeType'] ?? Environment::getGlobally('HTTP_ACCEPT', ''));
}
/**