Validate iri and iri-reference formats according to RFC 3987 - #962
Merged
Merged
Conversation
The iri and iri-reference formats had no validation in the Draft07 and Draft2019 format constraints, so every string was accepted. Add a validator derived from the RFC 3987 section 2.2 ABNF, checking IPv6 literals with filter_var and anchoring with \z to reject a trailing new line. Character runs are matched possessively to stay within the PCRE JIT stack limits for long values, and BMP and supplementary ranges live in separate classes to avoid a PCRE2 10.46 matching bug. Remove the now passing iri and iri-reference cases from the test suite skip list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The validator rejects RFC-valid IPvFuture host literals, and the URI-template PHPDocs are misplaced.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 2
Open (2)
What changed in this PR
Adds RFC 3987 validation for iri and iri-reference formats in Draft07 and Draft2019.
Changes:
- Implements IRI parsing and percent-encoding validation.
- Adds Unicode, newline, relative-reference, and performance regression tests.
- Enables corresponding JSON Schema Test Suite cases.
| File | Description |
|---|---|
src/JsonSchema/Constraints/Drafts/Draft07/FormatConstraint.php |
Adds Draft07 IRI validation. |
src/JsonSchema/Constraints/Drafts/Draft2019/FormatConstraint.php |
Adds Draft2019 IRI validation. |
tests/Constraints/Draft07/FormatConstraintTest.php |
Adds Draft07 regression coverage. |
tests/Constraints/Draft2019/FormatConstraintTest.php |
Adds Draft2019 regression coverage. |
tests/JsonSchemaTestSuiteTest.php |
Enables IRI test-suite cases. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
DannyvdSluijs
force-pushed
the
feature/iri-format
branch
from
September 22, 2026 18:07
d5c1187 to
c4d9d1c
Compare
Accept IPvFuture host literals as defined in the RFC 3986 / 3987 ABNF, and move the uri-template docblock back above validateUriTemplate() so it is no longer orphaned by the validateIri() docblock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
iriandiri-referencehad no case in the Draft07 / Draft2019FormatConstraintswitch, so they fell through todefaultand every string was accepted. The optional test suite cases were partly skipped; the percent-encoding cases added upstream in json-schema-org/JSON-Schema-Test-Suite#1184 were not, which accounts for 6 of the current CI failures.This adds
validateIri()(kept per draft) derived from the RFC 3987 §2.2 ABNF:iri=scheme ":" ihier-part [ "?" iquery ] [ "#" ifragment ];iri-referenceadditionally acceptsirelative-ref(no:in the first segment of a scheme-less relative path).iunreservedincludesucschar;iprivateis only allowed in the query;%must be followed by two hex digits.filter_var(..., FILTER_FLAG_IPV6)(rejects e.g.::ffff:192.168.0.01).\z, so a trailing new line is rejected ($would accept it).JIT stack limit exhaustedat ~8k characters and reports valid values as invalid; this version handles >1M characters.Errors reuse
ConstraintError::FORMAT_url()(iri) andFORMAT_URL_REF()(iri-reference), mirroringuri/uri-reference.The iri and iri-reference entries are removed from the skip list in
JsonSchemaTestSuiteTest, and regression cases (non-Latin characters, trailing new line, lone%, long path) are added to the Draft07 and Draft2019FormatConstraintTest.Test plan
./bin/run-test-case {draft7,draft2019-09}/optional/format/iri.json "validation of IRIs"→ 26 passed, 0 failed./bin/run-test-case {draft7,draft2019-09}/optional/format/iri-reference.json "validation of IRI References"→ 21 passed, 0 failedcomposer phpstan→ no errorscomposer test→ failures down from 24 to 18; the remaining ones are pre-existing upstream additions for uri-reference (percent-encoding) and idn-email🤖 Generated with Claude Code