rasuvaeff/domain-monitor

Domain monitoring toolkit for HTTP, SSL, WHOIS, DNS, ports, security headers, robots.txt, and sitemaps.

Maintainers

Package info

github.com/rasuvaeff/domain-monitor

pkg:composer/rasuvaeff/domain-monitor

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-06-01 08:31 UTC

This package is auto-updated.

Last update: 2026-06-01 08:33:15 UTC


README

Latest Stable Version Total Downloads Build Static analysis Coverage Psalm level License

A modular domain monitoring toolkit for PHP 8.3+. Zero-framework, PSR-compatible, with small immutable DTOs and focused stateless services. Each checker does one thing — you compose them as needed.

Checks: HTTP probing · SSL certificates · WHOIS · DNS · TCP ports · security headers · robots.txt · sitemaps.

Does not include: scheduling, persistence, caching, async runners, or a "check all" orchestrator. The package provides the building blocks; your application provides the workflow.

Using an AI coding assistant? llms.txt contains a compact API reference.

Requirements

  • PHP 8.3+
  • ext-openssl, ext-simplexml
  • A PSR-18 client and PSR-17 request factory for HTTP-based checks
  • io-developer/php-whois (pulls ext-curl, ext-mbstring)
  • ext-intl is optional (IDN normalization only)
  • ext-sockets is optional (DNS resolution only)

Installation

composer require rasuvaeff/domain-monitor

For HTTP checks you'll also need a PSR-18/PSR-17 implementation:

composer require symfony/http-client nyholm/psr7

Quick start: a full domain check

use DateTimeImmutable;
use Iodev\Whois\Factory;
use Nyholm\Psr7\Factory\Psr17Factory;
use Rasuvaeff\DomainMonitor\{
    DnsService,
    DomainHealthReport,
    HttpContentCheckService,
    HttpProbeService,
    PortService,
    RobotsTxtService,
    SecurityHeadersService,
    SitemapService,
    SslCertificateService,
    WhoisService,
};
use Symfony\Component\HttpClient\Psr18Client;

$host = 'example.com';
$client = new Psr18Client();
$requestFactory = new Psr17Factory();

$report = new DomainHealthReport(
    host: $host,
    probe: (new HttpProbeService(httpClient: $client, requestFactory: $requestFactory))
        ->check(url: "https://{$host}"),
    ssl: (new SslCertificateService())->check(host: $host),
    whois: (new WhoisService(whois: Factory::get()->createWhois()))->check(host: $host),
    dns: (new DnsService())->check(host: $host),
    port: (new PortService())->check(host: $host, port: 443),
);

// Aggregate status: worst among checks (OK → WARNING → CRITICAL → UNKNOWN)
echo $report->getStatus()->value;

Services

HTTP probing

use Rasuvaeff\DomainMonitor\HttpProbeOptions;
use Rasuvaeff\DomainMonitor\HttpProbeService;

$probe = (new HttpProbeService(httpClient: $client, requestFactory: $requestFactory))
    ->check(
        url: 'https://example.com',
        options: new HttpProbeOptions(method: 'HEAD', timeoutSeconds: 10.0),
    );

// ProbeResult { status: 200, totalTime: 0.12 }
var_dump($probe->status, $probe->totalTime);

timeoutSeconds is best-effort only — PSR-18 has no standard timeout API. Clients like Symfony's honor it; clients like raw Guzzle may not.

SSL

use Rasuvaeff\DomainMonitor\SslCertificateService;

$cert = (new SslCertificateService())->check(
    host: 'example.com',
    expectedOrg: 'Example Inc.', // optional org filter
);

if ($cert !== null) {
    echo $cert->daysUntilExpiry();      // e.g. 45
    echo $cert->isExpiringWithin(days: 30); // false
    echo $cert->subjectCn;              // "example.com"
    echo $cert->issuer;                 // "Example CA"
}

Note: SSL check reads the peer certificate without trust chain verification — it's a monitoring tool, not a PKI validator.

WHOIS

use Iodev\Whois\Factory;
use Rasuvaeff\DomainMonitor\WhoisService;

$info = (new WhoisService(whois: Factory::get()->createWhois()))
    ->check(host: 'example.com');

// TldInfo { domain, ?registrar, ?expirationDate, states }
echo $info->daysUntilExpiry(); // null if expirationDate missing

Fallback: if www.example.com fails, the service retries with example.com automatically.

DNS

use Rasuvaeff\DomainMonitor\DnsService;

$records = (new DnsService())->check(host: 'example.com');

// DnsRecords { a: ['93.184.216.34'], mx: ['...'], ns: ['...'], ... }
var_dump($records->a, $records->mx);

Port check (TCP)

use Rasuvaeff\DomainMonitor\PortService;

$check = (new PortService())->check(host: 'example.com', port: 443, timeoutSeconds: 5.0);
// PortCheck { status: OK, connectTime: 0.04, error: null }

Security headers

use Rasuvaeff\DomainMonitor\SecurityHeadersService;

// Pass a PSR-7 ResponseInterface (from a prior HTTP probe)
$headers = (new SecurityHeadersService())->check(response: $response);
// SecurityHeadersCheck { hasHsts: true, hasContentSecurityPolicy: false, ... }

robots.txt

use Rasuvaeff\DomainMonitor\RobotsTxtService;

$robots = (new RobotsTxtService(httpClient: $client, requestFactory: $requestFactory))
    ->check(baseUrl: 'https://example.com');
// RobotsTxtCheck { exists: true, sitemaps: ['https://example.com/sitemap.xml'] }

Sitemap

use Rasuvaeff\DomainMonitor\SitemapService;

$sitemap = (new SitemapService(httpClient: $client, requestFactory: $requestFactory))
    ->check(sitemapUrl: 'https://example.com/sitemap.xml');
// SitemapCheck { exists: true, urlCount: 42 }

Content check

use Rasuvaeff\DomainMonitor\HttpContentCheckService;

$content = (new HttpContentCheckService(httpClient: $client, requestFactory: $requestFactory))
    ->check(
        url: 'https://example.com',
        expectedStatus: 200,
        requiredText: 'Example Domain',     // must be present
        forbiddenText: 'Internal Error',    // must NOT be present
    );
// HttpContentCheck { status: OK, requiredTextFound: true, forbiddenTextFound: false }

Build a report

use Rasuvaeff\DomainMonitor\{DomainHealthReport, CheckStatus};
use Rasuvaeff\DomainMonitor\ProbeResult;
use Rasuvaeff\DomainMonitor\SslCertificate;

$report = new DomainHealthReport(
    host: 'example.com',
    probe: new ProbeResult(status: 200, totalTime: 0.13),
    ssl: new SslCertificate(/* ... */),
    whois: $tldInfo,
    dns: $dnsRecords,
);
echo $report->getStatus()->value; // 'ok' | 'warning' | 'critical' | 'unknown'

Full API reference

Class What it does
HostNormalizer Normalize hosts/URLs (lowercase, strip scheme/port/path, optional IDN)
HttpProbeService PSR-18 GET/HEAD probe with measured time → ProbeResult
HttpProbeOptions Configure method, headers, timeout, user-agent for HTTP probes
ProbeResult DTO: status, totalTime
SslCertificateService Read remote SSL cert; optional org filter → SslCertificate
SslCertificate DTO: validFrom, validUntil, subjectCn, issuer + expiry helpers
WhoisService Load & map WHOIS vendor data → TldInfo
TldInfo DTO: domain, ?registrar, ?expirationDate, states
DnsService dns_get_record() wrapper → DnsRecords
DnsRecords DTO: a, aaaa, mx, ns, txt, cname
PortService TCP reachability via stream_socket_client()PortCheck
PortCheck DTO: status, host, port, connectTime, ?error
SecurityHeadersService Check HSTS/CSP/XFO/XCTO on a PSR-7 response → SecurityHeadersCheck
SecurityHeadersCheck DTO: flags for each header + present/missing lists
RobotsTxtService Fetch /robots.txt + extract Sitemap hints → RobotsTxtCheck
RobotsTxtCheck DTO: exists, httpStatus, sitemaps[]
SitemapService Fetch sitemap + count <url> entries → SitemapCheck
SitemapCheck DTO: exists, httpStatus, urlCount
HttpContentCheckService Status code + required/forbidden keyword check → HttpContentCheck
HttpContentCheck DTO: status, httpStatus, ?finalUrl, text flags
DomainHealthReport Composite DTO for all check results → CheckStatus
CheckStatus Enum: OK, WARNING, CRITICAL, UNKNOWN

Security

  • HTTP checks accept only http and https URLs.
  • Host inputs are normalized and validated before use.
  • SslCertificateService reads peer certificates in monitoring mode (verify_peer: false) — it does not validate the PKI trust chain.
  • The package does not make any network requests on its own: it relies on user-provided PSR-18 clients and WHOIS instances.

Examples

See examples/ for runnable scripts.

Script Shows Network?
http-probe.php HTTP probe + content check Yes
ssl-whois-dns.php SSL, WHOIS, and DNS Yes
port.php TCP port check with custom host/port Yes
security-headers.php Check security headers on a live URL Yes
robots.php Fetch /robots.txt and extract sitemaps Yes
sitemap.php Fetch sitemap and count URLs Yes
report.php Build a DomainHealthReport from DTOs No

Run examples:

php examples/port.php example.com 443
php examples/security-headers.php https://example.com

Development

No PHP/Composer on the host — run in Docker via the composer:2 image:

docker run --rm -v "$PWD":/app -w /app composer:2 composer install
docker run --rm -v "$PWD":/app -w /app composer:2 composer build

Or with Make:

make install
make build
make cs-fix
make test

Integration tests (marked @coversNothing) skip unless DOMAIN_MONITOR_NET=1 is set:

DOMAIN_MONITOR_NET=1 make test

License

BSD-3-Clause