christian-riesen/base32
A strict RFC 4648 Base32 encoder and decoder for PHP, with support for the extended hex alphabet. Decoding rejects malformed input, and the package includes test vectors and unit tests.
Architecture fit. christian-riesen/base32 is a leaf-node utility library and nothing more: two static classes (Base32\Base32, Base32\Base32Hex), PSR-4 autoloading, zero runtime dependencies, no service provider, no facade, no config surface, no framework coupling. In a Laravel codebase that means it slots in below the application layer as a pure function library — it will never appear in a service container resolution graph unless we put it there. The corollary a TPM must internalize: this package does not integrate with Laravel, it is merely installable in Laravel. Every integration concern (DI, config for alphabet selection, validation, exception mapping to HTTP responses) is work we own and must scope explicitly. Effort is small but it is not zero, and the "one Composer line" framing in vendor-adjacent marketing understates the wrapper work.
Integration feasibility. High. composer require christian-riesen/base32 plus a thin wrapper is a sub-day task for one engineer. The API is stable, synchronous, and trivially testable against published RFC 4648 vectors, which the maintainer already ships. There is no infrastructure footprint, no migration, no data store, no daemon. The only real sequencing hazard is the PHP floor: 2.x requires PHP 8.1+, which effectively means Laravel 10+ unless we stay on the 1.x line (PHP 7.2+). That single constraint drives the whole adopt-or-defer decision and should be resolved against our actual runtime matrix before any ticket is written.
Technical risk.
0 dependents while the package is a known transitive dependency of the PHP OTP stack (otphp, google2fa). Treat this as an undercounted metric, not evidence of low adoption — and do not let it be used to justify either "nobody uses it" or "it's battle-tested."\InvalidArgumentException. This is the right change — it closes Trail of Bits finding TOB-WIKI2FA-5 from the Wikimedia 2FA review — but any code path that previously relied on lenient sanitizing of user input will start throwing. That is a latent production incident unless we audit decode call sites.hash_equals comparison. If the roadmap item is "ship 2FA," this package is one small component of a larger build/buy decision.isBase32() validator, no padding-preserving encode mode, no timing-safe comparison. All trivial locally, all must be explicitly scoped or they become "we assumed the library did that."Key questions to resolve before commit.
^1.6 and accept a slower-moving line.Stack fit. Clean but deliberately minimal. There is nothing to auto-discover and nothing to configure, so the fit is entirely a function of how we wrap it. Recommended shape:
Base32Codec interface (or a single small service class) exposing encode(string): string and decode(string): string.Base32 (or Base32Hex, selected by config — do not expose both classes as interchangeable; they are silently incompatible alphabets).\InvalidArgumentException to a 422/validation error, not a 500.Migration path. Two distinct migrations, and they should not be conflated.
decode() call site, classify each input source as "trusted/internal" versus "user-supplied," and add normalization plus exception handling on the user-supplied paths before bumping to 2.x. Any path that depended on lenient stripping — lowercase secrets, space-grouped secrets, unpadded input — will now throw. Sequence this as its own ticket with a rollback plan; do not bundle it into a routine dependency bump.Compatibility.
^2.0 or ^1.6 — never to a looser or older constraint.Sequencing.
Maintenance. Low but non-zero. Expect roughly one bump per year on this package's observed cadence. The real maintenance cost is not the upgrade — it is the annual repetition of the 2.0 question: did the major version change decoding semantics again, and do we have the decode call-site inventory to answer that quickly? The wrapper class is what makes that answer cheap. Treat the wrapper as the durable asset and the library as replaceable. If the maintainer goes dark, a from-scratch RFC 4648 implementation is a day or two of work with published test vectors — this is one of the few dependencies where "we could replace it" is genuinely credible, which materially reduces vendor risk.
Support. No SLA, no vendor, no security policy documented in the materials. Escalation path is an issue on a personal GitHub repo. For an authentication-path dependency this needs an explicit accepted-risk line in the dependency register rather than a silent pass. Mitigating factors worth recording: MIT license, no transitive dependencies, static API, published changelog, unit tests against official vectors, and a demonstrated history of responding to a third-party security audit finding.
Scaling. Effectively free. Pure in-process CPU, no I/O, no state, no caching concerns. Base32 carries a 8:5 expansion ratio (~60% overhead) versus the raw bytes, so watch payload sizing for any large-token or bulk-export use case, not for throughput. It will not be a capacity-planning line item at any realistic volume.
Failure modes to instrument and document.
\InvalidArgumentException on decode of user input → 500s. Highest-probability incident; mitigate with boundary normalization and exception mapping.Base32 and Base32Hex produce and accept different alphabets with no runtime signal. A wrong-class import is a silent data-corruption class of bug — mitigate with a single wrapper entry point and a code-review note.hash_equals() on decoded bytes.Ramp-up. Very low. A competent Laravel engineer is productive in under an hour; the entire public surface is two static methods. The onboarding cost that actually matters is the context, not the API: why strict decoding exists, why normalization happens upstream, why the hex alphabet is segregated, and why comparison must be timing-safe. Budget a short written note in the wrapper's docblock rather than a meeting — and make sure the first engineer to integrate writes it, because the second one will otherwise re-derive the 2.0 migration lessons from scratch.
TPM bottom line. Adopt directly only if Base32 appears in more than one place or we want a stable seam independent of whichever OTP library we pick; otherwise take it as a transitive dependency of the OTP framework and skip the wrapper. Either way, the decisions to record are: pinned version, PHP floor, wrapper ownership, and an explicit accepted-risk entry for single-maintainer support on an authentication-path dependency.
How can I help you explore Laravel packages today?