A lightweight & versatile library for generating and encoding unique identifiers. It provides fast, secure, and flexible solutions for modern applications.
-
Reversible encoders (
Base32,Base58,Base64) via a commonEncoderInterface -
Several ID generators (
UUIDv4,ULID,Nanoid, Snowflake-like IDs) via a commonIdGeneratorInterface -
Simple configuration of objects and factory helpers
|
Tip
|
All examples target PHP 8.2+ (the codebase is PHP 8.4-ready). Namespaces are rooted under Inane\IdForge.
|
use Inane\IdForge\IdGeneratorFactory;
use Inane\IdForge\EncoderFactory;
$uuid = IdGeneratorFactory::createUUID()->generate();
$ulid = IdGeneratorFactory::createULID()->generate();
$nanoid = IdGeneratorFactory::createNanoid()->generate();
$snow = IdGeneratorFactory::createSnowflake(1, 2)->generate();
$base58 = EncoderFactory::createBase58();
$encoded = $base58->encode($ulid);
$decoded = $base58->decode($encoded);This module provides reversible string encoders that share a simple contract, EncoderInterface. Implementations cover Base32, Base58, and Base64 (including a URL-safe variant).
Contract for reversible string encoders:
-
encode(string $data): string— converts binary-safe input to an encoded string -
decode(string $data): string— converts an encoded string back to the original binary data
Implementations must be deterministic and satisfy decode(encode($x)) === $x for valid input. Invalid input should raise Inane\Stdlib\Exception\InvalidArgumentException (or a domain-specific exception).
Namespace: Inane\IdForge\Encoder\Base32Encoder
-
Alphabet: configurable (RFC 4648 by default when using
EncoderFactory::createBase32()) -
Padding: not applied; trailing zero bits are used to complete the last 5-bit group
-
Errors: throws
InvalidArgumentExceptionif a character is not in the alphabet duringdecode()
use Inane\IdForge\EncoderFactory;
$base32 = EncoderFactory::createBase32();
$enc = $base32->encode("\x00\xFFHello");
$bin = $base32->decode($enc);Namespace: Inane\IdForge\Encoder\Base58Encoder
-
Alphabet: configurable (Bitcoin alphabet via
EncoderFactory::createBase58()) -
Preserves leading zero bytes as leading first-alphabet characters
-
Errors: throws
InvalidArgumentExceptionfor unknown characters duringdecode()
use Inane\IdForge\EncoderFactory;
$base58 = EncoderFactory::createBase58();
$enc = $base58->encode("\0\0payload");
$bin = $base58->decode($enc);Namespace: Inane\IdForge\Encoder\Base64Encoder
-
Standard Base64 via
encode()/decode() -
URL-safe helpers:
urlEncode()replaces+//with-/_and strips padding;urlDecode()restores and decodes -
Errors:
decode()andurlDecode()throwInvalidArgumentExceptionfor invalid Base64 input
use Inane\IdForge\EncoderFactory;
$base64 = EncoderFactory::createBase64();
$token = $base64->urlEncode(random_bytes(16));
$bytes = $base64->urlDecode($token);Encoders accept Inane\IdForge\Config\EncoderConfig which holds:
-
alphabet: string -
alphabetLength: int(precomputed)
Use EncoderFactory for sensible defaults or construct encoders manually with a custom alphabet.
IdForge includes several generators that implement a common contract, IdGeneratorInterface. Each generator focuses on a different trade-off: interoperability (UUID), sortability (ULID, Snowflake), or brevity and URL-friendliness (Nanoid).
-
generate(): string— create a new identifier as a string
Implementations should be fast, low-collision, and safe to use concurrently.
Namespace: Inane\IdForge\Generator\UUIDGenerator
-
RFC 4122 UUID version 4
-
Format: canonical 36-char string
8-4-4-4-12 -
Helpers:
-
isValid(string $uuid): bool -
toBase64(string $uuid, Base64Encoder $base64): string— URL-safe Base64 (no padding) -
fromBase64(string $b64, Base64Encoder $base64): string— back to canonical string -
Errors:
toBase64()throwsInvalidArgumentExceptionfor invalid input
use Inane\IdForge\IdGeneratorFactory;
use Inane\IdForge\EncoderFactory;
$uuid = IdGeneratorFactory::createUUID()->generate();
$base64 = EncoderFactory::createBase64();
$b64 = IdGeneratorFactory::createUUID()->toBase64($uuid, $base64);
$uuid2 = IdGeneratorFactory::createUUID()->fromBase64($b64, $base64);Namespace: Inane\IdForge\Generator\ULIDGenerator
-
26-char Crockford Base32, lexicographically sortable
-
Structure: 48-bit timestamp + 80 bits randomness
-
Monotonic mode ensures strict ordering within the same millisecond
-
Key methods:
-
__construct(?EncoderConfig $config = null, bool $monotonic = false) -
generate(?int $timestamp = null): string -
decodeTimestamp(string $ulid): int -
decode(string $ulid): array{timestamp:int, random:string} -
toEncoded(EncoderInterface $encoder): string -
Errors:
InvalidArgumentExceptionfor bad characters/length;Random\RandomExceptionfor entropy issues
use Inane\IdForge\IdGeneratorFactory;
$ulid = IdGeneratorFactory::createULID()->generate();use Inane\IdForge\Generator\ULIDGenerator;
use Inane\IdForge\Config\EncoderConfig;
$mono = new ULIDGenerator(new EncoderConfig('0123456789ABCDEFGHJKMNPQRSTVWXYZ'), true);
$a = $mono->generate();
$b = $mono->generate(); // guaranteed $a < $b when in same msNamespace: Inane\IdForge\Generator\NanoidGenerator
-
Short, URL-friendly random IDs
-
Constructor:
__construct(string $alphabet = '0-9a-zA-Z', int $size = 21) -
generate(): string
use Inane\IdForge\IdGeneratorFactory;
$id = IdGeneratorFactory::createNanoid()->generate();Namespace: Inane\IdForge\Generator\SnowflakeIdGenerator
-
64-bit composed numeric ID (as a string): timestamp + datacenter + worker + sequence
-
Configured via
SnowflakeConfig(epoch, bit allocations for worker/datacenter/sequence) -
Methods:
-
__construct(int $workerId = 0, int $datacenterId = 0, ?SnowflakeConfig $config = null) -
generate(): string -
toEncoded(EncoderInterface $encoder): string -
Behavior: on sequence overflow within the same millisecond, waits for the next millisecond
-
Errors:
RuntimeExceptionif the clock moves backwards;InvalidArgumentExceptionfor out-of-range worker/datacenter
use Inane\IdForge\IdGeneratorFactory;
$gen = IdGeneratorFactory::createSnowflake(workerId: 1, datacenterId: 2);
$id = $gen->generate();This module documents the small configuration objects that accompany encoders and generators.
Namespace: Inane\IdForge\Config\EncoderConfig
Holds the alphabet used by encoders and caches its length.
-
alphabet: string— characters used by the encoding -
alphabetLength: int— cached length of the alphabet
-
__construct(string $alphabet)— set the alphabet and precompute its length -
getAlphabet(): string -
getAlphabetLength(): int
use Inane\IdForge\Config\EncoderConfig;
use Inane\IdForge\Encoder\Base32Encoder;
$config = new EncoderConfig('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567');
$encoder = new Base32Encoder($config);Namespace: Inane\IdForge\Config\SnowflakeConfig
Controls the epoch and bit allocations for Snowflake-like IDs.
-
epoch: int— custom epoch in milliseconds (default: 1609459200000, 2021-01-01) -
workerIdBits: int— bits for worker/node id (default: 5) -
datacenterIdBits: int— bits for datacenter id (default: 5) -
sequenceBits: int— bits for per-millisecond sequence (default: 12)
-
__construct(int $epoch = 1609459200000, int $workerIdBits = 5, int $datacenterIdBits = 5, int $sequenceBits = 12) -
Getters:
-
getEpoch(): int -
getWorkerIdBits(): int -
getDatacenterIdBits(): int -
getSequenceBits(): int
use Inane\IdForge\Generator\SnowflakeIdGenerator;
use Inane\IdForge\Config\SnowflakeConfig;
$config = new SnowflakeConfig(epoch: 1700000000000, workerIdBits: 6, datacenterIdBits: 4, sequenceBits: 12);
$gen = new SnowflakeIdGenerator(workerId: 3, datacenterId: 1, config: $config);
$id = $gen->generate();Factory helpers provide convenient, opinionated constructors for common encoders and generators.
Namespace: Inane\IdForge\EncoderFactory
Creates encoder instances with sensible default alphabets.
-
createBase32(): Base32Encoder— RFC 4648 alphabetA-Z2-7 -
createBase58(): Base58Encoder— Bitcoin alphabet (no0,O,I,l) -
createBase64(): Base64Encoder— Standard Base64 alphabet
use Inane\IdForge\EncoderFactory;
$base32 = EncoderFactory::createBase32();
$base58 = EncoderFactory::createBase58();
$base64 = EncoderFactory::createBase64();Namespace: Inane\IdForge\IdGeneratorFactory
Creates generator instances with defaults and safe validation where applicable.
-
createNanoid(string $alphabet = '0-9a-zA-Z', int $size = 21): NanoidGenerator -
createSnowflake(int $workerId = 0, int $datacenterId = 0, ?SnowflakeConfig $config = null): SnowflakeIdGenerator -
createUUID(): UUIDGenerator -
createULID(?EncoderConfig $config = null): ULIDGenerator
use Inane\IdForge\IdGeneratorFactory;
$uuid = IdGeneratorFactory::createUUID()->generate();
$ulid = IdGeneratorFactory::createULID()->generate();
$nanoid = IdGeneratorFactory::createNanoid()->generate();
$snow = IdGeneratorFactory::createSnowflake(workerId: 1, datacenterId: 2)->generate();use Inane\IdForge\Config\EncoderConfig;
use Inane\IdForge\Config\SnowflakeConfig;
use Inane\IdForge\Encoder\AbstractEncoder;
use Inane\IdForge\EncoderFactory;
use Inane\IdForge\Generator\AbstractIdGenerator;
use Inane\IdForge\IdGeneratorFactory;
// Example usage
try {
// Create encoders via factory
$base32 = EncoderFactory::createBase32();
$base58 = EncoderFactory::createBase58();
$base64 = EncoderFactory::createBase64();
// Create ID generators via factory
$nanoid = IdGeneratorFactory::createNanoid();
$snowflake = IdGeneratorFactory::createSnowflake(1, 1);
$uuid = IdGeneratorFactory::createUUID();
$ulid = IdGeneratorFactory::createULID();
// Base32
$base32Encoded = $base32->encode('Hello');
echo "Base32 Encoded: $base32Encoded\n";
echo 'Base32 Decoded: ' . $base32->decode($base32Encoded) . "\n";
echo PHP_EOL;
// Base58
$base58Encoded = $base58->encode('Hello');
echo "Base58 Encoded: $base58Encoded\n";
echo 'Base58 Decoded: ' . $base58->decode($base58Encoded) . "\n";
echo PHP_EOL;
// Base64
$base64Encoded = $base64->urlEncode('Hello');
echo "Base64 URL Encoded: $base64Encoded\n";
echo 'Base64 URL Decoded: ' . $base64->urlDecode($base64Encoded) . "\n";
echo PHP_EOL;
// Nanoid
echo 'Nanoid: ' . $nanoid->generate() . "\n";
echo PHP_EOL;
// Snowflake ID
$snowflakeId = $snowflake->generate();
echo "Snowflake ID: $snowflakeId\n";
echo 'Snowflake ID (Base58): ' . $snowflake->toEncoded($base58) . "\n";
echo PHP_EOL;
// UUID
$uuidValue = $uuid->generate();
echo "UUID: $uuidValue\n";
$uuidBase64 = $uuid->toBase64($uuidValue, $base64);
echo "UUID Base64: $uuidBase64\n";
echo 'UUID from Base64: ' . $uuid->fromBase64($uuidBase64, $base64) . "\n";
echo PHP_EOL;
// ULID
$ulidValue = $ulid->generate();
echo "ULID: $ulidValue\n";
echo 'ULID Timestamp: ' . $ulid->decodeTimestamp($ulidValue) . "\n";
echo 'ULID Base32: ' . $ulid->toEncoded($base32) . "\n";
echo PHP_EOL;
// ULID
$ulidValue = $ulid->generate(1761168799791);
echo "ULID 2: $ulidValue\n";
echo 'ULID 2 Timestamp: ' . $ulid->decodeTimestamp($ulidValue) . "\n";
echo 'ULID 2 Base32: ' . $ulid->toEncoded($base32) . "\n";
} catch (Exception $e) {
echo 'Error: ' . $e->getMessage() . "\n";
}
// Add a New Encoder:
class Base16Encoder extends AbstractEncoder {
public function __construct() {
parent::__construct(new EncoderConfig('0123456789ABCDEF'));
}
public function encode(string $data): string {
return strtoupper(bin2hex($data));
}
public function decode(string $data): string {
return hex2bin($data);
}
}
class Encoder2Factory {
public static function createBase16(): Base16Encoder {
return new Base16Encoder();
}
}
$base16 = Encoder2Factory::createBase16()->encode('Hello');
$text = Encoder2Factory::createBase16()->decode($base16);
$line("Base16:encoded: $base16");
$line("Base16:decoded: $text");
// EncoderFactory::createBase16 = fn() => new Base16Encoder();
// Add a New ID Generator:
class CustomIdGenerator extends AbstractIdGenerator {
public function generate(): string {
$timestamp = $this->getTimestamp();
$random = $this->getRandomBytes(8);
return bin2hex($timestamp . $random);
}
}
class IdGenerator2Factory {
public static function createCustomId(): CustomIdGenerator {
return new CustomIdGenerator();
}
}
$customId = IdGenerator2Factory::createCustomId()->generate();
$line("CustomID: $customId");
// IdGeneratorFactory::createCustomId = fn() => new CustomIdGenerator();
// Customize Snowflake Configuration:
$customConfig = new SnowflakeConfig(1640995200000, 4, 4, 10); // Custom epoch, fewer bits
$snowflake = IdGeneratorFactory::createSnowflake(1, 1, $customConfig);
// Custom Alphabet for Nanoid:
$nanoid = IdGeneratorFactory::createNanoid('0123456789abcdef', 12); // Hex-only, shorter length-
Most decoders will throw
Inane\Stdlib\Exception\InvalidArgumentExceptionwhen the input contains invalid characters or cannot be parsed. -
SnowflakeIdGenerator::generate()can throwInane\Stdlib\Exception\RuntimeExceptionif it detects a system clock moving backwards. -
Generators that rely on randomness may throw
Random\RandomExceptionfrom PHP core when entropy is not available.
-
UUIDv4: Standard interoperable identifiers, not sortable, 36 chars.
-
ULID: 26-char, lexicographically sortable, timestamp + randomness; good for DB keys and logs.
-
Nanoid: Short, URL-friendly IDs with controllable alphabet and size.
-
Snowflake: Numeric IDs composed of timestamp + worker/datacenter + sequence; good for distributed systems that need k-sortable numbers.