Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Uri Laravel Package

vdb/uri

A Laravel/PHP package for building, parsing, and manipulating URIs with a fluent, immutable API. Compose paths and query strings, validate URL components, and work with clean URI value objects in your applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Install with Composer:

composer require vdb/uri

Open src/Uri.php first — it is the value object you will interact with 90% of the time. Then glance at the parser (UriParser or equivalent, depending on version) because it drives the static construction path. The README is thin; the class itself and the test suite are the real documentation for this package.

The first thing to get working is parsing a URL and reading back its RFC 3986 components:

use Vdb\Uri\Uri;

$uri = Uri::parse('https://[email protected]:8443/docs/page.html?sort=asc&page=2#top');

$uri->getScheme();    // "https"
$uri->getUserInfo();  // "alice"
$uri->getHost();      // "example.com"
$uri->getPort();      // 8443
$uri->getPath();      // "/docs/page.html"
$uri->getQuery();     // "sort=asc&page=2"
$uri->getFragment();  // "top"

(string) $uri;       // round-trips the original string

The method names mirror java.net.URI, not PSR-7, so getUserInfo() / getHost() / getPort() are the accessors you reach for — not getAuthority() alone. Verify the exact surface against the version you install (Uri, UriReference, UriParser are the common class names in this family).

Implementation Patterns

Wrap it, don’t scatter it. These classes are low-level. In application code, put them behind a small domain object (e.g. ExternalLink, CdnUrl, WebhookEndpoint) so you’re not passing Uri instances across layer boundaries and coupling your domain to a tiny, low-traffic dependency.

Resolving relative links against a base is the classic day-to-day use case — crawlers, sitemap builders, rewriting feeds:

$base = Uri::parse('https://example.com/blog/post-1/');
$abs  = $base->resolve('../archive/2023?page=2');
echo $abs; // https://example.com/blog/archive/2023?page=2

resolve() follows RFC 3986 §5, so it correctly handles .., empty references, and query-only references. If you’re scraping or mirroring a site, this is the single most valuable method in the package.

Normalization for dedup and cache keys. When you need to compare “are these the same URL?”, normalize first, then compare the string forms — not the individual components:

$key = (string) Uri::parse($raw)->normalize();
$cache->remember($key, fn () => $client->get((string) $raw));

This handles case folding of scheme/host, dot-segment removal, and default-port stripping. It is safer than ad-hoc strtolower / rtrim logic.

Building URLs from parts for endpoint configuration:

$endpoint = Uri::parse('https://api.example.com/')
    ->withPath('/v2/webhooks')
    ->withQuery(http_build_query(['token' => $t]));

If the version you install exposes with* immutables, prefer them over string concatenation — you avoid the double-slash and missing-? bugs that plague hand-built URLs.

Bridging to PSR-7 / Guzzle. There is no built-in PSR-7 conversion. Do it at the boundary:

$psr = new \GuzzleHttp\Psr7\Uri((string) $vdbUri);

Parse with vdb/uri when you need RFC-correct resolution/normalization; hand off to your HTTP client as a string or PSR-7 UriInterface.

Testing. Use it in unit tests to assert that generated links are structurally what you expect:

$this->assertSame('/v2/items', Uri::parse($link)->getPath());
$this->assertSame('', Uri::parse($link)->getQuery()); // empty, not null

Gotchas and Tips

  • Small, lightly maintained package. 11 stars, 0 dependents, no recent ecosystem. Treat it as vendored-level code: pin the version in composer.json, and cover the behaviors you rely on with your own tests before an upgrade. If you need a long-term bet, league/uri is the mainstream alternative with the same RFC 3986 heritage.
  • PSR-7 confusion. Developers will try getScheme(), getHost(), getPath() and then assume it behaves like UriInterface. It doesn’t implement PSR-7, and with* mutability, __toString() failure behavior, and empty-vs-null returns may differ. Read the source before mixing it into anything that expects PSR-7.
  • getQuery() and getFragment() return the raw component. RFC allows an empty query (?) and an empty fragment (#) that are distinct from “absent.” Don’t assume null — test for empty string explicitly if that distinction matters to you.
  • Percent-encoding is component-aware. Parsing will not decode %2F in a path segment, but you may still need rawurldecode() before storing values that originated as query parameters. Double-decoding is the common bug: decode once, at the edge, and keep Uri around only for structural operations.
  • Default ports. normalize() strips :80 / :443, but getPort() on the un-normalized object still reports what was written. If you compare ports directly you will get false negatives — compare normalized strings instead.
  • Trailing slashes are significant and unresolved. https://a.com/x and https://a.com/x/ are different URIs and normalize() won’t merge them. If your cache or routing treats them as equivalent, do that collapsing in your own layer.
  • Host casing and IDN. The RFC lowercases the host in normalization but does not perform IDNA/punycode conversion. If you accept international hostnames, run them through idn_to_ascii() before parsing, or your comparisons will silently mismatch.
  • Extension points are thin. There isn’t a plugin or driver layer. The extension path is subclassing Uri (if the constructor is protected and the parser is injectable in your version) or, more realistically, writing small decorators that consume the public getters. Assume no hooks and design around composition.
  • Debugging. When a parse fails or a resolve returns something surprising, (string) the intermediate pieces ($uri->getBaseUri(), then each component) rather than stepping through the parser — the string round-trip is the fastest signal for what the parser actually saw.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core