sabre/uri
Lightweight PHP URI utility library compliant with RFC3986. Provides resolve, normalize, parse/build, and split helpers for working with URLs, including Windows-style path edge cases. Fully unit tested and inspired by Node.js URL handling.
Installation:
composer require sabre/uri
For PHP 8.2+ projects, this will auto-select 3.1.0 (latest stable). For older PHP, use 2.3.4 or 3.0.3.
First Use Case: Resolve a relative URL against a base:
use Sabre\Uri\Uri;
$base = Uri::resolve('https://example.com/base/', './relative/path');
// Returns: 'https://example.com/base/relative/path'
Where to Look First:
tests/ directory for real-world examples (e.g., UriTest.php).URL Resolution in Laravel Controllers:
use Sabre\Uri\Uri;
public function redirectToDashboard(Request $request) {
$dashboardUrl = Uri::resolve(
route('dashboard'),
$request->input('redirect_to', '')
);
return redirect()->to($dashboardUrl);
}
Normalizing URIs for Comparison:
use Sabre\Uri\Uri;
$url1 = 'https://example.com/path?query=1';
$url2 = 'https://example.com/path?query=1#fragment';
$normalized1 = Uri::normalize($url1);
$normalized2 = Uri::normalize($url2, Uri::NORMALIZE_FRAGMENT);
if ($normalized1 === $normalized2) {
// Treat as equivalent (ignoring fragments)
}
RouteServiceProvider or API validation.Parsing Windows/Linux Paths:
use Sabre\Uri\Uri;
$windowsPath = 'file:///C:/Users/name/file.txt';
$parsed = Uri::parse($windowsPath);
// Returns: ['scheme' => 'file', 'host' => '', 'path' => '/C:/Users/name/file.txt']
filesystem_disks config).Splitting Paths for Laravel Views:
use Sabre\Uri\Uri;
$url = '/admin/users/123/edit';
[$dirname, $basename] = Uri::split($url);
// $dirname = '/admin/users/123'
// $basename = 'edit'
Laravel Service Providers: Bind the library as a singleton for dependency injection:
$this->app->singleton('uri', function () {
return new Sabre\Uri\Uri();
});
Then inject via constructor:
public function __construct(private Uri $uri) {}
Form Request Validation:
Use Uri::parse() to validate URL inputs:
public function rules() {
return [
'redirect_url' => [
'required',
function ($attribute, $value, $fail) {
try {
Uri::parse($value);
} catch (InvalidUriException $e) {
$fail('The :attribute must be a valid URL.');
}
},
],
];
}
API Resources:
Normalize URLs in toArray():
public function toArray($request) {
return [
'url' => Uri::normalize($this->resource->url),
];
}
Artisan Commands: Resolve paths for CLI tools:
$configPath = Uri::resolve(
base_path('config'),
$this->argument('module').'.php'
);
Windows Path Handling:
file:///C:/path may parse inconsistently across versions (see #81).Uri::parse() with Uri::PARSE_WINDOWS_PATHS flag for Windows-specific logic:
$parsed = Uri::parse('file:///C:/path', Uri::PARSE_WINDOWS_PATHS);
Triple Slash URIs:
///example.com (triple slash) may fail with PHP’s parse_url().Uri::parse('///example.com/path'); // Works
Empty Paths:
Uri::resolve('https://example.com', '') may return https://example.com/ (with trailing slash).Uri::normalize() to standardize:
Uri::normalize('https://example.com', Uri::NORMALIZE_PATH);
Unicode Characters:
parse_url().Fragment Handling:
Uri::normalize() may drop fragments by default.Uri::normalize($url, Uri::NORMALIZE_FRAGMENT);
Validate URIs Early: Wrap parsing in a try-catch:
try {
$parsed = Uri::parse($userInput);
} catch (InvalidUriException $e) {
report($e); // Log for monitoring
throw new \InvalidArgumentException('Invalid URL');
}
Compare with RFC Examples: Test against RFC3986 Appendix B edge cases:
// Example from RFC: "http://a/b/c/%7Bfoo%7D"
$parsed = Uri::parse('http://a/b/c/%7Bfoo%7D');
Use build() for Round-Trips:
Verify parsing/building consistency:
$original = 'https://example.com:8080/path?query=1#frag';
$parsed = Uri::parse($original);
$rebuilt = Uri::build($parsed);
assert($original === $rebuilt);
Custom URI Schemes:
Extend Sabre\Uri\Uri for non-standard schemes (e.g., s3://):
class CustomUri extends Uri {
public static function parse($uri, $flags = 0) {
if (str_starts_with($uri, 's3://')) {
return self::parseS3Uri($uri);
}
return parent::parse($uri, $flags);
}
}
Laravel Facade: Create a facade for cleaner syntax:
// app/Facades/Uri.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class Uri extends Facade {
protected static function getFacadeAccessor() {
return 'uri';
}
}
Then use:
Uri::resolve('base', 'relative');
Rector Rules:
Automate migrations from parse_url():
// rector.php
use Rector\Core\Contract\RectorConfigInterface;
return static function (RectorConfigInterface $config) {
$config->ruleWithConfiguration(
SabreUriRector::class,
['sabre/uri' => '^3.0']
);
};
PHP 8.2+ Only:
3.1.0 drops support for PHP 8.0/8.1. Use 3.0.3 for older versions.
Windows Paths:
Behavior changed in 3.0.0 (see #82). Test if upgrading:
// Old behavior (pre-3.0.0)
Uri::parse('file:///C:/path'); // ['host' => '', 'path' => '/C:/path']
// New behavior (3.0.0+)
Uri::parse('file:///C:/path', Uri::PARSE_WINDOWS_PATHS);
Normalization Flags: Combine flags with bitwise OR:
How can I help you explore Laravel packages today?