value; } /** * Check if this alphabet uses padding */ public function usesPadding(): bool { return match ($this) { self::RFC3548 => true, self::CROCKFORD => false }; } /** * Get the character count (always 32 for Base32) */ public function getCharacterCount(): int { return 32; } /** * Validate if a character exists in this alphabet */ public function containsCharacter(string $char): bool { return str_contains($this->value, strtoupper($char)); } /** * Get the index of a character in the alphabet */ public function getCharacterIndex(string $char): int { $index = strpos($this->value, strtoupper($char)); if ($index === false) { throw new \InvalidArgumentException("Character '{$char}' not found in {$this->name} alphabet"); } return $index; } /** * Get character at specific index */ public function getCharacterAt(int $index): string { if ($index < 0 || $index >= 32) { throw new \InvalidArgumentException("Index must be between 0 and 31, got {$index}"); } return $this->value[$index]; } /** * Validate an encoded string against this alphabet */ public function isValidEncoded(string $encoded): bool { // Remove padding if this alphabet uses it if ($this->usesPadding()) { $encoded = rtrim($encoded, '='); } $encoded = strtoupper($encoded); // Check if all characters are valid for ($i = 0, $len = strlen($encoded); $i < $len; $i++) { if (! $this->containsCharacter($encoded[$i])) { return false; } } return true; } /** * Get recommended use cases for this alphabet * @return array */ public function getUseCases(): array { return match ($this) { self::RFC3548 => [ 'TOTP secrets', 'General Base32 encoding', 'Email verification codes', 'API tokens', ], self::CROCKFORD => [ 'ULIDs', 'Human-readable identifiers', 'Short URLs', 'Database primary keys', ] }; } /** * Get description of this alphabet */ public function getDescription(): string { return match ($this) { self::RFC3548 => 'RFC 3548 standard Base32 alphabet with padding', self::CROCKFORD => 'Crockford\'s Base32 alphabet without padding, optimized for human readability' }; } /** * Generate a random string using this alphabet */ public function generateRandom(int $length): string { if ($length < 1) { throw new \InvalidArgumentException('Length must be positive'); } $result = ''; for ($i = 0; $i < $length; $i++) { $result .= $this->value[random_int(0, 31)]; } return $result; } }