JezK
Edit File: FileRule.php
<?php /** * Required rule class. * * @package Framework * @subpackage Validation * @since 1.0.0 */ namespace Kirki\Framework\Validation\Rules; \defined('ABSPATH') || exit; use finfo; use Kirki\Framework\Filesystem\File as FilesystemFile; use Kirki\Framework\Filesystem\MimeTypes; use Kirki\Framework\Supports\Arr; use Kirki\Framework\Validation\ValidationRule; use Kirki\Framework\Supports\Str; use InvalidArgumentException; /** * File rule class. * * @method $this size(string|int $size) * @method $this min(string|int $min) * @method $this max(string|int $max) * @method $this between(array $between) * @method $this image() * @method $this types(array $types) * @method $this extensions(array $extensions) */ class FileRule extends ValidationRule { /** * The rule name. * * @var string * * @since 1.0.0 */ protected string $rule = 'file'; /** * The constraints. * * @var array * * @since 1.0.0 */ protected array $constraints = ['size', 'min', 'max', 'between', 'image', 'types', 'extensions']; /** * The constructor. * * @param array|null $args The arguments. * * @return void * * @since 1.0.0 */ public function __construct($args = null) { parent::__construct($args); } /** * Validate the rule. * * @return bool * * @since 1.0.0 */ public function validate() : bool { $this->value = $this->make_file($this->value); if (!$this->value || !$this->value instanceof FilesystemFile || $this->value->getRealPath() === '') { return $this->fails($this->default_messages['default']); } return $this->validate_constraints(function ($passed, $constraint) { if (!$passed) { return $this->fails($this->default_messages[$constraint], $this->prepare_placeholder($constraint)); } }); } /** * Prepare the placeholder. * * @param string $constraint The constraint. * * @return array The placeholder. * * @since 1.0.0 */ protected function prepare_placeholder($constraint) { if (\in_array($constraint, ['min', 'max', 'size'])) { return [$constraint => $this->to_kilobytes($this->get($constraint))]; } if ($constraint === 'between') { return ['min' => $this->to_kilobytes($this->get('between')[0]), 'max' => $this->to_kilobytes($this->get('between')[1])]; } return [$constraint => $this->get($constraint)]; } /** * Validate the size constraint. * * @return bool * * @since 1.0.0 */ protected function validate_size() { $size = $this->to_kilobytes($this->get('size')); $filesize = $this->get_file_original_size($this->value); return $filesize === $size; } /** * Validate the min constraint. * * @return bool * * @since 1.0.0 */ protected function validate_min() { $min = $this->to_kilobytes($this->get('min')); $filesize = $this->get_file_original_size($this->value); return $filesize >= $min; } /** * Validate the max constraint. * * @return bool * * @since 1.0.0 */ protected function validate_max() { $max = $this->to_kilobytes($this->get('max')); $filesize = $this->get_file_original_size($this->value); return $filesize <= $max; } /** * Validate the between constraint. * * @return bool * * @since 1.0.0 */ protected function validate_between() { [$min, $max] = $this->get('between'); $min = $this->to_kilobytes($min); $max = $this->to_kilobytes($max); $filesize = $this->get_file_original_size($this->value); return $filesize >= $min && $filesize <= $max; } /** * Validate the image constraint. * * @return bool * * @since 1.0.0 */ protected function validate_image() { $mimetype = MimeTypes::make()->get_mimetype($this->value); $image_mimetypes = MimeTypes::make()->images_mimetypes; return \in_array($mimetype, $image_mimetypes, \true); } /** * Validate the types constraint. * * @return bool * * @since 1.0.0 */ protected function validate_types() { $types = $this->get('types'); $allowed_mimetypes = MimeTypes::make()->allowed_mimetypes($types); $mimetype = MimeTypes::make()->get_mimetype($this->value); return \in_array($mimetype, $allowed_mimetypes, \true); } /** * Validate the extensions constraint. * * @return bool * * @since 1.0.0 */ protected function validate_extensions() { $extensions = $this->get('extensions'); $allowed_extensions = MimeTypes::make()->allowed_extensions($extensions); $possible_extensions = MimeTypes::make()->guess_extensions($this->value); return \count(\array_values(\array_intersect($possible_extensions, $allowed_extensions))) > 0; } /** * Convert the file size to kilobytes. * * @param string|int $size The file size. * * @return int The file size in kilobytes. * * @since 1.0.0 */ protected function to_kilobytes($size) { if (!\is_string($size)) { return $size; } $size = \strtolower(\trim($size)); $value = (float) $size; switch (\true) { case Str::ends_with($size, 'kb'): return $value * 1; case Str::ends_with($size, 'mb'): return $value * 1024; case Str::ends_with($size, 'gb'): return $value * 1024 * 1024; case Str::ends_with($size, 'tb'): return $value * 1024 * 1024 * 1024; default: throw new InvalidArgumentException('Invalid file size: ' . $size); } } /** * Get the file original size. * * @param FilesystemFile $file The file. * * @return float The file original size. * * @since 1.0.0 */ protected function get_file_original_size(FilesystemFile $file) { return $file->getSize() / 1024; } /** * Get the file original mimetype. * * @param FilesystemFile $file The file. * * @return string The file original mimetype. * * @since 1.0.0 */ protected function get_file_original_mimetype(FilesystemFile $file) { $finfo = new finfo(\FILEINFO_MIME_TYPE); return \strtolower($finfo->file($file->getRealPath())); } /** * Get the file original extension. * * @param FilesystemFile $file The file. * * @return string The file original extension. * * @since 1.0.0 */ protected function get_file_original_extension(FilesystemFile $file) { return \strtolower($file->getExtension()); } /** * Make the file. * * @param string|FilesystemFile $value The file value. * * @return FilesystemFile The file. * * @since 1.0.0 */ protected function make_file($value) { if ($value instanceof FilesystemFile) { return $value; } if (\is_string($value)) { return new FilesystemFile($value, \false); } throw new InvalidArgumentException('Invalid file value: ' . $value); } /** * Get the error message. * * @return string * * @since 1.0.0 */ public function messages() { return $this->process_messages($this->messages); } }