delight-im/base64
A flexible PHP library for Base64 encoding and decoding with support for standard, URL-safe, and custom alphabets. It offers strict input validation, padding control, and a clean API with no external dependencies, making binary-to-text conversion safe and easy in any PHP project.
delight-im/base64 is a micro-package: a static wrapper around PHP's native Base64 functions whose only real value-add is consistent URL-safe encoding/decoding (RFC 4648 §5) and a tidier API. There is no service provider, no config file, no facade, and no publishable assets — it is a single class you call statically.
Install:
composer require delight-im/base64
Then open vendor/delight-im/base64/src/Base64.php before writing any code. The public surface is small (roughly encode, decode, encodeUrlSafe, decodeUrlSafe), but because the package is tiny and lightly maintained, confirm the exact method names, whether decoding is strict, and whether URL-safe output is padded on the version you actually installed. Two minutes of reading beats guessing.
First use case — issuing an opaque, URL-safe token:
use Delight\Base64\Base64;
$token = Base64::encodeUrlSafe(random_bytes(32));
// e.g. "k3Jd..._xQ" — safe in URLs, query strings, filenames
// and back again
$raw = Base64::decodeUrlSafe($token);
Where to look first in your Laravel app:
+, /, or = would break a route or query string.data: URIs all use base64url or padded base64, and this package smooths the difference.If all you ever do is base64_encode() on trusted data and base64_decode() on your own output, you do not need this package — the native functions are fine. Reach for it when padding and alphabet differences start causing bugs.
URL-safe tokens with random_bytes. The most common day-to-day use. Encode raw random bytes rather than generating random characters yourself:
$token = Base64::encodeUrlSafe(random_bytes(32)); // ~43 chars, no padding
Store the token hashed (hash('sha256', $token)) in the database, not the token itself, same as any bearer secret.
Decoding JWTs and other base64url segments. JWT header/payload segments are base64url without padding. If you are inspecting tokens in middleware or a debug endpoint:
[$header, $payload] = explode('.', $jwt);
$claims = json_decode(Base64::decodeUrlSafe($payload), true, flags: JSON_THROW_ON_ERROR);
Do not roll your own signature verification on top of this — use a real JWT library for auth. This pattern is for inspection, logging, and claim extraction only.
Base64 payloads in form requests / API resources. When clients send a base64 field (file upload, blob, key import), decode it in a FormRequest or a dedicated action rather than the controller:
final class StoreDocumentRequest extends FormRequest
{
public function rules(): array
{
return ['content' => ['required', 'string', 'base64']];
}
}
Laravel ships a base64 validation rule; pair it with the decode so a malformed payload fails validation instead of throwing deep in a job.
Strip data-URI prefixes first. Browser FileReader and <canvas>.toDataURL() produce data:image/png;base64,AAAA.... Split on the comma before handing the remainder to decode():
$payload = str_contains($dataUri, ',') ? explode(',', $dataUri, 2)[1] : $dataUri;
Wrap it if you expect to test or swap it. Static calls are awkward to mock. A one-method interface is usually enough:
final class Base64Codec
{
public function encodeUrlSafe(string $raw): string { return Base64::encodeUrlSafe($raw); }
public function decodeUrlSafe(string $s): string { return Base64::decodeUrlSafe($s); }
}
Bind it in a service provider and inject it. This also gives you one place to change behavior if the package is abandoned — a realistic concern given the low star count and zero dependents.
Queue jobs and casts. Base64 blobs are fine in job payloads at small sizes but bloat the queue. For larger blobs, store the binary in a longText column (decoded) or object storage and pass a reference through the queue.
encrypt() / Crypt facade, which combines encryption and its own base64 wrapping for storage.app/Support is a five-minute job if you ever want to drop the dependency. Pin the version in composer.json.base64_decode($s, true) returns false on invalid input, whereas the default silently drops invalid characters. Decide which behavior you want and check the package's decode accordingly — do not assume it throws. If it returns garbage instead of failing, validate upstream with the base64 rule.=, then translate -→+ and _→/ if you fall back to native functions.preg_replace('/\s+/', '', $s) before decoding certificate or PEM-style input.file_get_contents() a 200 MB file just to base64 it into memory.= in query strings and paths. Even standard base64 breaks routing because of +, /, and =. This is exactly the class of bug the URL-safe variant exists to prevent — default to encodeUrlSafe for anything user-visible or URL-borne.-/_ or +//? are there newlines? is it a data URI? is it base64 of base64? Work through those four questions and almost every decode failure resolves.How can I help you explore Laravel packages today?