/test/parsexml.php is the name of a test harness, not a second copy of the production parser. The production question—how to read a Cumulus XML export without blowing up on missing units, huge files, or hostile entities—is answered on parsing Cumulus station XML safely. What the export is sits on Cumulus XML as a structured snapshot. This URL is about proving those rules with golden XML, including the rule that XML External Entity processing fails closed. It is not a live debugger. It does not fetch station XML from the query string. TNET does not rehost the historical PHP.
A public /test/ parser is a security smell twice: it often dumps parsed fields, and it is the exact surface XXE and path-injection bugs were written for. Harness runs belong in CLI or CI against files that are not web-accessible.
Historical context
Shared-host weather sites parsed cumulusxml.xml with SimpleXML or DOMDocument and printed a temperature. When the parse broke, someone copied the script into /test/parsexml.php, pointed it at a file, and left it there. Forum links followed. The restoration keeps the address as a methods page for the harness those links implied.
Community dump shape is on the Cumulus Wiki XML webtags page (last checked 13 August 2026). Parser libraries follow XML 1.0 and, in PHP, libxml. OWASP’s XXE prevention cheat sheet (last checked 13 August 2026) is the defensive contract: disable DTDs and external entities; if a DTD cannot be disabled, disable external entity resolution and external DTD loading.
Golden XML is not last night’s upload
A golden input is a sanitized, versioned document you store with the tests. It is historical or constructed. It is not “whatever FTP wrote at 04:00,” and it is not current weather.
Keep at least:
- Happy path. A small, well-formed document with a known root (community dump:
weatherdata), a few allow-listed names (outside temperature, humidity, pressure, rain, wind, observation time), and a unit sibling on each value. Assert the parsed structure against a JSON golden. - Incomplete path. A well-formed document that omits a unit, omits a time, or leaves a leftover
<#temp>web tag in a text node. Assert missing or publication error, not a invented number. - Encoding path. A declaration and a body that disagree, or a degree sign in the wrong encoding. Assert refusal or a documented replacement policy—not silent mojibake on the unit.
Sanitize: dummy coordinates if present, no hostnames in comments, no real indoor temperatures you would not publish. Name files by generation, for example cumulusxml-webtags-iso88591.fixture.xml.
Do not republish a full production dump as a “sample current conditions” page. The harness compares structures. It does not need a live station identity.
XXE must fail closed
Station XML does not need a document type declaration. A DTD in a weather file is unexpected input. The production article already says not to ship an XXE payload as a public demo. The harness still has to prove the parser’s behavior.
Fail closed means: a document that declares external entities, an external DTD, or a parameter entity does not yield observations. The call returns an error, throws, or yields an empty result plus a logged reason. It does not expand entities. It does not open a URL. It does not read a local file. It does not hang until memory is gone.
How to test that without turning the repository into an attack cookbook:
- Keep a private hostile fixture off the web root and out of public docs. The file’s only job is to exist in the test suite.
- Assert on outcomes: parse error, no temperature field, no network activity, bounded time and memory. Do not assert on a recovered secret, and do not print the fixture in HTML.
- Prefer parser configuration tests as well: flags that would enable
LIBXML_NOENT,LIBXML_DTDLOAD,LIBXML_DTDATTR, orLIBXML_DTDVALIDare absent;LIBXML_NONETis present where the library offers it. PHP 8.0+ against libxml 2.9+ refuses external entity loading by default; older PHP did not. Tests should fail on an old, permissive build you still claim to support.
This page will not include a malicious XML document. If your suite cannot store a hostile fixture safely, test configuration flags only, and treat a DTD-bearing file from the outside as untrusted input that production already rejects.
Billion-laughs-style expansion and oversized files are resource tests, not weather tests. Cap byte length before building a DOM, as the production procedure states. The harness should include a file that exceeds the cap and assert that SimpleXML never runs.
Distinct from the production parser article
| | /parse_xml.php | /test/parsexml.php |
|---|---|---|
| Job | How to parse safely in production | How to prove that parse in a harness |
| Input | The file you actually ingest | Pinned goldens plus fail-closed cases |
| Output | Observations or a loud miss | Pass/fail, diffs, no HTML dump |
| XXE | Disable DTDs; do not demo payloads | Assert fail-closed; keep hostile files private |
| Audience | Operators wiring a consumer | People changing the parser |
If this article repeated the ingest checklist and called it done, it would clone the production page. The extra duty here is repeatability: another machine, another day, the same goldens, the same failures. A parser that can only be validated by hitting a live URL is a parser you cannot regress when a template adds a tag.
Web-tag leftovers (<#temp>) are a publication error. The harness should include one golden that contains that pattern and assert the production rule: do not treat the file as observations. Mapping names onto a web-tag vocabulary is a separate, documented step—not a guess inside simplexml_load_string.
No live debug endpoint
Do not restore parsexml.php as a page that prints var_dump($xml). Do not accept ?file= or a URL to parse. Do not log expanded entity text.
Use:
php bin/assert-station-xml.php tests/fixtures/happy.xml(nonzero on mismatch);- CI on every parser change;
- a private status of “last parse OK, document age, schema id” without field dumps.
The dayfile harness on /test/dayfile.php is the same idea for a different file family: pin a fixture, assert columns, keep it off the public vhost. Do not parse XML with the dayfile splitter or the other way around.
Modern relevance
Quality control on structured weather files is source identity, schema, units, freshness, and refusal of hostile input. TNET’s public description of that discipline for research records is data sources, quality controls, and methodology. Observed values versus later derived products stay conceptual on how the service works. The Cumulus hub indexes the cluster. This /test/ URL is a warning label: prove the parser with goldens, and prove XXE closed, without a world-readable script.
Sources
- W3C: XML 1.0
- OWASP: XML External Entity Prevention Cheat Sheet (last checked 13 August 2026)
- PHP: libxml_disable_entity_loader (last checked 13 August 2026)
- Cumulus Wiki: XML webtags (last checked 13 August 2026)
- TNET, Data sources, quality controls, and methodology
- TNET, How the service works