accredifysg / php-json-ld
A PHP implementation of the JSON-LD 1.1 specification.
Requires
- php: ^8.2
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.1 || ^2.0
Requires (Dev)
- guzzlehttp/guzzle: ^7.0
- guzzlehttp/psr7: ^2.0
- laravel/pint: ^1.0
- mockery/mockery: ^1.6
- pestphp/pest: ^2.14
- phpstan/phpstan: ^2.1
Suggests
- psr/http-client-implementation: A PSR-18 client (e.g. guzzlehttp/guzzle) is required if you use HttpDocumentLoader for resolving remote @context URLs.
- psr/http-factory-implementation: A PSR-17 request factory (e.g. guzzlehttp/psr7) is required if you use HttpDocumentLoader.
This package is auto-updated.
Last update: 2026-08-14 08:06:57 UTC
README
A PHP implementation of the JSON-LD 1.1 specification.
PHP-JSON-LD implements all six JSON-LD 1.1 processing algorithms —
Expansion, Compaction, Flattening, Serialize to RDF (toRdf),
RDF to JSON-LD (fromRdf), and Framing — validated against the
official W3C test suites (1,287 of 1,302 tests passing, with Compaction
and Flattening fully conformant) and cross-checked against reference
implementations for identical canonical RDF output. The public API is stable
and the project follows Semantic Versioning.
Highlights
- Complete algorithm coverage of the JSON-LD 1.1 Processing Algorithms and API and JSON-LD 1.1 Framing.
- Conformance gated in CI against the official W3C suites: any regression — or a documented blocker that silently starts passing — fails the build.
- Cross-implementation interoperability: RDF output is verified against
RDFC-1.0 canonical N-Quads goldens generated by jsonld.js over realistic
verifiable-credential documents, so signatures computed over this library's
output verify in other conformant processors (see
tests/Interop). - Pluggable document loading: implement one
DocumentLoaderinterface to serve known@contextURLs from local resources — recommended for verifiable-credential pipelines — or use the bundled PSR-18 HTTP loader. - No mandatory HTTP dependency: bring your own PSR-18 client, or none.
Installation
composer require accredifysg/php-json-ld
Requires PHP 8.2+. The bundled HttpDocumentLoader needs a PSR-18 HTTP client
and PSR-17 request factory (e.g. guzzlehttp/guzzle + guzzlehttp/psr7);
alternatively, implement Accredify\JsonLd\Contracts\DocumentLoader yourself
and no HTTP client is required.
Usage
use Accredify\JsonLd\JsonLdProcessor; use Accredify\JsonLd\Loaders\CachingDocumentLoader; use Accredify\JsonLd\Loaders\HttpDocumentLoader; use GuzzleHttp\Client; use GuzzleHttp\Psr7\HttpFactory; $loader = new CachingDocumentLoader( new HttpDocumentLoader(new Client, new HttpFactory), ); $processor = new JsonLdProcessor($loader); $expanded = $processor->expand($document); $compacted = $processor->compact($expanded->toArray(), $context)->toArray(); $nQuads = $processor->toRdf($document)->toNQuads();
To serve known contexts from local files (recommended for verifiable
credentials), implement Accredify\JsonLd\Contracts\DocumentLoader. See
tests/Interop/Support/FixtureDocumentLoader.php
for a compact example.
Framing note: a frame's
{}wildcard cannot be represented in PHP's associative-array model (it decodes identically to[]), so the framing API treats an empty frame value asmatch noneand accepts the documentedExpansion::FRAME_WILDCARDsentinel for a wildcard.
Conformance
The package is tested against the
official W3C JSON-LD 1.1 test suite
(git submodule at tests/w3c/; harness documented in
tests/W3c/README.md).
| Algorithm | Spec | W3C suite | Passing | Conformance |
|---|---|---|---|---|
| Expansion | §5.5 | 385 | 381 | 4 documented blockers |
| Compaction | §5.6 | 246 | 246 | 100% |
Serialize to RDF (toRdf) |
§7 | 467 | 463 | 4 documented blockers |
| Flattening | §4.6 | 58 | 58 | 100% |
RDF to JSON-LD (fromRdf) |
§4.9 | 54 | 50 | 4 documented blockers |
| Framing | framing §4 | 92 | 89 | 3 documented blockers |
Totals: 1,287 / 1,302 passing. The 15 residual non-conformances are
negative-test, non-normative, or environment limits, carried as an explicit
expected-failure allowlist
(tests/W3c/KnownBlockers.php) that gates CI in
both directions — a new regression fails the build, and so does a listed
blocker that starts passing:
#tc032/#tc033— unused embedded contexts aren't validated (negative tests)#ter56— redefining the@contextkeyword isn't rejected (negative test)#t0122(expand only) — keyword-shaped (@) IRIs are dropped rather than kept as{@id: null}(non-normative)#tjs10(toRdf only) — JSON-literal structural canonicalization differs (PHP cannot distinguish{}from[])#t0008/#tli03(fromRdf) — list-of-lists conversion; single-level lists are fully supported#tdi11/#tdi12(fromRdf, non-normative) — compound-literal direction folding#t0010(framing) — compaction safe-mode rejectsdcterms:creatoras an IRI confused with thedctermsprefix (the reference processor errors here too)#t0045(framing) —@languagecase-normalization (expansion preserves case, which the signature-criticaltoRdfbytes depend on)#t0059(framing) — the legacy@embed: @lastmode (the@oncedefault is implemented)
composer test # unit tests (includes the interop corpus) composer test:w3c # the W3C conformance suites
Implementation report
A W3C EARL implementation report is generated for each release and submitted to the JSON-LD 1.1 implementation report. To regenerate it:
vendor/bin/pest --testsuite W3C --log-junit w3c-junit.xml php scripts/generate-earl-report.php w3c-junit.xml <version> > reports/php-json-ld-earl.ttl
Tests marked specVersion: json-ld-1.0 are excluded from the report, matching
the consolidated report's JSON-LD 1.1 scope.
Interoperability
The W3C suite alone cannot catch a processor that is consistently wrong:
internal sign/verify round-trips recompute the same dataset on both sides, and
a divergence only surfaces when another implementation checks the signature.
tests/Interop closes that gap with realistic VC 2.0 and
Open Badges v3 documents whose RDFC-1.0 canonical N-Quads — the exact bytes an
eddsa-rdfc-2022 proof is computed over — are pinned to goldens generated by
jsonld.js and compared as datasets on every CI run.
Development notes
tests/Algorithms/Characterization/ holds JSON snapshots of the expander's
output over sample verifiable-credential documents. They are not a
spec-conformance reference; they pin behaviour so any change to expansion
output lands as a reviewable diff, to be paired with matching updates in
downstream consumers (e.g. signed-credential fixtures).
License
MIT © Accredify