-
Notifications
You must be signed in to change notification settings - Fork 191
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature: add file validation rule (#6859)
* feautre: add file validation rule * refactor: refer to rule id using static id * feature: add allowedMimeType validation * refactor: rename to FileRequest and update descriptions * refactor: add maxUploadSize accessors and leave deprecated ones for ffm * refactor: change name to UploadedFile * feature: add extra validation for wp/server defined rules * chore: cleanup comments --------- Co-authored-by: Jon Waldstein <[email protected]>
- Loading branch information
1 parent
038c680
commit ba2eb5f
Showing
3 changed files
with
327 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
<?php | ||
|
||
namespace Give\Framework\Http\Types; | ||
|
||
/** | ||
* The represents the shape of a file from a POST request. | ||
* | ||
* @see https://www.php.net/manual/en/reserved.variables.files.php | ||
* | ||
* @unreleased | ||
*/ | ||
class UploadedFile | ||
{ | ||
/** | ||
* The original name of the file on the client machine. | ||
* | ||
* @var string | ||
*/ | ||
protected $name; | ||
/** | ||
* The mime type of the file, if the browser provided this information. An example would be "image/gif". This mime type is however not checked on the PHP side and therefore don't take its value for granted | ||
* | ||
* @var string | ||
*/ | ||
protected $browserMimeType; | ||
/** | ||
* The temporary filename of the file in which the uploaded file was stored on the server. | ||
* | ||
* @var string | ||
*/ | ||
protected $temporaryName; | ||
/** | ||
* The error code associated with this file upload. | ||
* | ||
* @see https://www.php.net/manual/en/features.file-upload.errors.php | ||
* @var int | ||
*/ | ||
protected $error; | ||
/** | ||
* The size, in bytes, of the uploaded file | ||
* | ||
* @var int | ||
*/ | ||
protected $size; | ||
|
||
/** | ||
* @unreleased | ||
*/ | ||
public static function fromArray(array $fileArray): UploadedFile | ||
{ | ||
$file = new self(); | ||
|
||
$file->name = (string)$fileArray['name']; | ||
$file->browserMimeType = (string)$fileArray['type']; | ||
$file->temporaryName = (string)$fileArray['tmp_name']; | ||
$file->error = (int)$fileArray['error']; | ||
$file->size = (int)$fileArray['size']; | ||
|
||
return $file; | ||
} | ||
|
||
/** | ||
* @unreleased | ||
*/ | ||
public function getName(): string | ||
{ | ||
return $this->name; | ||
} | ||
|
||
/** | ||
* @unreleased | ||
*/ | ||
public function getTemporaryName(): string | ||
{ | ||
return $this->temporaryName; | ||
} | ||
|
||
/** | ||
* @unreleased | ||
*/ | ||
public function getBrowserMimeType(): string | ||
{ | ||
return $this->browserMimeType; | ||
} | ||
|
||
/** | ||
* @unreleased | ||
* | ||
* @see https://www.php.net/manual/en/function.is-uploaded-file.php | ||
*/ | ||
public function isUploadedFile(): bool | ||
{ | ||
return is_uploaded_file($this->temporaryName); | ||
} | ||
|
||
/** | ||
* @unreleased | ||
* | ||
* @see https://www.php.net/manual/en/function.mime-content-type.php | ||
*/ | ||
public function getMimeType(): string | ||
{ | ||
return mime_content_type($this->temporaryName); | ||
} | ||
|
||
/** | ||
* @unreleased | ||
*/ | ||
public function getSize(): int | ||
{ | ||
return $this->size; | ||
} | ||
|
||
/** | ||
* @unreleased | ||
*/ | ||
public function getError(): int | ||
{ | ||
return $this->error; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace Give\Framework\ValidationRules\Rules; | ||
|
||
use Closure; | ||
use Give\Framework\Http\Types\UploadedFile; | ||
use Give\Vendors\StellarWP\Validation\Contracts\ValidationRule; | ||
|
||
/** | ||
* @unreleased | ||
*/ | ||
class File implements ValidationRule | ||
{ | ||
/** | ||
* The size, in bytes, of the uploaded file | ||
* | ||
* @var int | ||
*/ | ||
protected $maxSize; | ||
|
||
/** | ||
* @var string[] | ||
*/ | ||
protected $allowedMimeTypes; | ||
|
||
/** | ||
* @unreleased | ||
*/ | ||
public static function id(): string | ||
{ | ||
return 'file'; | ||
} | ||
|
||
/** | ||
* @unreleased | ||
*/ | ||
public function maxSize(int $maxSize): ValidationRule | ||
{ | ||
$this->maxSize = $maxSize; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @unreleased | ||
*/ | ||
public function getMaxSize(): int | ||
{ | ||
return $this->maxSize ?? wp_max_upload_size(); | ||
} | ||
|
||
/** | ||
* @unreleased | ||
*/ | ||
public function allowedMimeTypes(array $allowedMimeTypes): ValidationRule | ||
{ | ||
$this->allowedMimeTypes = $allowedMimeTypes; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @unreleased | ||
* | ||
* @return string[] | ||
*/ | ||
public function getAllowedMimeTypes(): array | ||
{ | ||
return $this->allowedMimeTypes ?? get_allowed_mime_types(); | ||
} | ||
|
||
/** | ||
* @unreleased | ||
**/ | ||
public function __invoke($value, Closure $fail, string $key, array $values) | ||
{ | ||
try { | ||
$file = UploadedFile::fromArray($value); | ||
|
||
if (!$file->isUploadedFile()) { | ||
$fail(sprintf(__('%s must be a valid file.', 'give'), '{field}')); | ||
} | ||
|
||
// check against both the allowed mime types defined by the file rule and the server | ||
if (!in_array($file->getMimeType(), $this->getAllowedMimeTypes(), true) || | ||
!in_array($file->getMimeType(), get_allowed_mime_types(), true)) { | ||
$fail(sprintf(__('%s must be a valid file type.', 'give'), '{field}')); | ||
} | ||
|
||
// check against both the max upload size defined by the file rule and the server | ||
if ($file->getSize() > $this->getMaxSize() || $file->getSize() > wp_max_upload_size()) { | ||
$fail( | ||
sprintf(__('%s must be less than or equal to %d bytes.', 'give'), '{field}', $this->getMaxSize()) | ||
); | ||
} | ||
|
||
if ($file->getError() !== UPLOAD_ERR_OK) { | ||
$fail(sprintf(__('%s must be a valid file.', 'give'), '{field}')); | ||
} | ||
} catch (\Throwable $e) { | ||
$fail($e->getMessage()); | ||
} | ||
} | ||
|
||
/** | ||
* @unreleased | ||
*/ | ||
public static function fromString(string $options = null): ValidationRule | ||
{ | ||
return new self(); | ||
} | ||
} |