Skip to content

Validation Rules

Laravel Hyper provides custom validation rules for validating base64-encoded files from file inputs. These rules integrate with Laravel's validation system and use the same error message format as Laravel's native file validation rules.

Overview

When users select files with <input type="file" data-bind="avatar">, Datastar encodes them as base64 strings and sends them to the server in this format:

json
{
    "avatar": [
        "/9j/4AAQSkZJRgABAQAAAQ..."  // Base64 string
    ]
}

Hyper's validation rules handle this format automatically, validating the decoded file content.

File Validation Rules

b64file

Validate that the signal contains a valid base64-encoded file.

php
'document' => 'required|b64file'

What it checks:

  • Value is valid base64 format
  • Can be successfully decoded

Usage:

php
signals()->validate([
    'resume' => 'required|b64file',
    'cover_letter' => 'nullable|b64file'
]);

Error message: Uses Laravel's standard validation.file message

b64image

Validate that the signal contains a valid base64-encoded image.

php
'avatar' => 'required|b64image'

What it checks:

  • Value is valid base64 format
  • Decoded content is a valid image (JPEG, PNG, GIF, WEBP, SVG, etc.)
  • Uses PHP's getimagesizefromstring() for validation

Usage:

php
signals()->validate([
    'profile_picture' => 'required|b64image',
    'banner' => 'nullable|b64image'
]);

Error message: Uses Laravel's standard validation.image message

Size Validation Rules

b64max

Validate maximum file size in kilobytes.

php
b64max:size

Parameters:

  • size - Maximum file size in KB

Usage:

php
signals()->validate([
    'avatar' => 'required|b64image|b64max:2048',  // Max 2MB
    'document' => 'required|b64file|b64max:5120'  // Max 5MB
]);

How size is calculated:

Base64 encoding increases file size by approximately 33%. Hyper decodes the base64 string and validates the original file size in KB.

Error message: Uses Laravel's standard validation.max.file message

b64min

Validate minimum file size in kilobytes.

php
b64min:size

Parameters:

  • size - Minimum file size in KB

Usage:

php
signals()->validate([
    'presentation' => 'required|b64file|b64min:100'  // At least 100KB
]);

Error message: Uses Laravel's standard validation.min.file message

b64size

Validate exact file size in kilobytes.

php
b64size:size

Parameters:

  • size - Exact file size in KB

Usage:

php
signals()->validate([
    'thumbnail' => 'required|b64image|b64size:50'  // Exactly 50KB
]);

Error message: Uses Laravel's standard validation.size.file message

Image Dimension Rules

b64dimensions

Validate image dimensions with flexible constraints.

php
b64dimensions:constraint1,constraint2,...

Available constraints:

  • min_width=value - Minimum width in pixels
  • max_width=value - Maximum width in pixels
  • width=value - Exact width in pixels
  • min_height=value - Minimum height in pixels
  • max_height=value - Maximum height in pixels
  • height=value - Exact height in pixels
  • ratio=width/height - Aspect ratio (e.g., 16/9, 3/2)

Usage:

Minimum dimensions:

php
signals()->validate([
    'avatar' => 'required|b64image|b64dimensions:min_width=100,min_height=100'
]);

Maximum dimensions:

php
signals()->validate([
    'banner' => 'required|b64image|b64dimensions:max_width=1920,max_height=1080'
]);

Exact dimensions:

php
signals()->validate([
    'thumbnail' => 'required|b64image|b64dimensions:width=150,height=150'
]);

Aspect ratio:

php
signals()->validate([
    'cover_photo' => 'required|b64image|b64dimensions:ratio=16/9'
]);

Combined constraints:

php
signals()->validate([
    'profile_picture' => [
        'required',
        'b64image',
        'b64dimensions:min_width=200,min_height=200,max_width=1000,max_height=1000,ratio=1/1'
    ]
]);

Error message: Uses Laravel's standard validation.dimensions message

MIME Type Validation

b64mimes

Validate file extensions based on MIME type.

php
b64mimes:extension1,extension2,...

Parameters:

  • Comma-separated list of allowed file extensions

Supported extensions:

Images: jpg, jpeg, png, gif, webp, svg Documents: pdf, txt, csv, json

Usage:

Images only:

php
signals()->validate([
    'avatar' => 'required|b64image|b64mimes:jpg,png,webp'
]);

Documents:

php
signals()->validate([
    'resume' => 'required|b64file|b64mimes:pdf,doc,docx'
]);

Mixed types:

php
signals()->validate([
    'attachment' => 'required|b64file|b64mimes:pdf,jpg,png,txt'
]);

How it works:

  1. Decodes base64 content
  2. Detects MIME type using PHP's finfo_buffer() (or getimagesizefromstring() for images)
  3. Maps MIME type to file extension
  4. Checks if extension is in allowed list

Error message: Uses Laravel's standard validation.mimes message

Combining Rules

All validation rules can be combined with standard Laravel validation rules:

Complete File Upload Validation

php
signals()->validate([
    'avatar' => [
        'required',
        'b64image',
        'b64max:2048',
        'b64dimensions:min_width=100,min_height=100,max_width=500,max_height=500',
        'b64mimes:jpg,png'
    ]
]);

Multiple File Fields

php
signals()->validate([
    'profile_picture' => 'required|b64image|b64max:2048|b64mimes:jpg,png',
    'resume' => 'required|b64file|b64max:5120|b64mimes:pdf,doc,docx',
    'cover_letter' => 'nullable|b64file|b64max:5120|b64mimes:pdf,doc,docx'
]);

With Standard Laravel Rules

php
signals()->validate([
    'name' => 'required|string|max:255',
    'email' => 'required|email|unique:users',
    'avatar' => 'nullable|b64image|b64max:2048|b64mimes:jpg,png',
    'bio' => 'nullable|string|max:1000'
]);

Custom Error Messages

Use Laravel's custom error message syntax:

php
signals()->validate(
    [
        'avatar' => 'required|b64image|b64max:2048|b64dimensions:min_width=100'
    ],
    [
        'avatar.required' => 'Please upload a profile picture.',
        'avatar.b64image' => 'The profile picture must be a valid image.',
        'avatar.b64max' => 'The profile picture must not exceed 2MB.',
        'avatar.b64dimensions' => 'The profile picture must be at least 100x100 pixels.'
    ]
);

Common Patterns

Avatar Upload

php
public function uploadAvatar()
{
    signals()->validate([
        'avatar' => [
            'required',
            'b64image',
            'b64max:2048',
            'b64dimensions:min_width=100,min_height=100,max_width=500,max_height=500,ratio=1/1',
            'b64mimes:jpg,png,webp'
        ]
    ]);

    $path = signals()->store('avatar', 'avatars', 'public');

    auth()->user()->update(['avatar' => $path]);

    return hyper()->signals([
        'avatarUrl' => Storage::url($path),
        'message' => 'Avatar updated successfully!'
    ]);
}

Document Upload

php
public function uploadDocuments()
{
    signals()->validate([
        'resume' => [
            'required',
            'b64file',
            'b64max:5120',
            'b64mimes:pdf,doc,docx'
        ],
        'cover_letter' => [
            'nullable',
            'b64file',
            'b64max:5120',
            'b64mimes:pdf,doc,docx'
        ]
    ]);

    $paths = signals()->storeMultiple([
        'resume' => 'resumes',
        'cover_letter' => 'cover-letters'
    ], 'public');

    Application::create([
        'user_id' => auth()->id(),
        'resume_path' => $paths['resume'],
        'cover_letter_path' => $paths['cover_letter'] ?? null
    ]);

    return hyper()->signals([
        'message' => 'Application submitted successfully!',
        'errors' => []
    ]);
}

Profile Picture with Fallback

php
public function updateProfile()
{
    $rules = [
        'name' => 'required|string|max:255',
        'bio' => 'nullable|string|max:1000'
    ];

    // Only validate avatar if it's being uploaded
    if (signals()->has('avatar') && !empty(signals('avatar'))) {
        $rules['avatar'] = 'b64image|b64max:2048|b64mimes:jpg,png';
    }

    $validated = signals()->validate($rules);

    $user = auth()->user();

    // Handle avatar upload
    if (isset($validated['avatar'])) {
        // Delete old avatar
        if ($user->avatar) {
            Storage::delete($user->avatar);
        }

        $validated['avatar'] = signals()->store('avatar', 'avatars', 'public');
    }

    $user->update($validated);

    return hyper()->signals([
        'message' => 'Profile updated!',
        'errors' => []
    ]);
}
php
public function uploadGallery()
{
    signals()->validate([
        'photos' => 'required|array|min:1|max:10',
        'photos.*' => [
            'b64image',
            'b64max:2048',
            'b64dimensions:min_width=800,min_height=600',
            'b64mimes:jpg,png,webp'
        ]
    ]);

    $photos = signals('photos');
    $paths = [];

    foreach ($photos as $index => $photo) {
        // Temporarily set the signal for individual storage
        $tempSignal = "temp_photo_{$index}";

        // Store each photo
        $paths[] = signals()->store($tempSignal, 'gallery', 'public');
    }

    Gallery::create([
        'user_id' => auth()->id(),
        'photos' => $paths
    ]);

    return hyper()->signals([
        'message' => count($paths) . ' photos uploaded!',
        'errors' => []
    ]);
}

Technical Details

Base64 Detection

The validation rules automatically detect and handle:

  1. Array format (from Datastar file binding):

    json
    {"avatar": ["/9j/4AAQSkZJRg..."]}
  2. Data URL format (with MIME prefix):

    json
    {"avatar": ["data:image/jpeg;base64,/9j/4AAQSkZJRg..."]}
  3. Plain base64 string:

    json
    {"avatar": "/9j/4AAQSkZJRg..."}

Performance Considerations

  • All validation happens in memory using PHP's native functions
  • No temporary files are created during validation
  • Image validation uses getimagesizefromstring() for efficiency
  • MIME detection uses finfo_buffer() for non-image files

Size Calculation

Base64 encoding increases file size by ~33%. The validation rules decode the base64 string to validate the actual file size:

php
// User uploads 1MB image
// Base64 encoded: ~1.33MB
// Validation checks: 1MB (decoded size)
'avatar' => 'b64max:1024'  // Validates against original 1MB

Error Messages

All Hyper validation rules use Laravel's standard validation error messages for consistency:

RuleMessage KeyExample Message
b64filevalidation.file"The avatar must be a file."
b64imagevalidation.image"The avatar must be an image."
b64maxvalidation.max.file"The avatar must not be greater than 2048 kilobytes."
b64minvalidation.min.file"The avatar must be at least 100 kilobytes."
b64sizevalidation.size.file"The avatar must be 50 kilobytes."
b64dimensionsvalidation.dimensions"The avatar has invalid image dimensions."
b64mimesvalidation.mimes"The avatar must be a file of type: jpg, png."