PikaID is a tiny PHP library that creates unique, short, and sortable IDs β
a modern alternative to UUIDs for your databases, APIs, and distributed systems.
Imagine youβre building a web app where users can post messages or create orders.
Each new item needs a unique ID so your system can recognize it.
If you use normal numbers (1, 2, 3β¦), you can have conflicts when several servers create data at the same time.
If you use UUIDs, you get long, messy IDs that are hard to read and donβt follow creation time.
PikaID solves this:
- Every new ID is unique, even if many servers create them at once.
- IDs are short, so they look clean in URLs or logs.
- They are time-ordered, so when you list data, the newest appears last or first automatically.
You can use PikaID to:
- Identify users, orders, invoices, or API resources.
- Name uploaded files safely.
- Tag events or logs across distributed systems.
In short: PikaID gives you clean, safe, and sortable IDs for anything that needs a unique reference.
Small Β· Sortable Β· Secure ID generator
This is the official PHP implementation. Fully compliant with v1.0.1.
Pikaid is a 26-character, lowercase Base36 identifier, composed of:
- 7-character timestamp (seconds since epoch)
- 19-character cryptographically secure randomness
Itβs a modern, compact alternative to UUID and ULID:
- Lexicographically sortable
- Collision-resistant
- Compact binary form (
BINARY(17))
See the full technical specs and benchmarks at pikaid/pikaid-specs
- PHP 7.4+ (PHP 8 recommended)
ext-gmp(recommended for best performance) orext-bcmath(optional)- If neither extension is installed, a pure-PHP fallback is used.
Install via Composer:
composer require pikaid/pikaid-phpInclude Composer's autoloader in your project:
require 'vendor/autoload.php';<?php
use Pikaid\Pikaid;
// Generate a new Pikaid string
$id = Pikaid::generate();
echo "ID: $id\n"; // e.g. 0swct4q01ch83h91onl6l47vb6
// Validate
if (Pikaid::isValid($id)) {
echo "Valid ID!\n";
}
// Parse components
$data = Pikaid::parse($id);
echo "Timestamp: " . $data['timestamp']->format('Y-m-d H:i:s') . " UTC\n";
echo "Randomness (hex): {$data['randomness']}\n";Generate a new 26-character string ID.
- Layout:
[7 chars timestamp][19 chars randomness] - Sortable by second.
$id = Pikaid::generate();Generate the binary form directly (BINARY(17)).
- Layout:
[5 bytes timestamp (uint40, big-endian)][12 bytes entropy].
$bin = Pikaid::generateBinary();Convert a string ID to its binary (17 bytes) representation.
Throws InvalidArgumentException if the input is not a valid 26-character Pikaid or if the timestamp is out of range.
$bin = Pikaid::toBinary($id);Convert binary (17 bytes) back into a 26-char string.
Throws InvalidArgumentException if the binary length isnβt exactly 17 bytes.
$id = Pikaid::fromBinary($bin);Check if the given string is a valid Pikaid.
- Must be 26 chars long
- Must match regex:
/^[0-9a-z]{26}$/
if (Pikaid::isValid($id)) {
echo "Valid format!";
}Parse a string ID into its components:
timestampβDateTimeImmutable(UTC)randomnessβ lowercase hex string (24 chars = 12 bytes)
Throws InvalidArgumentException on invalid input.
$info = Pikaid::parse($id);
/*
[
'timestamp' => DateTimeImmutable(...),
'randomness' => 'a1b2c3d4e5f6a7b8c9d0e1f2'
]
*/Generate a string ID for a specific timestamp (seconds precision).
$id = Pikaid::fromDateTime(new DateTimeImmutable('@1234567890'));- String and binary representations sort lexicographically by second:
$id1 = Pikaid::generate();
sleep(1);
$id2 = Pikaid::generate();
assert($id1 < $id2); // always truePikaid is designed to be compact and index-friendly, with a predictable layout:
| Representation | Size | Sortable | Recommended for |
|---|---|---|---|
| BINARY(17) | 17B | Yes | High-performance storage and indexing |
| CHAR(26) | 26B | Yes | Readability in SQL, debugging, or logs |
Binary form stores exactly 17 bytes:
[5 bytes timestamp (uint40, big-endian)][12 bytes entropy]
CREATE TABLE pika_events (
id BINARY(17) NOT NULL, -- Primary key
payload JSON NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-- Optional: Extract timestamp for range queries and indexing
ts_seconds BIGINT UNSIGNED
AS ( ORD(SUBSTR(id, 1, 1)) * 4294967296
+ CONV(HEX(SUBSTR(id, 2, 4)), 16, 10) ) STORED,
PRIMARY KEY (id),
KEY idx_ts_seconds (ts_seconds),
KEY idx_created_at (created_at)
) ENGINE=InnoDB;use Pikaid\Pikaid;
// Generate binary ID and store it
$binId = Pikaid::generateBinary();
$stmt = $pdo->prepare('INSERT INTO pika_events (id, payload) VALUES (?, ?)');
$stmt->execute([$binId, json_encode(['event' => 'signup'])]);$stmt = $pdo->query('SELECT id, ts_seconds FROM pika_events ORDER BY id ASC');
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$stringId = Pikaid::fromBinary($row['id']); // Convert back to string
echo $stringId . ' @ ' . gmdate('c', (int)$row['ts_seconds']) . PHP_EOL;
}- Small index size = better performance
- Binary comparison matches chronological order
- Perfect for
PRIMARY KEYor clustered indexes
If you need IDs to remain human-readable directly in SQL queries, store the string form.
CREATE TABLE pika_events_str (
id CHAR(26) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, -- Primary key
payload JSON NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-- Optional: Extract timestamp for range queries and indexing
ts_seconds BIGINT UNSIGNED
AS (CONV(SUBSTR(id, 1, 7), 36, 10)) STORED,
PRIMARY KEY (id),
KEY idx_ts_seconds (ts_seconds),
KEY idx_created_at (created_at)
) ENGINE=InnoDB;use Pikaid\Pikaid;
$id = Pikaid::generate();
$stmt = $pdo->prepare('INSERT INTO pika_events_str (id, payload) VALUES (?, ?)');
$stmt->execute([$id, json_encode(['event' => 'login'])]);$stmt = $pdo->query('SELECT id, ts_seconds FROM pika_events_str ORDER BY id ASC');
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
echo $row['id'] . ' @ ' . gmdate('c', (int)$row['ts_seconds']) . PHP_EOL;
}- Slightly larger storage and index compared to
BINARY(17) - Ideal for debugging or manual inspection of IDs
Both BINARY(17) and CHAR(26) maintain natural chronological order:
$id1 = Pikaid::generate();
sleep(1);
$id2 = Pikaid::generate();
assert($id1 < $id2); // String order is chronological
assert(strcmp(Pikaid::toBinary($id1), Pikaid::toBinary($id2)) < 0); // Binary order tooPikaid is released under the MIT License.

