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

Php Whois Laravel Package

setechsolutions/php-whois

A PHP package for performing WHOIS lookups on domains, retrieving registration and ownership details from WHOIS servers. Useful for domain availability checks, expiry information, and DNS-related tooling in Laravel or plain PHP applications.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • The package is a self-contained domain-lookup library: RDAP first, WHOIS fallback, with a DomainInfo value object as the primary return type. It slots into the service layer of a Laravel app rather than dictating application structure — there is no persistence, queue, or event surface, which keeps it low-coupling.
  • Laravel integration is opt-in by auto-discovery only: a service provider and a Whois facade, plus a publishable config/whois.php driven by WHOIS_MODE and WHOIS_TIMEOUT. Critically, the package has no dependency on Laravel, so the same code path is usable in CLI tools, jobs, and non-Laravel services. That is a good fit for teams running mixed workloads.
  • The result contract has two distinct "empty" states that callers must distinguish: lookup() returns null when a domain is not registered, and individual accessors (createdAt(), expiresAt(), updatedAt()) return null when a registry does not publish that field. isAvailable() is the boolean counterpart to the first case. This is a cleaner model than 4.x, but it moves null handling into every call site.
  • The removal of the Iodev\Whois namespace and the dropped replace entry for io-developer/php-whois is the single most important architectural fact. 5.0 is a greenfield API, not a drop-in successor. Any project that relied on the package as a transparent substitute must stay pinned to ^4.2 on the 4.x branch.

Integration feasibility

  • Very low friction for greenfield: composer require setechsolutions/php-whois, then Whois::lookup('example.com'). No setup, no manual provider registration.
  • Input validation happens before any network call (InvalidDomainException), which removes a class of defensive coding from calling code.
  • Exceptions are consolidated under WhoisException with meaningful subtypes (InvalidDomainException, UnsupportedTldException, ConnectionException, RateLimitException). This maps cleanly onto HTTP response codes and retry logic — a meaningful improvement over 4.x's ServerMismatchException and mixed failure semantics.
  • The stated support matrix (PHP 7.2.5–8.5, Laravel 6–13, tested on lowest and highest PHP per Laravel version) is unusually well-documented and backed by CI plus reproducible Docker harnesses (bin/docker-test, bin/test-laravel-app). That materially reduces the cost of validating compatibility ourselves.

Technical risk

  • Breaking upgrade risk is high, not moderate. Namespace change, method renames, property-to-accessor conversion, mode constant rename, exception rename, and the replace removal all land at once. There is no deprecation bridge or compatibility shim. A migration table is provided, but every call site and every test touching lookup data must change.
  • Null propagation is the sharpest ergonomic edge. The vendor's own README example, $info->expiresAt()->format('Y-m-d'), is unsafe on two counts: $info is null for unregistered domains, and expiresAt() is null when the registry omits the field. Both fail as a fatal error rather than a catchable WhoisException. Copy-pasted snippets will reach production.
  • Loss of caching is a real regression. MemcachedLoader is removed and the release explicitly tells consumers to cache DomainInfo::toArray() themselves. Every team upgrading inherits an obligation to design and operate a cache layer, or accept the full latency and rate-limit cost on every lookup. DomainInfo being JSON-serializable softens this — the cache payload is a plain array, no serialization design needed — but the policy layer is still ours.
  • Loss of ASN lookups may silently invalidate a feature for some consumers; this is a scope reduction, not a refactor.
  • Synchronous, blocking network I/O with a 30s default timeout. In a request path, a slow or unresponsive WHOIS server can consume a worker for up to 30 seconds. This is the dominant architectural hazard and is not addressed by the package.
  • Third-party protocol dependency. RDAP/WHOIS behavior varies per registry; server availability, schema quirks, and rate limits are outside our control. Rate limiting is now a first-class exception type, which is correct, but it also confirms rate limits are an expected steady-state condition rather than an edge case.
  • Custom server precedence is fixed, not configurable. WHOIS servers passed in the options array are now tried before the bundled servers for the same zone. There is no "fallback-only override" mode, so we cannot register a preferred server as a last resort — an override is always a priority override.
  • Support floor of PHP 7.2.5 is generous but irrelevant to us if we are modern; the practical constraint is that the package must be exercised on our exact PHP/Laravel pair, and CI coverage of the matrix is evidence, not a guarantee.
  • Date representation change (DateTimeImmutable/null instead of unix time/0/''). Any code doing truthiness, numeric comparison, or arithmetic on expiry will break — sometimes loudly (type error), sometimes silently (a null treated as falsy). This is the highest-risk mechanical translation.

Key questions

  1. Are we a new consumer (greenfield adopt) or an existing 4.x consumer? This determines whether this is a composer require or a multi-ticket migration with a defined freeze on the 4.x branch.
  2. Which modes do we need — rdap_first (default), whois_first, or a hard-pinned single-protocol mode for compliance or determinism reasons?
  3. Is any lookup on a user-facing request path? If yes, blocking 30s timeouts need async/queue offload or a much lower WHOIS_TIMEOUT.
  4. What is our cache strategy now that MemcachedLoader is gone — TTL policy, key scheme, negative caching for null/available results, and cache stampede protection?
  5. Do we consume ASN data today? If so, 5.0 cannot serve that need and we need a second source.
  6. What is our TLD coverage requirement, and do we need to supply custom rdap_servers / whois_servers for private or regional zones? Note that any server we supply takes precedence over the bundled one, so overrides cannot be used purely as a safety net.
  7. Do we want raw null returns from the wrapper, or a Result/Optional type that forces callers to handle unregistered domains and missing dates explicitly?
  8. Do we rely on io-developer/php-whois transitively elsewhere in the dependency graph? Dropping replace means Composer may now install both, with namespace collisions on the old side.
  9. How do we want RateLimitException handled — retry with backoff, degrade gracefully, or surface to the caller?

Integration Approach

Stack fit

  • Fits Laravel 6 through 13 with zero configuration via package auto-discovery. The facade alias Whois is globally available; the provider is discovered. config/whois.php is publishable when we need per-environment overrides.
  • Configuration surface is intentionally small: WHOIS_MODE and WHOIS_TIMEOUT via .env, with the richer options (follow_registrar, curl_options, rdap_servers, whois_servers) passed per-invocation as an array. This is the right split — environment-level defaults in config, request-level overrides in code.
  • Because the package has no Laravel dependency, the same Whois instance is usable from artisan commands, queued jobs, and scheduled tasks. We should standardise on one wrapper service in our own codebase so the facade is not scattered across the application.

Migration path

  • For 4.x consumers this is a rewrite of the integration layer, not an upgrade. The 4.x branch is the correct home for anything that needs the drop-in io-developer/php-whois replacement behavior; treat 5.0 as a separate adoption decision.
  • Mechanical translation is well-documented by the provided table: Factory::get()->createWhois() → new Whois(); loadDomainInfo() → lookup(); isDomainAvailable() → isAvailable(); lookupDomain()->text → raw()->text(); property access → accessor methods (domain(), registrar(), owner(), createdAt(), expiresAt(), updatedAt(), statuses(), nameServers()); setLookupMode(LookupMode::WHOIS_ONLY) → new Whois(['mode' => Mode::WHOIS_ONLY]); new CurlLoader() + replaceOptions() → new Whois(['curl_options' => [...]]); ServerMismatchException → UnsupportedTldException.
  • Three non-mechanical items require design decisions rather than find-and-replace: (a) the caching layer replacing MemcachedLoader, (b) the removal of ASN lookups, which needs either a replacement source or an explicit feature de-scope, and (c) null-handling policy for both lookup()'s null return and the nullable date accessors.
  • The date semantics change (unix/0/'' → DateTimeImmutable/null) is the highest-risk mechanical translation because it is the one most likely to fail quietly. Grep for comparisons, arithmetic, and truthiness checks on the old date fields before merging, and add tests on the expiry path.

Compatibility

  • PHP 7.2.5 through 8.5 and Laravel 6 through 13 are all declared and CI-tested at the lowest and highest PHP per Laravel version. Confirm our exact pin sits inside the tested matrix rather than between tested points.
  • No Laravel dependency means no version conflict with the framework, and no transitive constraint pressure on our laravel/framework pin — a meaningful advantage over packages that chase framework majors.
  • The replace entry for io-developer/php-whois is gone. Audit composer.lock for any transitive dependency on that package; if present, both will install and the old Iodev\ namespace will exist alongside the new one.
  • No ext-* requirements beyond what cURL implies are stated, but curl_options implies ext-curl is in play — verify the extension is present in every runtime image, including queue workers and CI.

Sequencing

  1. Decide adopt vs. stay. Classify the codebase as greenfield (adopt 5.0) or 4.x-dependent (pin ^4.2, plan separately). Do not attempt a partial upgrade.
  2. Spike in isolation. Use bin/docker-test / bin/test-laravel-app or our own harness to run lookup(), isAvailable(), and raw() against a representative TLD set on our exact PHP and Laravel pins before touching application code. Include at least one unregistered domain and one registry that omits a date field — these are the paths the examples do not cover.
  3. Stand up the cache layer first. TTLs, key naming, negative caching for null/unregistered results, and stampede protection should exist before the first production lookup, since 5.0 provides none.
  4. Introduce an application-level wrapper. A single DomainLookupService that owns the Whois instance, applies our options array, wraps exceptions into our domain errors, reads/writes the cache, and encapsulates the null contract (either a Result/Optional type or a documented null-safe accessor set). This confines the blast radius of the breaking API and makes any future major cheaper.
  5. Port call sites using the migration table, with dedicated attention to date-field consumers and to any code that previously relied on 4.x's 0/'' sentinels.
  6. Resolve the ASN gap — replacement provider or explicit de-scope sign-off.
  7. Configuration and environment rollout: publish config/whois.php, set WHOIS_MODE and WHOIS_TIMEOUT per environment, defaulting the timeout well below 30s on any request-adjacent path.
  8. Soak and cut over behind a feature flag, with the 4.x path retained until the new path has run clean through a full traffic cycle.

Operational Impact

Maintenance

  • Low surface area to own: one facade, one config file, one options array. The absence of a Laravel dependency means the package will not force framework upgrades or fight our laravel/framework constraint.
  • The 4.x and 5.x branches diverge permanently. If any part of the estate stays on 4.x, we own two integration patterns and two upgrade narratives indefinitely — a standing maintenance tax worth naming explicitly.
  • Self-managed caching shifts an operational responsibility onto us. That cache is now our code, our TTLs, our invalidation bugs. Budget for it as first-class, not incidental.
  • Registry data is inherently unstable, so the package will need periodic updates as RDAP endpoints and WHOIS formats drift. Pin to a reviewed version and track releases rather than floating.

Support

  • Exception hierarchy is clear and actionable, which shortens triage: InvalidDomainException is a caller bug (and is raised pre-network, so it is cheap), UnsupportedTldException is a coverage gap, ConnectionException is infrastructure/protocol, RateLimitException is throttling. Each maps to a distinct runbook entry.
  • RateLimitException being protocol-agnostic is the most operationally valuable change in this release: it converts a previously ambiguous failure into a signal we can alert and retry on.
  • raw() provides an escape hatch for inspecting the underlying registry response when structured parsing yields surprises — valuable for support cases and worth documenting for the on-call rotation.
  • Nulls are not exceptions. A null domain, a null expiry, or a missing name server are all normal returns and will not appear in error tracking; they will appear as wrong business outcomes. Support runbooks must cover "correct response, unexpected null" as a distinct class from "lookup failed".
  • Documented, reproducible test harnesses (bin/docker-test, bin/test-laravel-app) reduce the cost of verifying a suspected version-specific bug and make upstream issue reports far more credible.

Scaling

  • Lookups are synchronous outbound network calls bounded by WHOIS_TIMEOUT (default 30s). Throughput scales with worker count and outbound connection capacity, not with application CPU. Unbatched lookups on a hot path will saturate PHP-FPM workers before they saturate anything else.
  • Offload to queued jobs for anything bulk or non-interactive. Reserve synchronous calls for single, user-blocking lookups, and only with a materially reduced timeout plus a cache in front.
  • Caching is the primary scaling lever, and it is now entirely ours to build. Cache hit rate — not concurrency tuning — determines cost. Note that RDAP/WHOIS results change on the order of hours to days, so generous TTLs are usually safe, but short-TTL negative caching for unregistered domains deserves separate thought to avoid amplifying lookups on names that will never resolve.
  • follow_registrar can multiply the number of outbound requests per logical lookup. Enable it deliberately, and measure the amplification factor before turning it on at scale.
  • Rate limits are per-registry and shared across all our workers. Concurrency increases the chance of tripping RateLimitException regardless of our own capacity, so backoff and jitter are required, not optional.

Failure modes

  • Timeout exhaustion on request path — a slow registry holds a worker for up to 30s. Mitigation: low WHOIS_TIMEOUT, queue offload, circuit breaking.
  • Rate limiting under load — RateLimitException under concurrency. Mitigation: backoff with jitter, per-registry concurrency caps, aggressive caching.
  • Null dereference on the happy path — lookup() returning null for an unregistered domain, or a nullable expiresAt(), chained into a method call produces a fatal error rather than a handled exception. Mitigation: null-safe wrapper, static analysis at the strictest level our toolchain allows, and tests covering unregistered domains and date-less registries.
  • Silent date breakage — code assuming 4.x's unix timestamps or 0/'' now receives DateTimeImmutable or null, producing wrong expiry logic rather than an exception. Mitigation: explicit null handling, type-aware comparisons, and test coverage on expiry paths.
  • Unsupported TLD — UnsupportedTldException for zones with neither RDAP nor a bundled WHOIS server. Mitigation: enumerate our required TLDs up front, supply rdap_servers / whois_servers overrides where needed (accepting that they take precedence over bundled servers), and treat this as a known-gap class rather than an incident.
  • Duplicate namespace install — with replace dropped, a transitive io-developer/php-whois can coexist. Mitigation: lock-file audit in CI.
  • Cache-layer failure — since caching is now ours, a cache outage degrades directly into unbounded live lookups against registries, which then triggers rate limiting. Mitigation: cache-aside with a bounded fallback, and treat cache availability as a dependency of the lookup path.
  • Parsing drift — registry response format changes surface as missing fields (null) rather than errors. Mitigation: monitor field-population rates and alert on sudden shifts.

Ramp-up

  • Initial developer ramp is near-zero: the README example is genuinely a two-liner and the facade requires no setup. Most engineers will be productive within an hour — but they will write unsafe code unless the null contract is documented, because the headline example does not demonstrate it.
  • The real ramp is organisational, not technical — the team must internalise (a) the 4.x/5.x split and which branch a given service is on, (b) the mandatory cache discipline, (c) the exception-to-runbook mapping, (d) the null contract for unregistered domains and missing dates, and (e) the date type change from unix timestamps. Each of these is a short document plus a code review checklist, not a training programme.
  • On-call ramp requires a runbook covering RateLimitException backoff, ConnectionException triage, timeout tuning per environment, and how to use raw() to diagnose a parsing anomaly. Budget roughly a day of on-call documentation work.
  • Overall: adopt 5.0 for greenfield without hesitation; treat 4.x migration as a scoped project with explicit cache-build, null-handling, and ASN-resolution workstreams, not as a routine dependency bump.
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.
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
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle