url

Validates that a field is a well-formed URL, optionally restricted to a list of allowed protocols.

Signature
url  |  url:protocol,protocol,...

Parameters

ParameterTypeDescription
$protocoloptionalstringZero or more URL protocols that should be considered valid, comma separated — for example http,https or minecraft,steam. With none given, any scheme is accepted.

Errors

Nothing on its own — the failure becomes a message, and validate() on a failing validator throws Illuminate\Validation\ValidationException.

url checks that a field is a well-formed URL. On its own it accepts any scheme; pass the protocols you actually want as parameters — 'website' => 'url:http,https' — and everything else is rejected. The documentation's second example, 'game' => 'url:minecraft,steam', shows that the list is not limited to web schemes.

When to reach for it

  • A profile website, a webhook endpoint, an avatar or feed URL.
  • Any link that your application will later render as an anchor or follow with an HTTP client.
  • Alongside active_url when the host must also resolve in DNS.

What trips people up

The bare rule is a syntax check, not a safety check. Because it accepts any scheme, hostile values shaped like javascript://example.com/%0aalert(1) are structurally valid URLs and pass — and if you echo one into an href, you have shipped a cross-site scripting hole. Always name the protocols for anything user-supplied and rendered.

It is also purely structural: nothing is fetched, so a URL for a domain that does not exist still passes. Use active_url if the host must resolve. And a value the user typed as example.com, with no scheme at all, fails — normalise it in prepareForValidation() if you want to be forgiving about that.

Example

Example · php
<?php

use Illuminate\Support\Facades\Validator;

$validator = Validator::make([
    'website' => 'https://laravel.com/docs',
    'profile' => 'javascript://example.com/%0aalert(1)',
    'blog'    => 'example.com',
], [
    'website' => ['required', 'url:http,https'],
    'profile' => ['required', 'url:http,https'],
    'blog'    => ['required', 'url:http,https'],
]);

print_r($validator->errors()->toArray());

// Array
// (
//     [profile] => Array
//         (
//             [0] => The profile field must be a valid URL.
//         )
//     [blog] => Array
//         (
//             [0] => The blog field must be a valid URL.
//         )
// )

// Drop the :http,https and the javascript: value passes.

When to use it

  • Validate a profile website field and force it to http or https.
  • Check a webhook endpoint a customer registers, restricted to https only.
  • Accept a game server link with a custom scheme such as minecraft or steam.
  • Combine with active_url when the host also has to resolve in DNS.

Frequently asked questions

How do I restrict the url validation rule to https?

Pass the protocols as rule parameters: 'endpoint' => 'url:https', or 'url:http,https' to allow both. With no parameters the rule accepts any scheme.

Does the url rule check that the website actually exists?

No — it is a structural check only and never makes a request. Add active_url, which resolves the host through PHP's dns_get_record, if the domain must exist.

Why does "example.com" fail the url validation rule?

Because a URL requires a scheme, and a bare hostname has none. Normalise the value in prepareForValidation() by prefixing https:// when the input contains no ://, then validate the corrected value.

More examples

An https-only webhook endpoint

prepareForValidation() runs before the rules, so a customer typing hooks.example.com is upgraded rather than rejected. url:https then bars plaintext http, active_url adds a DNS check that the bare rule never performs, and max:2048 stops an oversized value reaching a varchar column.

Example · php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreWebhookRequest extends FormRequest
{
    protected function prepareForValidation(): void
    {
        // Be forgiving about a missing scheme before the rules run.
        if ($url = $this->input('endpoint')) {
            if (! str_contains($url, '://')) {
                $this->merge(['endpoint' => 'https://'.$url]);
            }
        }
    }

    public function rules(): array
    {
        return [
            'endpoint' => ['required', 'url:https', 'active_url', 'max:2048'],
        ];
    }

    public function messages(): array
    {
        return [
            'endpoint.url' => 'The endpoint must be an https:// URL.',
        ];
    }
}

What the protocol list changes

The third and fourth rows are the reason to always name protocols: both are structurally valid URLs and both satisfy the bare rule. The last row shows that a scheme is mandatory either way — a bare hostname is never a valid URL to this rule.

Example · php
<?php

use Illuminate\Support\Facades\Validator;

$values = [
    'https://laravel.com',
    'http://localhost:8000/path?q=1',
    'ftp://files.example.com',
    'javascript://example.com/%0aalert(1)',
    'example.com',
];

foreach ($values as $value) {
    $any = Validator::make(['u' => $value], ['u' => 'url'])->passes();
    $web = Validator::make(['u' => $value], ['u' => 'url:http,https'])->passes();

    echo str_pad($value, 38),
         'url: ', $any ? 'pass  ' : 'fail  ',
         'url:http,https: ', $web ? "pass\n" : "fail\n";
}

// https://laravel.com                   url: pass  url:http,https: pass
// http://localhost:8000/path?q=1        url: pass  url:http,https: pass
// ftp://files.example.com               url: pass  url:http,https: fail
// javascript://example.com/%0aalert(1)  url: pass  url:http,https: fail
// example.com                           url: fail  url:http,https: fail

Discussion

  • Be the first to comment on this lesson.