jacyimp / memorable-otp
Human-friendly numeric verification code generator
v0.1.0
2026-09-02 07:02 UTC
Requires
- php: ^8.2
Requires (Dev)
- infection/infection: ^0.31.9
- phpstan/phpstan: ^2.2.12
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^11.5.50
- slevomat/coding-standard: ^8.31
- squizlabs/php_codesniffer: ^4.0.4
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Human-friendly numeric verification codes for PHP, while keeping as many possible codes as practical.
Install
composer require jacyimp/memorable-otp
Usage
use JacyImp\MemorableOtp\MemorableOtp; $code = MemorableOtp::readable(6); // e.g. 159915
Supported lengths: 4–10.
MemorableOtp::readable(4); // e.g. 0112 MemorableOtp::readable(6); // e.g. 159915 MemorableOtp::readable(8); // e.g. 49649440
Readability levels
MemorableOtp::readable(6); // e.g. 159915 MemorableOtp::easy(6); // e.g. 100212 MemorableOtp::veryEasy(6); // e.g. 012013 MemorableOtp::superEasy(6); // e.g. 010203 MemorableOtp::uberEasy(6); // e.g. 121212
| Preset | Possible codes kept | Entropy loss* |
|---|---|---|
readable() |
up to 50% | ≥ 1.0 bit |
easy() |
up to 30% | ≥ 1.7 bits |
veryEasy() |
up to 20% | ≥ 2.3 bits |
superEasy() |
up to 15% | ≥ 2.7 bits |
uberEasy() |
up to 10% | ≥ 3.3 bits |
- Actual values vary slightly by code length.
What it recognizes
121212 repeated chunk
112233 grouped sequence
123456 sequence
654321 descending sequence
123321 mirror
010203 chunk sequence
81818 periodic pattern
10020 round-number structure
Long identical runs are penalized to reduce transcription mistakes:
111111
Explicit preset
use JacyImp\MemorableOtp\MemorableOtp; use JacyImp\MemorableOtp\ReadabilityPreset; $code = MemorableOtp::generate( length: 7, preset: ReadabilityPreset::VeryEasy, ); // e.g. 4015642
Equivalent to:
$code = MemorableOtp::veryEasy(7); // e.g. 4015642
Security
Candidates are generated with cryptographically secure randomness and filtered using rejection sampling.
The first candidate that meets the selected readability threshold is returned. Accepted codes are not ranked against each other.
use JacyImp\MemorableOtp\MemorableOtp; use JacyImp\MemorableOtp\ReadabilityPreset; $security = MemorableOtp::security( length: 7, preset: ReadabilityPreset::UberEasy, ); $security->rawSearchSpace(); $security->acceptedSearchSpace(); $security->entropyBits(); $security->entropyLossBits(); $security->exact;
Normal OTP protections still apply: expiration, attempt limits, rate limiting, one-time use, secure storage, and secure delivery.
Requirements
PHP 8.2+
License
MIT