vipnytt/sitemapparser
A lightweight PHP library for parsing XML sitemaps and sitemap indexes. It recursively follows sitemap index files, extracts URLs, handles gzip compression, detects sitemap types, and supports robots.txt discovery with no external dependencies.
Architecture fit. vipnytt/sitemapparser is a single-purpose, framework-agnostic PHP class that reads XML sitemaps and sitemap index files per the Sitemaps.org protocol, including gzip-compressed variants. It is a library, not a bundle: no service provider, no facade, no config file, no Laravel discovery entry. That is actually a reasonable fit for a Laravel codebase — it slots in as a domain utility behind a thin application-layer wrapper (e.g. App\Services\Sitemap\SitemapReader) rather than colonizing the framework. The parsing surface is narrow and well-bounded, which keeps the blast radius small if we later swap it out. The main architectural caveat is that the library performs network I/O itself when following sitemap index files; that means it must be driven from a queued job or console command, not from a request cycle, and its HTTP behavior is not built on Guzzle or the Laravel HTTP client, so it will not inherit our existing retry, timeout, proxy, or observability conventions. Budget for an adapter that owns that policy rather than letting the library own it.
Integration feasibility. High for the basic case, moderate for production-grade. Composer install and a PSR-4 autoload is a same-day integration for single-file sitemap parsing. The work is concentrated in the wrapper: constructing the reader with sane limits, wrapping the iterator in a Laravel LazyCollection so sitemap entries can be streamed into jobs without materializing a 50k-URL sitemap in memory, and normalizing the library's return shapes into a DTO we control. Recursive index traversal needs our own recursion depth cap and a visited-set to avoid cycles. None of this is exotic — roughly 1–3 engineer-days including tests for a first-class integration, plus test fixtures for gzip, malformed XML, and index-of-indexes cases.
Technical risk. The dominant risk is lifecycle, not technology: the repository is marked archived. That is a hard signal — no upstream security patching, no PHP-version compatibility work, no issue triage. MIT licensing means we can fork and vendor it, and the code surface is small enough that a fork is genuinely viable, but that is now a line item we own rather than a dependency we consume. Secondary risks:
Key questions.
robots.txt-based sitemap discovery? That is a separate concern and a separate library; scoping it out keeps this dependency single-purpose.Stack fit. Assume a standard Laravel 10/11/12 application on PHP 8.2+. The library targets older PHP idioms; it will install cleanly but should be validated against our PHP version and our strict error reporting (E_ALL, deprecations promoted to exceptions in CI). Fit with our conventions is otherwise neutral — we are not adopting a competing HTTP client, queue system, or ORM, so there is no framework-level conflict.
Migration path. There is nothing to migrate from; this is greenfield. The correct framing is "adopt behind an interface," so that a future replacement is a container binding change and not a refactor:
SitemapReader interface in the application layer returning a stream of SitemapEntry DTOs.VipnyttSitemapReader as the adapter, containing all library-specific types. No library class names appear outside this file.This costs a few hours and removes the archived-dependency risk from being a rewrite risk.
Compatibility. Verify against the pinned PHP version, and confirm behavior under ext-libxml and ext-zlib availability — gzip support depends on the latter. Confirm the parser does not require allow_url_fopen; if it does, that is both a config constraint and an SSRF amplifier, and we should prefer a fork that accepts an injected HTTP client or a pre-fetched document body. If the library only accepts a URL, prefer feeding it a locally staged copy fetched by our own HTTP client — this gives us timeouts, retries, redirect limits, and allowlisting for free, and neuters the SSRF concern at the source.
Sequencing.
Maintenance. This is the crux. An archived dependency does not generate maintenance work — it generates ownership. We must assume we are the maintainers: track CVEs in PHP/libxml ourselves, apply PHP-version fixes at each upgrade cycle, and carry the fork in our VCS with a documented patch log. The offsetting factor is that the total code is small and the protocol is stable and essentially frozen. Budget roughly 1–2 engineer-days per year of reactive maintenance, plus a review at each PHP major upgrade. Compare that against the cost of writing and owning ~300 lines of parser ourselves, which is the honest alternative and not obviously worse.
Support. No upstream support channel. Internally, the adapter interface is the support boundary — on-call engineers debug SitemapReader behavior, not the vendor class. Document the fork, the pinned commit, and the patch log in the repo. If this feeds a customer-visible surface, note in the runbook that "sitemap rejected as invalid" may be a parser strictness issue rather than a customer error, and give support a path to inspect the raw document.
Scaling. Parsing is CPU-light and I/O-bound. The scaling concerns are:
->toArray() a sitemap, and never JSON-serialize one into a job payload.Failure modes.
Ramp-up. Low. A mid-level Laravel engineer can be productive with the adapter in half a day; the Sitemaps.org protocol is a short read and the library's own API is a handful of methods. The non-obvious knowledge that must be written down: the fork's existence and why, the allowlist enforcement point, the staging-before-parsing pattern and its rationale, and the quarantine-vs-retry decision rule per failure class. Given the archived status, the ramp-up risk is less about learning the library and more about a future engineer discovering an unmaintained vendor directory with no note explaining the decision — the ADR is a deliverable, not documentation debt.
Recommendation. Proceed behind an interface, contingent on passing the SSRF/XXE review and on a documented fork decision. Keep a timeboxed parallel spike (a day) against a maintained alternative or an in-house parser; if that spike lands, prefer it, because the only real argument for taking on an archived dependency is speed, and speed here is worth about two days.
How can I help you explore Laravel packages today?