PHP RFC: Add data encoding API
- Version: 1.5
- Date: 2025-11-05
- Author: Ignace Nyamagana Butera, nyamsprod@gmail.com
- Status: Under Discussion
- First Published at: https://wiki.php.net/rfc/data_encoding_api
Introduction
To improve interoperability between PHP and other programming languages, and to simplify data encoding in PHP, we propose adding native support for encoding and decoding data using:
- the family of RFC 4648 algorithms (Base16, Base32, and Base64).
- the family of base58 algorithms
- the family of base85 algorithms
Currently, PHP only supports a limited subset of RFC 4648. With this RFC, we aim to provide full compliance with the standard and introduce missing yet popular encoding algorithms for developers.
Downsides of the current approach
PHP provides partial support for Base64 via the base64_encode and base64_decode functions but they do not provide:
- support for base64 URL alphabet and specific settings
- support for base64 IMAP alphabet and specific settings
- support for padding character removal during encoding
PHP provides partial support for Base16 via the bin2hex and hex2bin functions but they do not provide:
- support for strict decoding mechanism
- support for strict encoding (PHP uses lowercased letters whereas the RFC recommends using uppercased letters)
PHP currently lacks native support for Base32, Base58 and Base85 encoding and decoding algorithm.
In addition to the absence of these algorithms, the ecosystem suffers from a fragmented landscape of user-land packages—many of which claim compliance to one or the other algorithm without clearly specifying which variant is being refer to or implemented. This lack of a consistent reference can become problematic when applications rely on a specific algorithm for processing incoming or outgoing data. This challenge makes working with data encoding in PHP more complex than necessary.
PHP currently offers Base58 encoding and decoding via a PECL extension. This proposal seeks to integrate these functions directly into the PHP core, with additional support for the Flickr variant of Base58.
Although Base58 is not defined in a dedicated RFC defined under the IETF, it has seen widespread adoption in production systems—most notably in Bitcoin and other cryptocurrencies for encoding addresses and keys, as well as in platforms like Flickr for generating compact, URL-safe identifiers. Compared to Base64, Base58 yields shorter output, avoids visually ambiguous characters (such as 0, O, I, and l), and is inherently safe for use in URLs without additional encoding. The Base58 algorithm is simple, deterministic, and has remained stable and well-understood in the software ecosystem for over a decade.
Base85 (Ascii85) is a compact, widely used binary-to-text encoding. Base85 is more efficient for binary-heavy data such as checksums, digital signatures, or compact serialization formats. Given PHP’s growing role in systems integration and tooling (e.g., Composer, code profilers, Git interactions), native Base85 support would make such use cases cleaner and faster.
Last but not least, PHP lacks support for generating time constant encoding string which can be critical for security related processes.
The goal of this RFC is to propose adding the encoding and decoding functionalities defined in RFC 4648 to the PHP standard library as well as Base58 and Base85. It also introduces a native, constant-time implementation to address security concerns in data encoding. Once adopted, this feature will simplify data encoding in PHP, enhance interoperability with other programming languages, and strengthen security within the PHP ecosystem.
Proposal
A new, always available Encoding namespace will be added to the standard library. The namespace will contain classes and functions for encoding and decoding string or byte sequences.
For this purpose, the following internal classes and functions are added:
namespace Encoding { class EncodingError extends \Error { } class EncodingException extends \Exception { } class UnableToDecodeException extends EncodingException { } class UnableToEncodeException extends EncodingException { } enum Base16 { case Upper; case Lower; } enum Base32 { case Ascii; case Hex; case Crockford; case Z; } enum Base58 { case Bitcoin; case Flickr; } enum Base64 { case Standard; case UrlSafe; case Imap; } enum Base85 { case Adobe; case Z85; case Git; } enum PaddingMode { case VariantControlled; case StripPadding; case PreservePadding; } enum DecodingMode { case Forgiving; case Strict; } enum TimingMode { case Variable; case Constant; } }
The following Base16 functions are added:
namespace Encoding { /** * @throws UnableToEncodeException */ function base16_encode( string $data, Base16 $variant = Base16::Upper, TimingMode $timingMode = TimingMode::Variable, ): string; /** * @throws UnableToDecodeException */ function base16_decode( string $data, Base16 $variant = Base16::Upper, DecodingMode $decodingMode = DecodingMode::Strict, TimingMode $timingMode = TimingMode::Variable, ): string; }
The following Base32 functions are added:
namespace Encoding { /** * @throws UnableToEncodeException */ function base32_encode( string $data, Base32 $variant = Base32::Ascii, PaddingMode $paddingMode = PaddingMode::VariantControlled, TimingMode $timingMode = TimingMode::Variable, ): string; /** * @throws UnableToDecodeException */ function base32_decode( string $data, Base32 $variant = Base32::Ascii, DecodingMode $decodingMode = DecodingMode::Strict, TimingMode $timingMode = TimingMode::Variable, ): string; }
The following Base58 functions are added:
namespace Encoding { /** * @throws UnableToEncodeException */ function base58_encode( string $data, Base58 $variant = Base58::Bitcoin, TimingMode $timingMode = TimingMode::Variable, ): string; /** * @throws UnableToDecodeException */ function base58_decode( string $data, Base58 $variant = Base58::Bitcoin, TimingMode $timingMode = TimingMode::Variable, ): string; }
The following Base64 functions are added:
namespace Encoding { /** * @throws UnableToEncodeException */ function base64_encode( string $data, Base64 $variant = Base64::Standard, PaddingMode $paddingMode = PaddingMode::VariantControlled, TimingMode $timingMode = TimingMode::Variable, ): string; /** * @throws UnableToDecodeException */ function base64_decode( string $data, Base64 $variant = Base64::Standard, DecodingMode $decodingMode = DecodingMode::Strict, TimingMode $timingMode = TimingMode::Variable, ): string; }
The following Base85 functions are added:
namespace Encoding { /** * @throws UnableToEncodeException */ function base85_encode( string