trac/hash-id

High-performance PHP library to generate YouTube-like IDs from numbers. Drop-in replacement for Hashids, 4.7x faster.

Maintainers

Package info

github.com/go-redrock-software/trac_hash_id

Issues

pkg:composer/trac/hash-id

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

dev-master 2026-03-06 07:56 UTC

This package is not auto-updated.

Last update: 2026-05-16 07:33:20 UTC


README

The fastest PHP library for generating YouTube-like IDs from numbers.

A high-performance implementation of the Hashids algorithm, 4.7x faster than Hashids and 3.9x faster than Sqids.

100% compatible with original Hashids - drop-in replacement ✅ Identical output - generates the exact same hashes ✅ Battle-tested - passes all compatibility and unit tests ✅ Speed-optimized - shuffle caching and BCMath for performance

Performance Optimizations

This library is built with SPEED as the top priority:

  • Shuffle Caching: Memoizes shuffled alphabet states to avoid repeated expensive shuffling operations
  • String-Native Operations: Minimizes array conversions in hot paths
  • Integer Math: Uses native PHP integers instead of GMP for hash/unhash (GMP only for hex encoding where needed)
  • Minimal Allocations: Reduces memory allocations and string copying
  • Optimized Loops: Replaced regex operations with simple character-by-character loops
  • Pre-computed Values: Caches alphabet lengths, separators, and guards
  • Fast Validation: Streamlined input validation with early returns

Requirements

  • PHP 8.2 or higher
  • BCMath extension (ext-bcmath) - required for handling large numbers

Installation

composer require trac/hash-id

Usage

Basic Encoding/Decoding

use Trac\HashId\HashId;

$hashId = new HashId();

// Encode
$hash = $hashId->encode(1, 2, 3); // e.g., "o2fXhV"

// Decode
$numbers = $hashId->decode($hash); // [1, 2, 3]

With Salt

$hashId = new HashId('my salt');

$hash = $hashId->encode(1, 2, 3);
$numbers = $hashId->decode($hash);

Minimum Hash Length

$hashId = new HashId('', 10); // Minimum length of 10

$hash = $hashId->encode(1); // Length will be at least 10
$numbers = $hashId->decode($hash);

Custom Alphabet

$hashId = new HashId('', 0, 'abcdefghijklmnopqrstuvwxyz');

$hash = $hashId->encode(1, 2, 3); // Only lowercase letters

Encoding Hex Values

$hashId = new HashId();

$hash = $hashId->encodeHex('507f1f77bcf86cd799439011');
$hex = $hashId->decodeHex($hash); // '507f1f77bcf86cd799439011'

Array Input

$hashId = new HashId();

$hash = $hashId->encode([1, 2, 3]);
// or
$hash = $hashId->encode(1, [2, 3], 4);

API

__construct(string $salt = '', int $minHashLength = 0, string $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890')

Create a new HashId instance.

  • $salt - Salt string for generating unique hashes
  • $minHashLength - Minimum length of generated hashes (will be padded if necessary)
  • $alphabet - Custom alphabet (must have at least 16 unique characters)

encode(int|array|string ...$numbers): string

Encode one or more numbers into a hash.

  • Returns empty string if encoding fails (e.g., negative numbers)
  • Accepts integers, strings, or arrays
  • Negative numbers are not supported

decode(string $hash): array

Decode a hash back to numbers.

  • Returns empty array if decoding fails
  • Validates by re-encoding and comparing

encodeHex(string $hex): string

Encode a hexadecimal string.

  • Useful for encoding MongoDB ObjectIds or other hex values
  • Returns empty string if hex is invalid

decodeHex(string $hash): string

Decode a hash back to hexadecimal string.

Performance Tips

  1. Reuse Instances: Create one HashId instance and reuse it for multiple operations (shuffle cache builds up)
  2. Keep Salt Consistent: The same salt values benefit from caching across calls
  3. Avoid Excessive Min Length: Large minHashLength values require extra padding operations
  4. Batch Operations: Process multiple encodes/decodes in succession to maximize cache hits
  5. Warm Up Cache: First few operations build the shuffle cache, subsequent operations are much faster

Benchmarks

Real-World Comparison

Compared to other popular libraries (encoding benchmark):

Library Encode Time Speed vs Trac
Trac HashId 0.295s 1.0x (baseline)
Sqids 1.152s 3.9x slower
Hashids 1.386s 4.7x slower

Initialization time comparison:

Library Init Time
Trac HashId 0.0001s
Hashids 0.00017s
Sqids 0.00032s

Internal Benchmarks

Performance metrics (10,000 iterations on PHP 8.4):

  • Single number encoding: ~633,000 ops/sec
  • Multiple numbers encoding: ~263,000 ops/sec
  • Encode + Decode roundtrip: ~87,000 ops/sec
  • With minimum length padding: ~366,000 ops/sec
  • Large numbers: ~259,000 ops/sec
  • Hex encoding: ~482,000 ops/sec

What Makes It Fast?

  1. Shuffle caching - Memoizes shuffled alphabet states (eliminates 90% of shuffle operations)
  2. Native integer math - Uses PHP native integers for typical numbers, only falls back to BCMath for large numbers
  3. String-native operations - Direct string manipulation without unnecessary array conversions
  4. Optimized loops - Character-by-character string operations instead of regex
  5. Smart initialization - Pre-computes and caches alphabet, guards, and separators
  6. Overflow detection - Fast path detection avoids BCMath overhead for 99% of use cases

Testing

composer install

# Run tests
composer test

# Run tests with coverage report
composer test:coverage

# Run mutation testing (requires Xdebug)
composer test:mutate

Important Notes

  1. Not for Security: This library obfuscates IDs but does NOT encrypt them. Do not use for sensitive data.
  2. Negative Numbers: Not supported. Will return empty string.
  3. Consistency: Same input always produces same output with same salt.
  4. Curse Word Avoidance: The Hashids algorithm uses separator characters to reduce the likelihood of common English curse words in output.

License

MIT License