xiaowang/kirby/src/Cms/FileBlueprint.php
2021-10-29 18:05:46 +02:00

181 lines
5.3 KiB
PHP

<?php
namespace Kirby\Cms;
use Kirby\Toolkit\F;
use Kirby\Toolkit\Str;
/**
* Extension of the basic blueprint class
* to handle all blueprints for files.
*
* @package Kirby Cms
* @author Bastian Allgeier <bastian@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier GmbH
* @license https://getkirby.com/license
*/
class FileBlueprint extends Blueprint
{
/**
* `true` if the default accepted
* types are being used
*
* @var bool
*/
protected $defaultTypes = false;
public function __construct(array $props)
{
parent::__construct($props);
// normalize all available page options
$this->props['options'] = $this->normalizeOptions(
$this->props['options'] ?? true,
// defaults
[
'changeName' => null,
'create' => null,
'delete' => null,
'read' => null,
'replace' => null,
'update' => null,
]
);
// normalize the accept settings
$this->props['accept'] = $this->normalizeAccept($this->props['accept'] ?? []);
}
/**
* @return array
*/
public function accept(): array
{
return $this->props['accept'];
}
/**
* Returns the list of all accepted MIME types for
* file upload or `*` if all MIME types are allowed
*
* @return string
*/
public function acceptMime(): string
{
// don't disclose the specific default types
if ($this->defaultTypes === true) {
return '*';
}
$accept = $this->accept();
$restrictions = [];
if (is_array($accept['mime']) === true) {
$restrictions[] = $accept['mime'];
} else {
// only fall back to the extension or type if
// no explicit MIME types were defined
// (allows to set custom MIME types for the frontend
// check but still restrict the extension and/or type)
if (is_array($accept['extension']) === true) {
// determine the main MIME type for each extension
$restrictions[] = array_map(['Kirby\Toolkit\Mime', 'fromExtension'], $accept['extension']);
}
if (is_array($accept['type']) === true) {
// determine the MIME types of each file type
$mimes = [];
foreach ($accept['type'] as $type) {
if ($extensions = F::typeToExtensions($type)) {
$mimes[] = array_map(['Kirby\Toolkit\Mime', 'fromExtension'], $extensions);
}
}
$restrictions[] = array_merge(...$mimes);
}
}
if ($restrictions !== []) {
if (count($restrictions) > 1) {
// only return the MIME types that are allowed by all restrictions
$mimes = array_intersect(...$restrictions);
} else {
$mimes = $restrictions[0];
}
// filter out empty MIME types and duplicates
return implode(', ', array_filter(array_unique($mimes)));
}
// no restrictions, accept everything
return '*';
}
/**
* @param mixed $accept
* @return array
*/
protected function normalizeAccept($accept = null): array
{
if (is_string($accept) === true) {
$accept = [
'mime' => $accept
];
} elseif ($accept === true) {
// explicitly no restrictions at all
$accept = [
'mime' => null
];
} elseif (empty($accept) === true) {
// no custom restrictions
$accept = [];
}
$accept = array_change_key_case($accept);
$defaults = [
'extension' => null,
'mime' => null,
'maxheight' => null,
'maxsize' => null,
'maxwidth' => null,
'minheight' => null,
'minsize' => null,
'minwidth' => null,
'orientation' => null,
'type' => null
];
// default type restriction if none are configured;
// this ensures that no unexpected files are uploaded
if (
array_key_exists('mime', $accept) === false &&
array_key_exists('extension', $accept) === false &&
array_key_exists('type', $accept) === false
) {
$defaults['type'] = ['image', 'document', 'archive', 'audio', 'video'];
$this->defaultTypes = true;
}
$accept = array_merge($defaults, $accept);
// normalize the MIME, extension and type from strings into arrays
if (is_string($accept['mime']) === true) {
$accept['mime'] = array_map(function ($mime) {
return $mime['value'];
}, Str::accepted($accept['mime']));
}
if (is_string($accept['extension']) === true) {
$accept['extension'] = array_map('trim', explode(',', $accept['extension']));
}
if (is_string($accept['type']) === true) {
$accept['type'] = array_map('trim', explode(',', $accept['type']));
}
return $accept;
}
}