phrity/net-uri
Lightweight PSR-7 UriInterface and PSR-17 UriFactory implementation not tied to HTTP messaging. Supports any valid scheme plus helpful extras like query item helpers, component access, equals/string/json support, and immutable with* methods.
Installation:
composer require phrity/net-uri
Add to composer.json under require or require-dev based on use case.
Basic Usage:
use Phrity\Net\Uri;
$uri = new Uri('https://example.com/path?query=value');
echo $uri->getPath(); // Outputs: /path
First Use Case: Replace Laravel’s default URI handling in a custom HTTP client or middleware:
use Phrity\Net\Uri;
$requestUri = new Uri($request->getUri());
$modifiedUri = $requestUri->withQueryItem('debug', 'true');
REQUIRE_PORT, NORMALIZE_PATH, and IDN_ENCODE for common edge cases.Immutable URI Modifications:
Use with* methods for safe, functional-style updates:
$uri = (new Uri('http://example.com'))
->withScheme('https')
->withQueryItem('token', 'abc123');
Query Parameter Handling: Leverage helper methods for dynamic query updates:
$uri = new Uri('http://example.com?page=1');
$uri->withQueryItems(['page' => 2, 'sort' => 'desc']);
Path Normalization: Clean up paths with modifiers:
$uri = new Uri('http://example.com/a/./b/../c');
$normalized = $uri->withPath($uri->getPath(), Uri::NORMALIZE_PATH | Uri::ABSOLUTE_PATH);
Factory Integration:
Centralize URI creation via UriFactory:
$factory = new Phrity\Net\UriFactory();
$uri = $factory->createUri('https://example.com');
PSR-17 Compliance: Use the factory in Laravel’s HTTP clients (e.g., Guzzle) for consistency:
$client = new GuzzleHttp\Client([
'base_uri' => $factory->createUri('https://api.example.com'),
]);
API Request Construction: Dynamically build URIs with query parameters:
$baseUri = new Uri('https://api.example.com/v1');
$resourceUri = $baseUri
->withPath('/users')
->withQueryItem('limit', $request->input('limit'));
Middleware URI Manipulation: Modify request URIs in middleware:
public function handle($request, Closure $next) {
$uri = new Uri($request->getUri());
$uri = $uri->withQueryItem('locale', app()->getLocale());
$request = $request->withUri($uri);
return $next($request);
}
Route Generation: Generate canonical URIs for redirects or links:
$uri = new Uri('/products/{id}');
$canonical = $uri->withPath(str_replace('{id}', $product->id, $uri->getPath()));
Non-HTTP URIs:
Handle custom schemes (e.g., app://, mailto:):
$uri = new Uri('mailto:user@example.com?subject=Hello');
$uri->getScheme(); // Outputs: mailto
Laravel Service Provider: Bind the factory to the container for dependency injection:
$this->app->bind(
Psr\Http\Message\UriInterface::class,
fn() => (new Phrity\Net\UriFactory())->createUri('')
);
Replace Default URI Handling:
Override Laravel’s UrlGenerator or Request URI parsing where needed:
// In a custom Request class
public function getUri() {
return new Phrity\Net\Uri(parent::getUri());
}
Testing:
Use the package’s equals() method for URI assertions:
$this->assertTrue(
(new Uri('https://example.com'))->equals('https://example.com')
);
IDN Support: Encode/decode internationalized domains:
$uri = new Uri('https://ηßöø必Дあ.com');
$encoded = $uri->getHost(Uri::IDN_ENCODE);
Performance:
Cache UriFactory instances for repeated use:
$factory = new Phrity\Net\UriFactory(); // Reuse this instance
Port Omission:
Default ports (e.g., 80 for HTTP) are omitted unless REQUIRE_PORT is used:
$uri = new Uri('http://example.com:80');
$uri->getPort(); // Returns null (default port)
$uri->toString(Uri::REQUIRE_PORT); // Includes `:80`
Path Normalization:
NORMALIZE_PATH may behave unexpectedly with relative paths:
$uri = new Uri('http://example.com/./path/../');
$uri->getPath(Uri::NORMALIZE_PATH); // Returns '/' (root)
Query Parsing:
Query strings with special characters (e.g., &, =) may require URI_DECODE:
$uri = new Uri('http://example.com?key=value&key2=value2');
$uri->getQueryItem('key', Uri::URI_DECODE); // Decodes URL-encoded values
IDN Encoding:
IDN_ENCODE modifies the host permanently unless combined with withHost():
$uri = new Uri('https://ηßöø必Дあ.com');
$uri->getHost(Uri::IDN_ENCODE); // Encodes but doesn’t modify $uri
$uri->withHost($uri->getHost(), Uri::IDN_ENCODE); // Updates $uri
PHP 8.1+ Requirement: The package requires PHP 8.1+ (as of v2.2). Ensure your Laravel app meets this requirement.
Invalid URIs: The package may silently accept malformed URIs. Validate with:
if (!$uri->getScheme()) {
throw new InvalidArgumentException('Invalid URI scheme');
}
Modifier Conflicts:
Combine modifiers carefully (e.g., ABSOLUTE_PATH + NORMALIZE_PATH):
$uri->withPath('relative/path', Uri::ABSOLUTE_PATH | Uri::NORMALIZE_PATH);
Query Item Overrides:
Use withQueryItems() to replace all query parameters:
$uri->withQueryItems(['new' => 'value']); // Overrides all existing items
Laravel URL Helper:
Extend Laravel’s URL::to() with custom logic using this package:
URL::macro('custom', function ($path, $query = []) {
$uri = new Uri($path);
return $uri->withQueryItems($query)->__toString();
});
Immutable Chaining:
Chain with* methods for fluent URI construction:
$uri = (new Uri('http://example.com'))
->withPath('/api/v1')
->withQueryItem('format', 'json');
Component Manipulation:
Use getComponents() and withComponents() for bulk updates:
$components = $uri->getComponents();
$components['scheme'] = 'https';
$uri = $uri->withComponents($components);
Testing Edge Cases: Test with:
https://例子.测试).http://example.com:8080)./path/../to).Performance Optimization:
Avoid repeated URI parsing by reusing Uri instances:
$baseUri = new Uri('https://api.example.com');
// Reuse $baseUri across requests
Laravel Route Parameters: Parse route URIs with this package
How can I help you explore Laravel packages today?