url
Validates that a field is a well-formed URL, optionally restricted to a list of allowed protocols.
url | url:protocol,protocol,...Parameters
| Parameter | Type | Description |
|---|---|---|
$protocoloptional | string | Zero 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_urlwhen 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
<?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.
<?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.
<?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