Update to Kirby 4.7.0
This commit is contained in:
parent
02a9ab387c
commit
ba25a9a198
509 changed files with 26604 additions and 14872 deletions
|
@ -27,18 +27,19 @@ class Asset
|
|||
/**
|
||||
* Relative file path
|
||||
*/
|
||||
protected string|null $path = null;
|
||||
protected string|null $path;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new Asset object for the given path.
|
||||
*/
|
||||
public function __construct(string $path)
|
||||
{
|
||||
$this->setProperties([
|
||||
'path' => dirname($path),
|
||||
'root' => $this->kirby()->root('index') . '/' . $path,
|
||||
'url' => $this->kirby()->url('base') . '/' . $path
|
||||
]);
|
||||
$this->root = $this->kirby()->root('index') . '/' . $path;
|
||||
$this->url = $this->kirby()->url('base') . '/' . $path;
|
||||
|
||||
$path = dirname($path);
|
||||
$this->path = $path === '.' ? '' : $path;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,7 +47,7 @@ class Asset
|
|||
*
|
||||
* @throws \Kirby\Exception\BadMethodCallException
|
||||
*/
|
||||
public function __call(string $method, array $arguments = [])
|
||||
public function __call(string $method, array $arguments = []): mixed
|
||||
{
|
||||
// public property access
|
||||
if (isset($this->$method) === true) {
|
||||
|
@ -114,15 +115,4 @@ class Asset
|
|||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the path
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function setPath(string $path): static
|
||||
{
|
||||
$this->path = $path === '.' ? '' : $path;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ class Dir
|
|||
string $dir,
|
||||
bool $recursive = false,
|
||||
array|false|null $ignore = [],
|
||||
string $path = null
|
||||
string|null $path = null
|
||||
): array {
|
||||
$result = [];
|
||||
$dir = realpath($dir);
|
||||
|
@ -169,7 +169,10 @@ class Dir
|
|||
$result[] = $entry;
|
||||
|
||||
if ($recursive === true && is_dir($root) === true) {
|
||||
$result = array_merge($result, static::index($root, true, $ignore, $entry));
|
||||
$result = [
|
||||
...$result,
|
||||
...static::index($root, true, $ignore, $entry)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,143 +220,145 @@ class Dir
|
|||
array|null $contentIgnore = null,
|
||||
bool $multilang = false
|
||||
): array {
|
||||
$dir = realpath($dir);
|
||||
|
||||
$inventory = [
|
||||
'children' => [],
|
||||
'files' => [],
|
||||
'template' => 'default',
|
||||
];
|
||||
|
||||
$dir = realpath($dir);
|
||||
|
||||
if ($dir === false) {
|
||||
return $inventory;
|
||||
}
|
||||
|
||||
$items = static::read($dir, $contentIgnore);
|
||||
|
||||
// a temporary store for all content files
|
||||
$content = [];
|
||||
|
||||
// sort all items naturally to avoid sorting issues later
|
||||
// read and sort all items naturally to avoid sorting issues later
|
||||
$items = static::read($dir, $contentIgnore);
|
||||
natsort($items);
|
||||
|
||||
// loop through all directory items and collect all relevant information
|
||||
foreach ($items as $item) {
|
||||
// ignore all items with a leading dot
|
||||
// ignore all items with a leading dot or underscore
|
||||
if (in_array(substr($item, 0, 1), ['.', '_']) === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$root = $dir . '/' . $item;
|
||||
|
||||
// collect all directories as children
|
||||
if (is_dir($root) === true) {
|
||||
// extract the slug and num of the directory
|
||||
if (preg_match('/^([0-9]+)' . static::$numSeparator . '(.*)$/', $item, $match)) {
|
||||
$num = (int)$match[1];
|
||||
$slug = $match[2];
|
||||
} else {
|
||||
$num = null;
|
||||
$slug = $item;
|
||||
}
|
||||
|
||||
$inventory['children'][] = [
|
||||
'dirname' => $item,
|
||||
'model' => null,
|
||||
'num' => $num,
|
||||
'root' => $root,
|
||||
'slug' => $slug,
|
||||
];
|
||||
} else {
|
||||
$extension = pathinfo($item, PATHINFO_EXTENSION);
|
||||
|
||||
switch ($extension) {
|
||||
case 'htm':
|
||||
case 'html':
|
||||
case 'php':
|
||||
// don't track those files
|
||||
break;
|
||||
case $contentExtension:
|
||||
$content[] = pathinfo($item, PATHINFO_FILENAME);
|
||||
break;
|
||||
default:
|
||||
$inventory['files'][$item] = [
|
||||
'filename' => $item,
|
||||
'extension' => $extension,
|
||||
'root' => $root,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove the language codes from all content filenames
|
||||
if ($multilang === true) {
|
||||
foreach ($content as $key => $filename) {
|
||||
$content[$key] = pathinfo($filename, PATHINFO_FILENAME);
|
||||
$inventory['children'][] = static::inventoryChild(
|
||||
$item,
|
||||
$root,
|
||||
$contentExtension,
|
||||
$multilang
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$content = array_unique($content);
|
||||
$extension = pathinfo($item, PATHINFO_EXTENSION);
|
||||
|
||||
// don't track files with these extensions
|
||||
if (in_array($extension, ['htm', 'html', 'php']) === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// collect all content files separately,
|
||||
// not as inventory entries
|
||||
if ($extension === $contentExtension) {
|
||||
$filename = pathinfo($item, PATHINFO_FILENAME);
|
||||
|
||||
// remove the language codes from all content filenames
|
||||
if ($multilang === true) {
|
||||
$filename = pathinfo($filename, PATHINFO_FILENAME);
|
||||
}
|
||||
|
||||
$content[] = $filename;
|
||||
continue;
|
||||
}
|
||||
|
||||
// collect all other files
|
||||
$inventory['files'][$item] = [
|
||||
'filename' => $item,
|
||||
'extension' => $extension,
|
||||
'root' => $root,
|
||||
];
|
||||
}
|
||||
|
||||
$inventory = static::inventoryContent($inventory, $content);
|
||||
$inventory = static::inventoryModels($inventory, $contentExtension, $multilang);
|
||||
$content = array_unique($content);
|
||||
|
||||
$inventory['template'] = static::inventoryTemplate(
|
||||
$content,
|
||||
$inventory['files']
|
||||
);
|
||||
|
||||
return $inventory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take all content files,
|
||||
* remove those who are meta files and
|
||||
* detect the main content file
|
||||
* Collect information for a child for the inventory
|
||||
*/
|
||||
protected static function inventoryContent(array $inventory, array $content): array
|
||||
{
|
||||
// filter meta files from the content file
|
||||
if (empty($content) === true) {
|
||||
$inventory['template'] = 'default';
|
||||
return $inventory;
|
||||
protected static function inventoryChild(
|
||||
string $item,
|
||||
string $root,
|
||||
string $contentExtension = 'txt',
|
||||
bool $multilang = false
|
||||
): array {
|
||||
// extract the slug and num of the directory
|
||||
if ($separator = strpos($item, static::$numSeparator)) {
|
||||
$num = (int)substr($item, 0, $separator);
|
||||
$slug = substr($item, $separator + 1);
|
||||
}
|
||||
|
||||
foreach ($content as $contentName) {
|
||||
// could be a meta file. i.e. cover.jpg
|
||||
if (isset($inventory['files'][$contentName]) === true) {
|
||||
// determine the model
|
||||
if (empty(Page::$models) === false) {
|
||||
if ($multilang === true) {
|
||||
$code = App::instance()->defaultLanguage()->code();
|
||||
$contentExtension = $code . '.' . $contentExtension;
|
||||
}
|
||||
|
||||
// look if a content file can be found
|
||||
// for any of the available models
|
||||
foreach (Page::$models as $modelName => $modelClass) {
|
||||
if (is_file($root . '/' . $modelName . '.' . $contentExtension) === true) {
|
||||
$model = $modelName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'dirname' => $item,
|
||||
'model' => $model ?? null,
|
||||
'num' => $num ?? null,
|
||||
'root' => $root,
|
||||
'slug' => $slug ?? $item,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the main template for the inventory
|
||||
* from all collected content files, ignore file meta files
|
||||
*/
|
||||
protected static function inventoryTemplate(
|
||||
array $content,
|
||||
array $files,
|
||||
): string {
|
||||
foreach ($content as $name) {
|
||||
// is a meta file corresponding to an actual file, i.e. cover.jpg
|
||||
if (isset($files[$name]) === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// it's most likely the template
|
||||
$inventory['template'] = $contentName;
|
||||
// (will overwrite and use the last match for historic reasons)
|
||||
$template = $name;
|
||||
}
|
||||
|
||||
return $inventory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Go through all inventory children
|
||||
* and inject a model for each
|
||||
*/
|
||||
protected static function inventoryModels(
|
||||
array $inventory,
|
||||
string $contentExtension,
|
||||
bool $multilang = false
|
||||
): array {
|
||||
// inject models
|
||||
if (
|
||||
empty($inventory['children']) === false &&
|
||||
empty(Page::$models) === false
|
||||
) {
|
||||
if ($multilang === true) {
|
||||
$contentExtension = App::instance()->defaultLanguage()->code() . '.' . $contentExtension;
|
||||
}
|
||||
|
||||
foreach ($inventory['children'] as $key => $child) {
|
||||
foreach (Page::$models as $modelName => $modelClass) {
|
||||
if (file_exists($child['root'] . '/' . $modelName . '.' . $contentExtension) === true) {
|
||||
$inventory['children'][$key]['model'] = $modelName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $inventory;
|
||||
return $template ?? 'default';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -402,10 +407,8 @@ class Dir
|
|||
|
||||
$parent = dirname($dir);
|
||||
|
||||
if ($recursive === true) {
|
||||
if (is_dir($parent) === false) {
|
||||
static::make($parent, true);
|
||||
}
|
||||
if ($recursive === true && is_dir($parent) === false) {
|
||||
static::make($parent, true);
|
||||
}
|
||||
|
||||
if (is_writable($parent) === false) {
|
||||
|
@ -426,19 +429,22 @@ class Dir
|
|||
* subfolders have been modified for the last time.
|
||||
*
|
||||
* @param string $dir The path of the directory
|
||||
* @param 'date'|'intl'|'strftime'|null $handler Custom date handler or `null`
|
||||
* for the globally configured one
|
||||
*/
|
||||
public static function modified(string $dir, string $format = null, string $handler = 'date'): int|string
|
||||
{
|
||||
public static function modified(
|
||||
string $dir,
|
||||
string|null $format = null,
|
||||
string|null $handler = null
|
||||
): int|string {
|
||||
$modified = filemtime($dir);
|
||||
$items = static::read($dir);
|
||||
|
||||
foreach ($items as $item) {
|
||||
if (is_file($dir . '/' . $item) === true) {
|
||||
$newModified = filemtime($dir . '/' . $item);
|
||||
} else {
|
||||
$newModified = static::modified($dir . '/' . $item);
|
||||
}
|
||||
|
||||
$newModified = match (is_file($dir . '/' . $item)) {
|
||||
true => filemtime($dir . '/' . $item),
|
||||
false => static::modified($dir . '/' . $item)
|
||||
};
|
||||
$modified = ($newModified > $modified) ? $newModified : $modified;
|
||||
}
|
||||
|
||||
|
@ -593,7 +599,10 @@ class Dir
|
|||
return true;
|
||||
}
|
||||
|
||||
if (is_dir($subdir) === true && static::wasModifiedAfter($subdir, $time) === true) {
|
||||
if (
|
||||
is_dir($subdir) === true &&
|
||||
static::wasModifiedAfter($subdir, $time) === true
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -475,12 +475,13 @@ class F
|
|||
/**
|
||||
* Get the file's last modification time.
|
||||
*
|
||||
* @param string $handler date, intl or strftime
|
||||
* @param 'date'|'intl'|'strftime'|null $handler Custom date handler or `null`
|
||||
* for the globally configured one
|
||||
*/
|
||||
public static function modified(
|
||||
string $file,
|
||||
string|IntlDateFormatter|null $format = null,
|
||||
string $handler = 'date'
|
||||
string|null $handler = null
|
||||
): string|int|false {
|
||||
if (file_exists($file) !== true) {
|
||||
return false;
|
||||
|
@ -579,7 +580,7 @@ class F
|
|||
}
|
||||
|
||||
// the math magic
|
||||
$size = round($size / pow(1024, ($unit = floor(log($size, 1024)))), 2);
|
||||
$size = round($size / 1024 ** ($unit = floor(log($size, 1024))), 2);
|
||||
|
||||
// format the number if requested
|
||||
if ($locale !== false) {
|
||||
|
@ -727,7 +728,8 @@ class F
|
|||
}
|
||||
|
||||
/**
|
||||
* Sanitize a filename to strip unwanted special characters
|
||||
* Sanitize a file's full name (filename and extension)
|
||||
* to strip unwanted special characters
|
||||
*
|
||||
* <code>
|
||||
*
|
||||
|
@ -740,12 +742,46 @@ class F
|
|||
*/
|
||||
public static function safeName(string $string): string
|
||||
{
|
||||
$name = static::name($string);
|
||||
$extension = static::extension($string);
|
||||
$safeName = Str::slug($name, '-', 'a-z0-9@._-');
|
||||
$safeExtension = empty($extension) === false ? '.' . Str::slug($extension) : '';
|
||||
$basename = static::safeBasename($string);
|
||||
$extension = static::safeExtension($string);
|
||||
|
||||
return $safeName . $safeExtension;
|
||||
if (empty($extension) === false) {
|
||||
$extension = '.' . $extension;
|
||||
}
|
||||
|
||||
return $basename . $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a file's name (without extension)
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public static function safeBasename(
|
||||
string $string,
|
||||
bool $extract = true
|
||||
): string {
|
||||
// extract only the name part from whole filename string
|
||||
if ($extract === true) {
|
||||
$string = static::name($string);
|
||||
}
|
||||
|
||||
return Str::slug($string, '-', 'a-z0-9@._-');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a file's extension
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public static function safeExtension(
|
||||
string $string,
|
||||
bool $extract = true
|
||||
): string {
|
||||
// extract only the extension part from whole filename string
|
||||
if ($extract === true) {
|
||||
$string = static::extension($string);
|
||||
}
|
||||
|
||||
return Str::slug($string);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -776,11 +812,11 @@ class F
|
|||
);
|
||||
}
|
||||
|
||||
try {
|
||||
return filesize($file);
|
||||
} catch (Throwable) {
|
||||
return 0;
|
||||
if ($size = @filesize($file)) {
|
||||
return $size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,7 +10,6 @@ use Kirby\Http\Response;
|
|||
use Kirby\Sane\Sane;
|
||||
use Kirby\Toolkit\Escape;
|
||||
use Kirby\Toolkit\Html;
|
||||
use Kirby\Toolkit\Properties;
|
||||
use Kirby\Toolkit\V;
|
||||
|
||||
/**
|
||||
|
@ -27,23 +26,21 @@ use Kirby\Toolkit\V;
|
|||
*/
|
||||
class File
|
||||
{
|
||||
use Properties;
|
||||
|
||||
/**
|
||||
* Parent file model
|
||||
* The model object must use the `\Kirby\Filesystem\IsFile` trait
|
||||
*/
|
||||
protected object|null $model = null;
|
||||
protected object|null $model;
|
||||
|
||||
/**
|
||||
* Absolute file path
|
||||
*/
|
||||
protected string|null $root = null;
|
||||
protected string|null $root;
|
||||
|
||||
/**
|
||||
* Absolute file URL
|
||||
*/
|
||||
protected string|null $url = null;
|
||||
protected string|null $url;
|
||||
|
||||
/**
|
||||
* Validation rules to be used for `::match()`
|
||||
|
@ -58,6 +55,8 @@ class File
|
|||
*
|
||||
* @param array|string|null $props Properties or deprecated `$root` string
|
||||
* @param string|null $url Deprecated argument, use `$props['url']` instead
|
||||
*
|
||||
* @throws \Kirby\Exception\InvalidArgumentException When the model does not use the `Kirby\Filesystem\IsFile` trait
|
||||
*/
|
||||
public function __construct(
|
||||
array|string|null $props = null,
|
||||
|
@ -65,7 +64,6 @@ class File
|
|||
) {
|
||||
// Legacy support for old constructor of
|
||||
// the `Kirby\Image\Image` class
|
||||
// @todo 4.0.0 remove
|
||||
if (is_array($props) === false) {
|
||||
$props = [
|
||||
'root' => $props,
|
||||
|
@ -73,11 +71,21 @@ class File
|
|||
];
|
||||
}
|
||||
|
||||
$this->setProperties($props);
|
||||
$this->root = $props['root'] ?? null;
|
||||
$this->url = $props['url'] ?? null;
|
||||
$this->model = $props['model'] ?? null;
|
||||
|
||||
if (
|
||||
$this->model !== null &&
|
||||
method_exists($this->model, 'hasIsFileTrait') !== true
|
||||
) {
|
||||
throw new InvalidArgumentException('The model object must use the "Kirby\Filesystem\IsFile" trait');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Improved `var_dump` output
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __debugInfo(): array
|
||||
{
|
||||
|
@ -269,6 +277,15 @@ class File
|
|||
if (is_array($rules['mime'] ?? null) === true) {
|
||||
$mime = $this->mime();
|
||||
|
||||
// the MIME type could not be determined, but matching
|
||||
// to it was requested explicitly
|
||||
if ($mime === null) {
|
||||
throw new Exception([
|
||||
'key' => 'file.mime.missing',
|
||||
'data' => ['filename' => $this->filename()]
|
||||
]);
|
||||
}
|
||||
|
||||
// determine if any pattern matches the MIME type;
|
||||
// once any pattern matches, `$carry` is `true` and the rest is skipped
|
||||
$matches = array_reduce(
|
||||
|
@ -343,19 +360,14 @@ class File
|
|||
/**
|
||||
* Returns the file's last modification time
|
||||
*
|
||||
* @param string|null $handler date, intl or strftime
|
||||
* @param 'date'|'intl'|'strftime'|null $handler Custom date handler or `null`
|
||||
* for the globally configured one
|
||||
*/
|
||||
public function modified(
|
||||
string|IntlDateFormatter|null $format = null,
|
||||
string|null $handler = null
|
||||
): string|int|false {
|
||||
$kirby = $this->kirby();
|
||||
|
||||
return F::modified(
|
||||
$this->root(),
|
||||
$format,
|
||||
$handler ?? $kirby?->option('date.handler', 'date') ?? 'date'
|
||||
);
|
||||
return F::modified($this->root(), $format, $handler);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -435,45 +447,6 @@ class File
|
|||
return $this->root ??= $this->model?->root();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the parent file model, which uses this instance as proxied file asset
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws \Kirby\Exception\InvalidArgumentException When the model does not use the `Kirby\Filesystem\IsFile` trait
|
||||
*/
|
||||
protected function setModel(object|null $model = null): static
|
||||
{
|
||||
if ($model !== null && method_exists($model, 'hasIsFileTrait') !== true) {
|
||||
throw new InvalidArgumentException('The model object must use the "Kirby\Filesystem\IsFile" trait');
|
||||
}
|
||||
|
||||
$this->model = $model;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the root
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function setRoot(string|null $root = null): static
|
||||
{
|
||||
$this->root = $root;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the file url
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function setUrl(string|null $url = null): static
|
||||
{
|
||||
$this->url = $url;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute url for the file
|
||||
*/
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Kirby\Filesystem;
|
||||
|
||||
use Kirby\Cms\Language;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
|
@ -28,44 +29,33 @@ use Kirby\Toolkit\Str;
|
|||
*/
|
||||
class Filename
|
||||
{
|
||||
/**
|
||||
* List of all applicable attributes
|
||||
*/
|
||||
protected array $attributes;
|
||||
|
||||
/**
|
||||
* The sanitized file extension
|
||||
*/
|
||||
protected string $extension;
|
||||
|
||||
/**
|
||||
* The source original filename
|
||||
*/
|
||||
protected string $filename;
|
||||
|
||||
/**
|
||||
* The sanitized file name
|
||||
*/
|
||||
protected string $name;
|
||||
|
||||
/**
|
||||
* The template for the final name
|
||||
*/
|
||||
protected string $template;
|
||||
|
||||
/**
|
||||
* Creates a new Filename object
|
||||
*
|
||||
* @param string $template for the final name
|
||||
* @param array $attributes List of all applicable attributes
|
||||
*/
|
||||
public function __construct(string $filename, string $template, array $attributes = [])
|
||||
{
|
||||
$this->filename = $filename;
|
||||
$this->template = $template;
|
||||
$this->attributes = $attributes;
|
||||
$this->extension = $this->sanitizeExtension(
|
||||
public function __construct(
|
||||
protected string $filename,
|
||||
protected string $template,
|
||||
protected array $attributes = [],
|
||||
protected string|null $language = null
|
||||
) {
|
||||
$this->name = $this->sanitizeName($filename);
|
||||
$this->extension = $this->sanitizeExtension(
|
||||
$attributes['format'] ??
|
||||
pathinfo($filename, PATHINFO_EXTENSION)
|
||||
);
|
||||
$this->name = $this->sanitizeName(pathinfo($filename, PATHINFO_FILENAME));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,6 +79,7 @@ class Filename
|
|||
'blur' => $this->blur(),
|
||||
'bw' => $this->grayscale(),
|
||||
'q' => $this->quality(),
|
||||
'sharpen' => $this->sharpen(),
|
||||
];
|
||||
|
||||
$array = array_filter(
|
||||
|
@ -227,24 +218,49 @@ class Filename
|
|||
|
||||
/**
|
||||
* Sanitizes the file extension.
|
||||
* The extension will be converted
|
||||
* to lowercase and `jpeg` will be
|
||||
* replaced with `jpg`
|
||||
* It also replaces `jpeg` with `jpg`.
|
||||
*/
|
||||
protected function sanitizeExtension(string $extension): string
|
||||
{
|
||||
$extension = strtolower($extension);
|
||||
$extension = F::safeExtension('test.' . $extension);
|
||||
$extension = str_replace('jpeg', 'jpg', $extension);
|
||||
return $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes the name with Kirby's
|
||||
* Str::slug function
|
||||
* Sanitizes the file name
|
||||
*/
|
||||
protected function sanitizeName(string $name): string
|
||||
{
|
||||
return Str::slug($name);
|
||||
// temporarily store language rules
|
||||
$rules = Str::$language;
|
||||
|
||||
// add rules for a particular language to `Str` class
|
||||
if ($this->language !== null) {
|
||||
Str::$language = [
|
||||
...Str::$language,
|
||||
...Language::loadRules($this->language)];
|
||||
}
|
||||
|
||||
// sanitize name
|
||||
$name = F::safeBasename($this->filename);
|
||||
|
||||
// restore language rules
|
||||
Str::$language = $rules;
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the sharpen option value
|
||||
*/
|
||||
public function sharpen(): int|false
|
||||
{
|
||||
return match ($this->attributes['sharpen'] ?? false) {
|
||||
false => false,
|
||||
true => 50,
|
||||
default => (int)$this->attributes['sharpen']
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,7 +5,6 @@ namespace Kirby\Filesystem;
|
|||
use Kirby\Cms\App;
|
||||
use Kirby\Exception\BadMethodCallException;
|
||||
use Kirby\Image\Image;
|
||||
use Kirby\Toolkit\Properties;
|
||||
|
||||
/**
|
||||
* Trait for all objects that represent an asset file.
|
||||
|
@ -22,8 +21,6 @@ use Kirby\Toolkit\Properties;
|
|||
*/
|
||||
trait IsFile
|
||||
{
|
||||
use Properties;
|
||||
|
||||
/**
|
||||
* File asset object
|
||||
*/
|
||||
|
@ -32,19 +29,20 @@ trait IsFile
|
|||
/**
|
||||
* Absolute file path
|
||||
*/
|
||||
protected string|null $root = null;
|
||||
protected string|null $root;
|
||||
|
||||
/**
|
||||
* Absolute file URL
|
||||
*/
|
||||
protected string|null $url = null;
|
||||
protected string|null $url;
|
||||
|
||||
/**
|
||||
* Constructor sets all file properties
|
||||
*/
|
||||
public function __construct(array $props)
|
||||
{
|
||||
$this->setProperties($props);
|
||||
$this->root = $props['root'] ?? null;
|
||||
$this->url = $props['url'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,7 +50,7 @@ trait IsFile
|
|||
*
|
||||
* @throws \Kirby\Exception\BadMethodCallException
|
||||
*/
|
||||
public function __call(string $method, array $arguments = [])
|
||||
public function __call(string $method, array $arguments = []): mixed
|
||||
{
|
||||
// public property access
|
||||
if (isset($this->$method) === true) {
|
||||
|
@ -136,28 +134,6 @@ trait IsFile
|
|||
return $this->root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the root
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function setRoot(string|null $root = null): static
|
||||
{
|
||||
$this->root = $root;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the file url
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function setUrl(string|null $url = null): static
|
||||
{
|
||||
$this->url = $url;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file type
|
||||
*/
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Kirby\Filesystem;
|
||||
|
||||
use Kirby\Toolkit\A;
|
||||
use Kirby\Toolkit\Str;
|
||||
use SimpleXMLElement;
|
||||
|
||||
|
@ -30,7 +31,7 @@ class Mime
|
|||
'aifc' => 'audio/x-aiff',
|
||||
'aiff' => 'audio/x-aiff',
|
||||
'avi' => 'video/x-msvideo',
|
||||
'avif' => 'image/avif',
|
||||
'avif' => 'image/avif',
|
||||
'bmp' => 'image/bmp',
|
||||
'css' => 'text/css',
|
||||
'csv' => ['text/csv', 'text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream'],
|
||||
|
@ -119,24 +120,22 @@ class Mime
|
|||
|
||||
/**
|
||||
* Fixes an invalid MIME type guess for the given file
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $mime
|
||||
* @param string $extension
|
||||
* @return string|null
|
||||
*/
|
||||
public static function fix(string $file, string $mime = null, string $extension = null)
|
||||
{
|
||||
public static function fix(
|
||||
string $file,
|
||||
string|null $mime = null,
|
||||
string|null $extension = null
|
||||
): string|null {
|
||||
// fixing map
|
||||
$map = [
|
||||
'text/html' => [
|
||||
'svg' => ['Kirby\Filesystem\Mime', 'fromSvg'],
|
||||
'svg' => [Mime::class, 'fromSvg'],
|
||||
],
|
||||
'text/plain' => [
|
||||
'css' => 'text/css',
|
||||
'json' => 'application/json',
|
||||
'mjs' => 'text/javascript',
|
||||
'svg' => ['Kirby\Filesystem\Mime', 'fromSvg'],
|
||||
'svg' => [Mime::class, 'fromSvg'],
|
||||
],
|
||||
'text/x-asm' => [
|
||||
'css' => 'text/css'
|
||||
|
@ -167,9 +166,6 @@ class Mime
|
|||
|
||||
/**
|
||||
* Guesses a MIME type by extension
|
||||
*
|
||||
* @param string $extension
|
||||
* @return string|null
|
||||
*/
|
||||
public static function fromExtension(string $extension): string|null
|
||||
{
|
||||
|
@ -179,11 +175,8 @@ class Mime
|
|||
|
||||
/**
|
||||
* Returns the MIME type of a file
|
||||
*
|
||||
* @param string $file
|
||||
* @return string|false
|
||||
*/
|
||||
public static function fromFileInfo(string $file)
|
||||
public static function fromFileInfo(string $file): string|false
|
||||
{
|
||||
if (function_exists('finfo_file') === true && file_exists($file) === true) {
|
||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||
|
@ -197,13 +190,13 @@ class Mime
|
|||
|
||||
/**
|
||||
* Returns the MIME type of a file
|
||||
*
|
||||
* @param string $file
|
||||
* @return string|false
|
||||
*/
|
||||
public static function fromMimeContentType(string $file)
|
||||
public static function fromMimeContentType(string $file): string|false
|
||||
{
|
||||
if (function_exists('mime_content_type') === true && file_exists($file) === true) {
|
||||
if (
|
||||
function_exists('mime_content_type') === true &&
|
||||
file_exists($file) === true
|
||||
) {
|
||||
return mime_content_type($file);
|
||||
}
|
||||
|
||||
|
@ -212,11 +205,8 @@ class Mime
|
|||
|
||||
/**
|
||||
* Tries to detect a valid SVG and returns the MIME type accordingly
|
||||
*
|
||||
* @param string $file
|
||||
* @return string|false
|
||||
*/
|
||||
public static function fromSvg(string $file)
|
||||
public static function fromSvg(string $file): string|false
|
||||
{
|
||||
if (file_exists($file) === true) {
|
||||
libxml_use_internal_errors(true);
|
||||
|
@ -234,10 +224,6 @@ class Mime
|
|||
/**
|
||||
* Tests if a given MIME type is matched by an `Accept` header
|
||||
* pattern; returns true if the MIME type is contained at all
|
||||
*
|
||||
* @param string $mime
|
||||
* @param string $pattern
|
||||
* @return bool
|
||||
*/
|
||||
public static function isAccepted(string $mime, string $pattern): bool
|
||||
{
|
||||
|
@ -256,10 +242,6 @@ class Mime
|
|||
* Tests if a MIME wildcard pattern from an `Accept` header
|
||||
* matches a given type
|
||||
* @since 3.3.0
|
||||
*
|
||||
* @param string $test
|
||||
* @param string $wildcard
|
||||
* @return bool
|
||||
*/
|
||||
public static function matches(string $test, string $wildcard): bool
|
||||
{
|
||||
|
@ -268,11 +250,8 @@ class Mime
|
|||
|
||||
/**
|
||||
* Returns the extension for a given MIME type
|
||||
*
|
||||
* @param string|null $mime
|
||||
* @return string|false
|
||||
*/
|
||||
public static function toExtension(string $mime = null)
|
||||
public static function toExtension(string|null $mime = null): string|false
|
||||
{
|
||||
foreach (static::$types as $key => $value) {
|
||||
if (is_array($value) === true && in_array($mime, $value) === true) {
|
||||
|
@ -289,22 +268,33 @@ class Mime
|
|||
|
||||
/**
|
||||
* Returns all available extensions for a given MIME type
|
||||
*
|
||||
* @param string|null $mime
|
||||
* @return array
|
||||
*/
|
||||
public static function toExtensions(string $mime = null): array
|
||||
public static function toExtensions(string|null $mime = null, bool $matchWildcards = false): array
|
||||
{
|
||||
$extensions = [];
|
||||
$testMime = fn (string $v) => static::matches($v, $mime);
|
||||
|
||||
foreach (static::$types as $key => $value) {
|
||||
if (is_array($value) === true && in_array($mime, $value) === true) {
|
||||
$extensions[] = $key;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($value === $mime) {
|
||||
$extensions[] = $key;
|
||||
if (is_array($value) === true) {
|
||||
if ($matchWildcards === true) {
|
||||
if (A::some($value, $testMime)) {
|
||||
$extensions[] = $key;
|
||||
}
|
||||
} else {
|
||||
if (in_array($mime, $value) === true) {
|
||||
$extensions[] = $key;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($matchWildcards === true) {
|
||||
if ($testMime($value) === true) {
|
||||
$extensions[] = $key;
|
||||
}
|
||||
} else {
|
||||
if ($value === $mime) {
|
||||
$extensions[] = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,8 +304,10 @@ class Mime
|
|||
/**
|
||||
* Returns the MIME type of a file
|
||||
*/
|
||||
public static function type(string $file, string|null $extension = null): string|null
|
||||
{
|
||||
public static function type(
|
||||
string $file,
|
||||
string|null $extension = null
|
||||
): string|null {
|
||||
// use the standard finfo extension
|
||||
$mime = static::fromFileInfo($file);
|
||||
|
||||
|
@ -338,8 +330,6 @@ class Mime
|
|||
|
||||
/**
|
||||
* Returns all detectable MIME types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function types(): array
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue