jorisdugue/h5p-bundle
Laravel bundle for integrating H5P interactive content into PHP applications. Manage H5P libraries, content types, and editor/viewer assets, making it easier to create, embed, and serve rich interactive exercises and quizzes.
Architecture fit — primary finding: platform mismatch. Despite the brief describing this as a "Laravel/PHP package," jorisdugue/h5p-bundle is a Symfony bundle. It has no Laravel service provider, facade, config publishing, or Eloquent persistence. It binds into Symfony's DI container, config tree, event dispatcher, routing loader, and Twig namespace — none of which exist in Laravel. The reusable asset is therefore not the package itself but the adapter layer it implements on top of h5p/h5p-core and h5p/h5p-editor-php-library, specifically the H5PFrameworkInterface and H5PEditorAjaxInterface implementations. Those interfaces are framework-agnostic; the bundle is one opinionated binding of them.
Integration feasibility. Moderate, and entirely dependent on which path we pick. H5P is a mature, well-specified subsystem: it needs (a) three storage tables for libraries, content, and content types, (b) a writable file area for .h5p packages and extracted assets, (c) editor AJAX endpoints, (d) player/embed rendering, and (e) an optional xAPI statement sink. The bundle demonstrates that wiring works in a Symfony context — useful as a reference implementation and as a smoke test of the H5P core version it pins. Reimplementing those two interfaces against Eloquent, Laravel's Storage facade, and a route group is a known-shape task, not a research task.
Technical risk. High on supply chain, medium on technology:
.h5p files are ZIPs that get extracted into a served directory. If that directory is web-reachable and PHP-executable, this is a remote-code-execution class issue. Non-negotiable hardening: extraction outside the docroot or php_flag engine off / handler removal, plus MIME and zip-slip validation.Key questions for the maintainer / spike:
.h5p extraction and asset serving — docroot layout, permissions, execution guards?Stack fit. Two viable paths; the choice is a build-vs-borrow trade, not a technical one.
H5PFrameworkInterface / H5PEditorAjaxInterface implementations and rewrite the persistence and file layers against Eloquent and Storage. Removes the second app and gives a single ORM, single auth model, single deploy. Cost: roughly 4–8 engineer-weeks including test coverage, plus permanent ownership of H5P core upgrades — which we inherit either way.h5p/h5p-core directly with a thinner in-house adapter. Justified only if the sidecar proves operationally unacceptable and the port proves larger than estimated.Migration path. There is no existing H5P footprint implied by the package, so this is greenfield adoption rather than migration. The one migration-adjacent concern is content portability: H5P content is exportable as .h5p packages, so an exit path from Option A to Option B — or to a managed H5P service — is available and should be validated in the spike by exporting and re-importing one piece of content.
Compatibility. Confirm the PHP version matrix matches our runtime, and confirm the bundle's Symfony constraint. If it targets an older Symfony line, the sidecar runs on a pinned, supported Symfony release and we accept the drift, or we fork. Laravel version compatibility is not a constraint for Option A and is entirely our own code for Option B.
Sequencing.
Maintenance. This package must be treated as fork-and-own from day one, not as a dependency. Expected recurring load: H5P core/editor upgrades (quarterly is realistic), content type library updates on the same cadence, and Symfony/security patches for the sidecar if Option A is chosen. Budget roughly 10–15% of one engineer ongoing, plus a named owner. The absence of dependents means there is no external signal when something breaks — we are the signal.
Support. No vendor, no community, no SLA. Required internally: a runbook covering content type installation, library cache rebuild, failed-upload triage, and the upgrade procedure. If H5P is learner-facing and graded, this is a tier-1 dependency and needs an on-call story, not just a runbook.
Scaling. The dominant load is static, not compute: H5P content type libraries are tens of megabytes of JS/CSS and are aggressively cacheable. Serve them from a CDN with immutable, long-lived cache headers and fingerprinting — this is the single highest-leverage scaling decision. Beyond that: content tables grow with authored content and are modest; user state and xAPI statements grow with learner activity and are the real growth vector, so plan retention and archival for statements early. Upload/extract is CPU- and I/O-bound; keep it off the request-critical path where possible and cap concurrent extractions.
Failure modes.
| Failure | Impact | Detection | Mitigation |
|---|---|---|---|
| H5P core upgrade breaks adapter | Authoring or playback down | Staging smoke test on every upgrade | Pin versions; upgrade in staging first; maintain fork with tested patches |
| Content type missing after deploy | Blank or broken content | Synthetic playback check per content type | Bake content types into the image; no runtime Hub dependency |
.h5p upload → code execution |
Critical security | File-integrity scanning, handler config audit | Extract outside docroot or disable PHP handlers; zip-slip and MIME validation |
| Sidecar auth token misconfiguration | Content leaked cross-tenant | Auth negative tests in CI | Short TTL, audience claim, origin allowlist, tenant claim enforced server-side |
| Asset cache miss / CDN misconfig | Slow first load, bandwidth spike | p95 load time, CDN hit ratio | Immutable cache headers, warm the origin after deploys |
| xAPI sink backlog or loss | Missing completions/grades | Statement count reconciliation, sink lag alert | Durable queue between H5P and sink; idempotent statement IDs |
| Hub or upstream unreachable | Cannot install new content types | Authoring error rate | Mirror the content type registry internally |
Ramp-up. A mid-level Laravel engineer needs roughly 1–2 weeks to be productive against the H5P interfaces, and the port path (Option B) adds meaningful design time on the storage abstraction. Add approximately one week of legal review for content type licensing before any customer-facing launch — this is frequently the schedule surprise, not the engineering. The sidecar path shortens engineering ramp-up but adds operational ramp-up for whoever owns the second app.
TPM recommendation. Given a score of 0.565 and near-zero adoption, treat the package as a validated reference implementation, not a runtime dependency. Fund the 2–3 day spike, and if H5P is confirmed as a product requirement, default to the sidecar so we get the bundle's wiring benefits without pretending it is a Laravel library. Do not commit to the native port until the spike proves the content model and the licensing position.
How can I help you explore Laravel packages today?