update kirby to v5 and add refresh cache panel view button

This commit is contained in:
isUnknown 2025-09-10 14:28:38 +02:00
commit 9a86d41254
466 changed files with 19960 additions and 10497 deletions

View file

@ -25,12 +25,10 @@ class Cookie
/**
* Set a new cookie
*
* <code>
*
* cookie::set('mycookie', 'hello', ['lifetime' => 60]);
* ```php
* // expires in 1 hour
*
* </code>
* Cookie::set('mycookie', 'hello', ['lifetime' => 60]);
* ```
*
* @param string $key The name of the cookie
* @param string $value The cookie content
@ -92,12 +90,10 @@ class Cookie
/**
* Stores a cookie forever
*
* <code>
*
* cookie::forever('mycookie', 'hello');
* ```php
* // never expires
*
* </code>
* Cookie::forever('mycookie', 'hello');
* ```
*
* @param string $key The name of the cookie
* @param string $value The cookie content
@ -119,10 +115,10 @@ class Cookie
/**
* Get a cookie value
*
* <code>
* cookie::get('mycookie', 'peter');
* ```php
* // sample output: 'hello' or if the cookie is not set 'peter'
* </code>
* Cookie::get('mycookie', 'peter');
* ```
*
* @param string|null $key The name of the cookie
* @param string|null $default The default value, which should be returned
@ -171,7 +167,7 @@ class Cookie
protected static function parse(string $string): string|null
{
// if no hash-value separator is present, we can't parse the value
if (strpos($string, '+') === false) {
if (str_contains($string, '+') === false) {
return null;
}
@ -197,12 +193,10 @@ class Cookie
/**
* Remove a cookie
*
* <code>
*
* cookie::remove('mycookie');
* ```php
* // mycookie is now gone
*
* </code>
* Cookie::remove('mycookie');
* ```
*
* @param string $key The name of the cookie
* @return bool true: the cookie has been removed,

View file

@ -112,7 +112,7 @@ class Environment
/**
* Returns the server's IP address
* @see ::ip
* @see self::ip()
*/
public function address(): string|null
{
@ -156,13 +156,13 @@ class Environment
array|null $options = null,
array|null $info = null
): array {
$defaults = [
$options = [
'cli' => null,
'allowed' => null
'allowed' => null,
...$options ?? []
];
$info ??= $_SERVER;
$options = array_merge($defaults, $options ?? []);
$info ??= $_SERVER;
$this->info = static::sanitize($info);
$this->cli = $this->detectCli($options['cli']);
@ -178,11 +178,11 @@ class Environment
if ($options['allowed'] === '*' || $options['allowed'] === ['*']) {
$this->detectAuto(true);
// fixed environments
// fixed environments
} elseif (empty($options['allowed']) === false) {
$this->detectAllowed($options['allowed']);
// secure auto-detection
// secure auto-detection
} else {
$this->detectAuto();
}
@ -211,7 +211,9 @@ class Environment
$baseUrl = A::first($allowed);
if (is_string($baseUrl) === false) {
throw new InvalidArgumentException('Invalid allow list setup for base URLs');
throw new InvalidArgumentException(
message: 'Invalid allow list setup for base URLs'
);
}
$uri = new Uri($baseUrl, ['slash' => false]);
@ -248,7 +250,9 @@ class Environment
}
}
throw new InvalidArgumentException('The environment is not allowed');
throw new InvalidArgumentException(
message: 'The environment is not allowed'
);
}
/**
@ -330,7 +334,7 @@ class Environment
$term = getenv('TERM');
if (
substr($sapi, 0, 3) === 'cgi' &&
str_starts_with($sapi, 'cgi') === true &&
$term &&
$term !== 'unknown'
) {
@ -529,7 +533,7 @@ class Environment
$protocols = ['https', 'https, http'];
return in_array(strtolower($protocol), $protocols) === true;
return in_array(strtolower($protocol), $protocols, true) === true;
}
/**
@ -634,13 +638,13 @@ class Environment
/**
* Gets a value from the server environment array
*
* <code>
* $server->get('document_root');
* ```php
* // sample output: /var/www/kirby
* $server->get('document_root');
*
* $server->get();
* // returns the whole server array
* </code>
* $server->get();
* ```
*
* @param string|false|null $key The key to look for. Pass `false` or `null`
* to return the entire server array.
@ -771,13 +775,13 @@ class Environment
$ips = array_unique(array_filter($ips));
// no known ip? Better not assume it's local
if (empty($ips) === true) {
if ($ips === []) {
return false;
}
// stop as soon as a non-local ip is found
foreach ($ips as $ip) {
if (in_array($ip, ['::1', '127.0.0.1']) === false) {
if (in_array($ip, ['::1', '127.0.0.1'], true) === false) {
return false;
}
}
@ -810,18 +814,24 @@ class Environment
}
// load the config for the host
if (empty($host) === false) {
if (
empty($host) === false &&
F::exists($path = $root . '/config.' . $host . '.php', $root) === true
) {
$configHost = F::load(
file: $root . '/config.' . $host . '.php',
file: $path,
fallback: [],
allowOutput: false
);
}
// load the config for the server IP
if (empty($addr) === false) {
if (
empty($addr) === false &&
F::exists($path = $root . '/config.' . $addr . '.php', $root) === true
) {
$configAddr = F::load(
file: $root . '/config.' . $addr . '.php',
file: $path,
fallback: [],
allowOutput: false
);

View file

@ -287,15 +287,14 @@ class Header
*/
public static function download(array $params = []): void
{
$defaults = [
$options = [
'name' => 'download',
'size' => false,
'mime' => 'application/force-download',
'modified' => time()
'modified' => time(),
...$params
];
$options = array_merge($defaults, $params);
header('Pragma: public');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $options['modified']) . ' GMT');

View file

@ -4,6 +4,7 @@ namespace Kirby\Http;
use Kirby\Toolkit\Obj;
use Kirby\Toolkit\Str;
use Stringable;
/**
* A wrapper around a URL params
@ -16,7 +17,7 @@ use Kirby\Toolkit\Str;
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
*/
class Params extends Obj
class Params extends Obj implements Stringable
{
public static string|null $separator = null;
@ -48,7 +49,7 @@ class Params extends Obj
$slash = false;
if (is_string($path) === true) {
$slash = substr($path, -1, 1) === '/';
$slash = str_ends_with($path, '/') === true;
$path = Str::split($path, '/');
}
@ -57,7 +58,7 @@ class Params extends Obj
$separator = static::separator();
foreach ($path as $index => $p) {
if (strpos($p, $separator) === false) {
if (str_contains($p, $separator) === false) {
continue;
}
@ -137,7 +138,7 @@ class Params extends Obj
}
}
if (empty($params) === true) {
if ($params === []) {
return '';
}

View file

@ -14,6 +14,8 @@ use Kirby\Toolkit\Str;
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
*
* @extends \Kirby\Toolkit\Collection<string>
*/
class Path extends Collection
{
@ -35,7 +37,7 @@ class Path extends Collection
bool $leadingSlash = false,
bool $trailingSlash = false
): string {
if (empty($this->data) === true) {
if ($this->data === []) {
return '';
}

View file

@ -3,6 +3,7 @@
namespace Kirby\Http;
use Kirby\Toolkit\Obj;
use Stringable;
/**
* A wrapper around a URL query string
@ -15,7 +16,7 @@ use Kirby\Toolkit\Obj;
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
*/
class Query extends Obj
class Query extends Obj implements Stringable
{
public function __construct(string|array|null $query)
{

View file

@ -68,11 +68,11 @@ class Remote
// update the defaults with App config if set;
// request the App instance lazily
if ($app = App::instance(null, true)) {
$defaults = array_merge($defaults, $app->option('remote', []));
$defaults = [...$defaults, ...$app->option('remote', [])];
}
// set all options
$this->options = array_merge($defaults, $options);
$this->options = [...$defaults, ...$options];
// add the url
$this->options['url'] = $url;
@ -95,11 +95,11 @@ class Remote
array $arguments = []
): static {
return new static(
url: $arguments[0],
options: array_merge(
['method' => strtoupper($method)],
$arguments[1] ?? []
)
url: $arguments[0],
options: [
'method' => strtoupper($method),
...$arguments[1] ?? []
]
);
}
@ -171,7 +171,9 @@ class Remote
$this->curlopt[CURLOPT_SSL_VERIFYPEER] = true;
$this->curlopt[CURLOPT_CAPATH] = $this->options['ca'];
} else {
throw new InvalidArgumentException('Invalid "ca" option for the Remote class');
throw new InvalidArgumentException(
message: 'Invalid "ca" option for the Remote class'
);
}
// add the progress
@ -267,13 +269,13 @@ class Remote
*/
public static function get(string $url, array $params = []): static
{
$defaults = [
$options = [
'method' => 'GET',
'data' => [],
...$params
];
$options = array_merge($defaults, $params);
$query = http_build_query($options['data']);
$query = http_build_query($options['data']);
if (empty($query) === false) {
$url = match (Url::hasQuery($url)) {

View file

@ -229,7 +229,7 @@ class Request
// the request method can be overwritten with a header
$methodOverride = strtoupper(Environment::getGlobally('HTTP_X_HTTP_METHOD_OVERRIDE', ''));
if (in_array($methodOverride, $methods) === true) {
if (in_array($methodOverride, $methods, true) === true) {
$method ??= $methodOverride;
}
@ -240,7 +240,7 @@ class Request
$method = strtoupper($method);
// sanitize the method
if (in_array($method, $methods) === false) {
if (in_array($method, $methods, true) === false) {
$method = 'GET';
}
@ -310,8 +310,8 @@ class Request
foreach (Environment::getGlobally() as $key => $value) {
if (
substr($key, 0, 5) !== 'HTTP_' &&
substr($key, 0, 14) !== 'REDIRECT_HTTP_'
str_starts_with($key, 'HTTP_') === false &&
str_starts_with($key, 'REDIRECT_HTTP_') === false
) {
continue;
}

View file

@ -3,6 +3,7 @@
namespace Kirby\Http\Request;
use SensitiveParameter;
use Stringable;
/**
* Base class for auth types
@ -13,7 +14,7 @@ use SensitiveParameter;
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
*/
abstract class Auth
abstract class Auth implements Stringable
{
/**
* @param string $data Raw authentication data after the first space in the `Authorization` header

View file

@ -2,6 +2,8 @@
namespace Kirby\Http\Request;
use Stringable;
/**
* The Body class parses the
* request body and provides a nice
@ -14,7 +16,7 @@ namespace Kirby\Http\Request;
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
*/
class Body
class Body implements Stringable
{
use Data;
@ -84,7 +86,7 @@ class Body
return $this->data = $json;
}
if (strstr($contents, '=') !== false) {
if (str_contains($contents, '=') === true) {
// try to parse the body as query string
parse_str($contents, $parsed);

View file

@ -2,6 +2,8 @@
namespace Kirby\Http\Request;
use Stringable;
/**
* The Query class helps to
* parse and inspect URL queries
@ -13,7 +15,7 @@ namespace Kirby\Http\Request;
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
*/
class Query
class Query implements Stringable
{
use Data;

View file

@ -6,6 +6,7 @@ use Closure;
use Exception;
use Kirby\Exception\LogicException;
use Kirby\Filesystem\F;
use Stringable;
/**
* Representation of an Http response,
@ -18,7 +19,7 @@ use Kirby\Filesystem\F;
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
*/
class Response
class Response implements Stringable
{
/**
* Store for all registered headers,
@ -74,7 +75,7 @@ class Response
$this->charset = $charset ?? 'UTF-8';
// automatic mime type detection
if (strpos($this->type, '/') === false) {
if (str_contains($this->type, '/') === false) {
$this->type = F::extensionToMime($this->type) ?? 'text/html';
}
}
@ -134,7 +135,7 @@ class Response
array $props = []
): static {
if (file_exists($file) === false) {
throw new Exception('The file could not be found');
throw new Exception(message: 'The file could not be found');
}
$filename ??= basename($file);
@ -167,10 +168,11 @@ class Response
*/
public static function file(string $file, array $props = []): static
{
$props = array_merge([
$props = [
'body' => F::read($file),
'type' => F::extensionToMime(F::extension($file))
], $props);
'type' => F::extensionToMime(F::extension($file)),
...$props
];
// if we couldn't serve a correct MIME type, force
// the browser to display the file as plain text to
@ -272,6 +274,23 @@ class Response
]);
}
/**
* Creates a refresh response, which will
* send the visitor to the given location
* after the specified number of seconds.
*
* @since 5.0.3
*/
public static function refresh(string $location = '/', int $code = 302, int $refresh = 0): static
{
return new static([
'code' => $code,
'headers' => [
'Refresh' => $refresh . '; url=' . Url::unIdn($location)
]
]);
}
/**
* Sends all registered headers and
* returns the response body

View file

@ -131,7 +131,7 @@ class Route
*/
public static function next(): void
{
throw new Exceptions\NextRouteException('next');
throw new Exceptions\NextRouteException(message: 'next');
}
/**
@ -177,7 +177,7 @@ class Route
// We only need to check routes with regular expression since all others
// would have been able to be matched by the search for literal matches
// we just did before we started searching.
if (strpos($pattern, '(') === false) {
if (str_contains($pattern, '(') === false) {
return false;
}

View file

@ -63,7 +63,9 @@ class Router
foreach ($routes as $props) {
if (isset($props['pattern'], $props['action']) === false) {
throw new InvalidArgumentException('Invalid route parameters');
throw new InvalidArgumentException(
message: 'Invalid route parameters'
);
}
$patterns = A::wrap($props['pattern']);
@ -163,7 +165,10 @@ class Router
array|null $ignore = null
): Route {
if (isset($this->routes[$method]) === false) {
throw new InvalidArgumentException('Invalid routing method: ' . $method, 400);
throw new InvalidArgumentException(
message: 'Invalid routing method: ' . $method,
code: 400
);
}
// remove leading and trailing slashes
@ -175,14 +180,17 @@ class Router
if ($arguments !== false) {
if (
empty($ignore) === true ||
in_array($route, $ignore) === false
in_array($route, $ignore, true) === false
) {
return $this->route = $route;
}
}
}
throw new Exception('No route found for path: "' . $path . '" and request method: "' . $method . '"', 404);
throw new Exception(
code: 404,
message: 'No route found for path: "' . $path . '" and request method: "' . $method . '"',
);
}
/**

View file

@ -5,6 +5,7 @@ namespace Kirby\Http;
use Kirby\Cms\App;
use Kirby\Exception\InvalidArgumentException;
use SensitiveParameter;
use Stringable;
use Throwable;
/**
@ -16,7 +17,7 @@ use Throwable;
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
*/
class Uri
class Uri implements Stringable
{
/**
* Cache for the current Uri object
@ -100,8 +101,7 @@ class Uri
$props['username'] = $props['user'] ?? null;
$props['password'] = $props['pass'] ?? null;
$props = array_merge($props, $inject);
$props = [...$props, ...$inject];
}
// parse the path and extract params
@ -245,7 +245,7 @@ class Uri
if (
$this->port !== null &&
in_array($this->port, [80, 443]) === false
in_array($this->port, [80, 443], true) === false
) {
$domain .= ':' . $this->port;
}
@ -374,7 +374,9 @@ class Uri
if ($port !== null) {
if ($port < 1 || $port > 65535) {
throw new InvalidArgumentException('Invalid port format: ' . $port);
throw new InvalidArgumentException(
message: 'Invalid port format: ' . $port
);
}
}
@ -396,8 +398,13 @@ class Uri
*/
public function setScheme(string|null $scheme = null): static
{
if ($scheme !== null && in_array($scheme, static::$schemes) === false) {
throw new InvalidArgumentException('Invalid URL scheme: ' . $scheme);
if (
$scheme !== null &&
in_array($scheme, static::$schemes, true) === false
) {
throw new InvalidArgumentException(
message: 'Invalid URL scheme: ' . $scheme
);
}
$this->scheme = $scheme;
@ -465,7 +472,7 @@ class Uri
$path = $this->path->toString($slash) . $this->params->toString(true);
if ($this->slash && $slash === true) {
if ($this->slash && ($path !== '' || $slash === true)) {
$path .= '/';
}
@ -515,7 +522,7 @@ class Uri
// use the full path;
// automatically detect the trailing slash from it if possible
if (is_string($props['path']) === true) {
$props['slash'] = substr($props['path'], -1, 1) === '/';
$props['slash'] = str_ends_with($props['path'], '/') === true;
}
return $props;

View file

@ -116,7 +116,7 @@ class Url
return $home ?? static::home();
}
if (substr($path, 0, 1) === '#') {
if (str_starts_with($path, '#') === true) {
return $path;
}
@ -226,7 +226,10 @@ class Url
$path ??= '';
// keep relative urls
if (substr($path, 0, 2) === './' || substr($path, 0, 3) === '../') {
if (
str_starts_with($path, './') === true ||
str_starts_with($path, '../') === true
) {
return $path;
}

View file

@ -167,7 +167,7 @@ class Visitor
{
foreach ($this->acceptedMimeTypes() as $acceptedMime) {
// look for direct matches
if (in_array($acceptedMime->type(), $mimeTypes)) {
if (in_array($acceptedMime->type(), $mimeTypes, true)) {
return $acceptedMime->type();
}