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

Network Utilities Laravel Package

yiisoft/network-utilities

Network utilities for PHP, including helpers for validating and normalizing IPv4/IPv6 addresses, checking private/reserved ranges, working with subnets, and converting IP addresses to and from binary form. Useful for access rules, logging, and network-aware validation.

Deep Wiki
Context7

Getting Started

composer require yiisoft/network-utilities

This is a small, dependency-light helper package — no service provider, no config file, no migrations, no events. Installation is the whole setup; there is nothing to register in the container unless you choose to wrap it yourself.

Where to look first: open vendor/yiisoft/network-utilities/src/ and read IpHelper end to end. It is a static utility class for IP validation and IP/CIDR range matching, which is 90% of what you will use day to day. The method names are stable but verify against the installed version before writing a lot of code around them.

First use case — allow/deny by subnet:

use Yiisoft\NetworkUtilities\IpHelper;

$clientIp = $request->getServerParams()['REMOTE_ADDR'] ?? '';

if (!IpHelper::isValid($clientIp)) {
    throw new BadRequestHttpException('Unparsable client IP');
}

if (IpHelper::inRange($clientIp, '10.0.0.0/8')) {
    // internal traffic
}

Typical first wins:

  • Reject malformed REMOTE_ADDR / X-Forwarded-For values before they reach your logic.
  • Gate admin routes or health/debug endpoints to loopback or RFC1918 ranges.
  • Normalize an IP once at the edge of your request pipeline, then pass it around as a trusted value.

Implementation Patterns

CIDR allow-list as configuration. Keep ranges in config/params, not in code, and reduce over them:

$allowed = $params['security.trustedCidrs']; // ['10.0.0.0/8', '2001:db8::/32']

$isAllowed = false;
foreach ($allowed as $cidr) {
    if (IpHelper::inRange($clientIp, $cidr)) {
        $isAllowed = true;
        break;
    }
}

Short-circuit on first match — range checks are cheap but lists are not always short.

PSR-15 middleware for IP gating. The package has no middleware of its own; write one thin middleware and inject the allow-list. This composes with Yii's middleware stack and stays testable:

final class TrustedNetworkMiddleware implements MiddlewareInterface
{
    public function __construct(private array $cidrs) {}

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $ip = $request->getServerParams()['REMOTE_ADDR'] ?? '';
        foreach ($this->cidrs as $cidr) {
            if (IpHelper::inRange($ip, $cidr)) {
                return $handler->handle($request);
            }
        }
        return new EmptyResponse(403);
    }
}

Real client IP behind a proxy. Do not trust X-Forwarded-For blindly. Check the immediate peer against your trusted proxy CIDRs, then take the leftmost forwarded address and validate it:

$peer = $request->getServerParams()['REMOTE_ADDR'];
if (!IpHelper::inRange($peer, '10.0.0.0/8')) {
    return $peer; // proxy header is untrusted, ignore it
}

$forwarded = trim(explode(',', $request->getHeaderLine('X-Forwarded-For'))[0] ?? '');
return IpHelper::isValid($forwarded) ? $forwarded : $peer;

Validator integration. Wrap the helper in a Yii Validator rule so form/DTO validation stays consistent with middleware logic. One rule for "valid IP", a second for "IP in one of these ranges". Keep the range list as a constructor argument so the rule is reusable.

Bulk / database-backed checks. For matching many addresses or storing them, convert once with inet_pton (or the package's binary conversion if exposed) and store as VARBINARY(16). Binary comparison is faster and avoids canonicalization mismatches between IPv4 dotted-quad and IPv6 compressed forms. For range queries, store a numeric start/end pair per CIDR and compare integers.

Normalize at the boundary. Parse and validate the IP once when it enters your application (request middleware, import job, webhook handler), then treat it as a validated string downstream. Do not sprinkle isValid() checks through every service — it encourages inconsistent handling of IPv4-mapped and compressed IPv6 forms.

Keep a seam. Static helpers cannot be mocked. If IP logic appears in domain code, put a tiny IpMatcherInterface in front of it and implement it with IpHelper. That keeps your unit tests free of network-shaped fixtures and lets you swap in a more feature-rich library later without touching call sites.

Gotchas and Tips

  • IPv4-mapped IPv6 does not behave like IPv4. ::ffff:192.0.2.1 will not match 192.0.2.0/24 in a naive comparison. Normalize (filter_var with FILTER_FLAG_IPV4, or explicit prefix stripping) before range checks if your stack can produce mapped addresses.
  • Validate before matching. inRange() on a malformed string will either return false or throw depending on version and input. Always gate with isValid() at the boundary and decide explicitly whether garbage input means "deny" (usually yes) or "skip check" (almost never).
  • CIDR host bits are your problem. 10.0.0.5/8 is not the canonical form of the network. Build ranges from proper network addresses (10.0.0.0/8) rather than user input, or normalize the mask yourself. This is the most common source of "the rule works for some IPs" bugs.
  • IPv6 text forms are not comparable as strings. Compressed (2001:db8::1), expanded, and mixed-case forms are all the same address. Compare binary representations, not strings, and lowercase before logging or storing.
  • Zone IDs and brackets are rejected by design. fe80::1%eth0 and [2001:db8::1] are not plain addresses. Strip brackets from URL-derived values and drop zone IDs before validation; treat a failure here as malformed input, not a package bug.
  • Leading-zero IPv4 octets are ambiguous. 010.0.0.1 may be parsed as decimal or rejected depending on path. If you ingest user-supplied IPs, canonicalize with inet_pton/inet_ntop rather than trusting the raw string.
  • This package does no I/O. It does not resolve DNS, open sockets, or look up geolocation. If you need gethostbyname, reverse DNS, or ASN data, that is a separate, blocking concern — do not assume it lives here.
  • No config quirks, only version quirks. There is no config file to misconfigure. Pin the version in composer.json and re-run your IP fixtures after upgrades; small parse/validation changes in a utility package are silent until an edge-case address appears in production.
  • Debugging tip: when a range check "should" pass, dump inet_pton($ip) and inet_pton($cidrNetwork) as hex side by side. Nine times out of ten the mismatch is a mapped address, a non-canonical CIDR, or an IPv6 form you did not expect.
  • Extension point: there is no plugin system. Compose, do not subclass. A small value object (IpAddress) plus an IpMatcher wrapper around IpHelper gives you validation, normalization, and mockability in about 40 lines and is the cleanest way to keep this dependency at the edges of your codebase.
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.
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment