Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,21 @@ Checks if the given value is a string.
Checks if the string value consists of all uppercase letters.
25. **`url`**<br/>
Checks if the value is a valid URL.
26. **`file`**<br/>
Checks if the field under validation is a valid file upload. Supports standard PHP `$_FILES` arrays and WordPress attachment IDs.<br/>
e.g. `['avatar' => ['required', 'file']]`
27. **`mimes:type1,type2,...`**<br/>
Checks if the file under validation has one of the allowed MIME types or extensions. Accepts comma-separated values (e.g., `jpg`, `png`, `pdf`).<br/>
e.g. `['document' => ['required', 'file', 'mimes:pdf,doc,docx']]`
28. **`max_file:size`**<br/>
Checks if the file size (in kilobytes) is less than or equal to the specified maximum size.<br/>
e.g. `['avatar' => ['required', 'file', 'max_file:2048']]` (2MB limit)
29. **`image`**<br/>
Checks if the file under validation is an image using WordPress allowed image MIME types.<br/>
e.g. `['photo' => ['required', 'file', 'image']]`
30. **`image_dimensions:width,height`**<br/>
Checks if the image dimensions (in pixels) are less than or equal to the specified maximum width and height.<br/>
e.g. `['avatar' => ['required', 'file', 'image', 'image_dimensions:1920,1080']]`

Missing any validation rule that you need? Refer to the [Custom Validation Rule](#custom-validation-rule) section to know how you can create and use custom validation rules in your project alongside the library.

Expand Down
10 changes: 10 additions & 0 deletions src/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ protected function getValueLength($value)

}

protected function getAttachmentSizeBytes(int $attachmentId, string $filePath)
{
$metadata = wp_get_attachment_metadata($attachmentId);
if ($metadata && isset($metadata['filesize'])) {
return (int) $metadata['filesize'];
}

return filesize($filePath);
}

public function setNestedElement(&$data, $keys, $value)
{
$current = &$data;
Expand Down
5 changes: 4 additions & 1 deletion src/Rule.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ public function getParamKeys()

public function setParameterValues($paramKeys, $paramValues): void
{
if (count($paramKeys) === count($paramValues)) {
if (count($paramKeys) === 1 && count($paramValues) > 1) {
// Single-key rules that accept comma-separated values (e.g. mimes:jpg,png,pdf)
$this->params = [$paramKeys[0] => implode(',', $paramValues)];
} elseif (count($paramKeys) === count($paramValues)) {
$this->params = array_combine($paramKeys, $paramValues);
}
}
Expand Down
21 changes: 16 additions & 5 deletions src/Rules/BetweenRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,28 @@ public function validate($value)
$this->checkRequiredParameter($this->requireParameters);

$min = (int) $this->getParameter('min');

$max = (int) $this->getParameter('max');

$length = $this->getValueLength($value);
if (is_array($value) && isset($value['size'])) {
$sizeKB = (int) $value['size'] / 1024;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The (int) cast here is applied only to $value['size'] before the division, which is redundant as the size is already an integer. If the intention was to truncate the result of the division to an integer (KB), parentheses are missing. However, using floats for range comparison is generally more accurate. Also, note the inconsistency with SizeRule which uses round().

            $sizeKB = $value['size'] / 1024;

return $sizeKB >= $min && $sizeKB <= $max;
}

if ($length) {
return $length >= $min && $length <= $max;
if (is_numeric($value) && function_exists('get_attached_file')) {
$attachmentId = (int) $value;
$filePath = get_attached_file($attachmentId);
if (! empty($filePath) && file_exists($filePath)) {
$sizeKB = $this->getAttachmentSizeBytes($attachmentId, $filePath) / 1024;
return $sizeKB >= $min && $sizeKB <= $max;
}
}

return false;
$length = $this->getValueLength($value);
if ($length === false) {
return false;
}

return $length >= $min && $length <= $max;
}

public function getParamKeys()
Expand Down
61 changes: 61 additions & 0 deletions src/Rules/EncodingRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
namespace BitApps\WPValidator\Rules;

use BitApps\WPValidator\Helpers;
use BitApps\WPValidator\Rule;

class EncodingRule extends Rule
{
use Helpers;

protected $message = "The :attribute must be encoded as one of: :encoding";

protected $requireParameters = ['encoding'];

public function validate($value)
{
$this->checkRequiredParameter($this->requireParameters);

if ($this->isEmpty($value)) {
return false;
}

$allowedEncodings = array_map('trim', explode(',', $this->getParameter('encoding')));

$filePath = $this->getFilePath($value);
if (! $filePath) {
return false;
}

$contents = file_get_contents($filePath);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Loading the entire file content into memory using file_get_contents() can lead to memory exhaustion (OOM) errors, especially with large file uploads. Since mb_detect_encoding only needs a representative sample of the text to detect the encoding, consider reading only the first few kilobytes of the file to improve performance and stability.

        $contents = file_get_contents($filePath, false, null, 0, 32768);

if ($contents === false) {
return false;
}

return mb_detect_encoding($contents, $allowedEncodings, true) !== false;
}

private function getFilePath($value)
{
if (is_numeric($value)) {
$filePath = get_attached_file((int) $value);
return (! empty($filePath) && file_exists($filePath)) ? $filePath : null;
}

if (is_array($value) && isset($value['tmp_name']) && is_uploaded_file($value['tmp_name'])) {
return $value['tmp_name'];
}

return null;
}

public function getParamKeys()
{
return $this->requireParameters;
}

public function message()
{
return $this->message;
}
}
61 changes: 61 additions & 0 deletions src/Rules/ExtensionsRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
namespace BitApps\WPValidator\Rules;

use BitApps\WPValidator\Helpers;
use BitApps\WPValidator\Rule;

class ExtensionsRule extends Rule
{
use Helpers;

protected $message = "The :attribute must have one of the following extensions: :extensions";

protected $requireParameters = ['extensions'];

public function validate($value)
{
$this->checkRequiredParameter($this->requireParameters);

if ($this->isEmpty($value)) {
return false;
}

$allowedExtensions = array_map(function ($e) {
return strtolower(trim($e));
}, explode(',', $this->getParameter('extensions')));

$fileName = $this->getFileName($value);
if (! $fileName) {
return false;
}

$wpFileType = wp_check_filetype($fileName);
$extension = strtolower($wpFileType['ext'] ?? '');

return ! empty($extension) && in_array($extension, $allowedExtensions, true);
}

private function getFileName($value)
{
if (is_numeric($value)) {
$filePath = get_attached_file((int) $value);
return (! empty($filePath) && file_exists($filePath)) ? basename($filePath) : null;
}

if (is_array($value) && isset($value['name'])) {
return $value['name'];
}

return null;
}

public function getParamKeys()
{
return $this->requireParameters;
}

public function message()
{
return $this->message;
}
}
49 changes: 49 additions & 0 deletions src/Rules/FileRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
namespace BitApps\WPValidator\Rules;

use BitApps\WPValidator\Helpers;
use BitApps\WPValidator\Rule;

class FileRule extends Rule
{
use Helpers;

protected $message = "The :attribute must be a valid file upload";

public function validate($value)
{
if ($this->isEmpty($value)) {
return false;
}

if (is_numeric($value)) {
$attachmentId = (int) $value;
$filePath = get_attached_file($attachmentId);
return ! empty($filePath) && file_exists($filePath);
}

if (is_array($value)) {
$requiredKeys = array_flip(['name', 'type', 'tmp_name', 'error', 'size']);
if (array_diff_key($requiredKeys, $value)) {
return false;
}

if ($value['error'] !== UPLOAD_ERR_OK) {
return false;
}

if (empty($value['tmp_name']) || ! is_uploaded_file($value['tmp_name'])) {
return false;
}

return true;
}

return false;
}

public function message()
{
return $this->message;
}
}
86 changes: 86 additions & 0 deletions src/Rules/ImageDimensionsRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php
namespace BitApps\WPValidator\Rules;

use BitApps\WPValidator\Helpers;
use BitApps\WPValidator\Rule;

class ImageDimensionsRule extends Rule
{
use Helpers;

protected $message = "The :attribute must not be larger than :width x :height pixels";

protected $requireParameters = ['width', 'height'];

public function validate($value)
{
$this->checkRequiredParameter($this->requireParameters);

if ($this->isEmpty($value)) {
return false;
}

$maxWidth = (int) $this->getParameter('width');
$maxHeight = (int) $this->getParameter('height');

$dimensions = $this->getImageDimensions($value);
if (! $dimensions) {
return false;
}

$width = $dimensions['width'];
$height = $dimensions['height'];

return $width <= $maxWidth && $height <= $maxHeight;
}

private function getImageDimensions($value)
{
$filePath = null;

if (is_numeric($value)) {
$attachmentId = (int) $value;
$filePath = get_attached_file($attachmentId);
if (empty($filePath) || ! file_exists($filePath)) {
return null;
}

$metadata = wp_get_attachment_metadata($attachmentId);
if ($metadata && isset($metadata['width']) && isset($metadata['height'])) {
return [
'width' => (int) $metadata['width'],
'height' => (int) $metadata['height'],
];
}
}

if (is_array($value) && isset($value['tmp_name'])) {
if (empty($value['tmp_name']) || ! is_uploaded_file($value['tmp_name'])) {
return null;
}
$filePath = $value['tmp_name'];
}

if ($filePath && file_exists($filePath)) {
$imageSize = @getimagesize($filePath);
if ($imageSize && isset($imageSize[0]) && isset($imageSize[1])) {
return [
'width' => (int) $imageSize[0],
'height' => (int) $imageSize[1],
];
}
}

return null;
}

public function getParamKeys()
{
return $this->requireParameters;
}

public function message()
{
return $this->message;
}
}
Loading