{"id":23434922,"url":"https://github.com/gpslab/base64uid","last_synced_at":"2025-04-13T03:19:53.551Z","repository":{"id":62512160,"uuid":"94885299","full_name":"gpslab/base64uid","owner":"gpslab","description":"Generate UID like YouTube","archived":false,"fork":false,"pushed_at":"2020-01-14T15:15:30.000Z","size":97,"stargazers_count":68,"open_issues_count":0,"forks_count":8,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-10T15:58:20.279Z","etag":null,"topics":["php","uid"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gpslab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-06-20T11:43:49.000Z","updated_at":"2025-01-14T02:58:54.000Z","dependencies_parsed_at":"2022-11-02T13:15:32.230Z","dependency_job_id":null,"html_url":"https://github.com/gpslab/base64uid","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gpslab%2Fbase64uid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gpslab%2Fbase64uid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gpslab%2Fbase64uid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gpslab%2Fbase64uid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gpslab","download_url":"https://codeload.github.com/gpslab/base64uid/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248658252,"owners_count":21140910,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["php","uid"],"created_at":"2024-12-23T12:34:00.361Z","updated_at":"2025-04-13T03:19:53.527Z","avatar_url":"https://github.com/gpslab.png","language":"PHP","readme":"[![Latest Stable Version](https://img.shields.io/packagist/v/gpslab/base64uid.svg?maxAge=3600\u0026label=stable)](https://packagist.org/packages/gpslab/base64uid)\n[![Total Downloads](https://img.shields.io/packagist/dt/gpslab/base64uid.svg?maxAge=3600)](https://packagist.org/packages/gpslab/base64uid)\n[![Build Status](https://img.shields.io/travis/gpslab/base64uid.svg?maxAge=3600)](https://travis-ci.org/gpslab/base64uid)\n[![Coverage Status](https://img.shields.io/coveralls/gpslab/base64uid.svg?maxAge=3600)](https://coveralls.io/github/gpslab/base64uid?branch=master)\n[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/gpslab/base64uid.svg?maxAge=3600)](https://scrutinizer-ci.com/g/gpslab/base64uid/?branch=master)\n[![SensioLabs Insight](https://img.shields.io/sensiolabs/i/0feb22b7-b64d-462d-b8ba-da49e548be70.svg?maxAge=3600\u0026label=SLInsight)](https://insight.sensiolabs.com/projects/0feb22b7-b64d-462d-b8ba-da49e548be70)\n[![StyleCI](https://styleci.io/repos/94885299/shield?branch=master)](https://styleci.io/repos/94885299)\n[![License](https://img.shields.io/packagist/l/gpslab/base64uid.svg?maxAge=3600)](https://github.com/gpslab/base64uid)\n\n# Base64 UID\n\nGenerate UID like YouTube.\n\n## Introduction\n\nThe library generates a unique identifier consisting of 64 characters and a length of 10 characters *(you can change\nthe length of the identifier).* This gives us 64\u003csup\u003e10\u003c/sup\u003e = 2\u003csup\u003e60\u003c/sup\u003e = 1 152 921 504 606 846 976 combinations.\n\nTo represent this number, imagine that in order to get all possible values of identifiers with a length of **10**\ncharacters and generating an ID every microsecond, it takes **36 559** years.\n\n[UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) works on the same principle, but its main drawback\nis that it's too long. It is not convenient to use it as a public identifier, for example in the URL. In order to get\nthe same number of combinations as the UUID, we need 2\u003csup\u003e128\u003c/sup\u003e = 64\u003csup\u003e21\u003c/sup\u003e lines 21 characters long, that\nis, almost 2 times shorter than the UUID (37 characters). And if we take an identifier of the same length as the UUID,\nthen we get 64\u003csup\u003e37\u003c/sup\u003e = 2\u003csup\u003e222\u003c/sup\u003e against 2\u003csup\u003e128\u003c/sup\u003e for the UUID.\n\nThe most important advantage of this approach is that you ourselves control the number of combinations by changing the\nlength of the string and the character set. This will optimize the length of the identifier for your business\nrequirements.\n\n## Collision\n\nThe probability of collision of identifiers can be calculated by the formula:\n\n```\np(n) ≈ 1 - exp(N * (ln(N - 1) - ln(N - n)) + n * (ln(N - n) - ln(N) - 1) - (ln(N - 1) - ln(N) - 1))\n```\n\nWhere\n * *N* - number of possible options;\n * *n* - number of generated keys.\n\nTake an identifier with a length of 11 characters, like YouTube, which will give us *N* = 64\u003csup\u003e11\u003c/sup\u003e =\n2\u003csup\u003e66\u003c/sup\u003e and we will get:\n\n * p(2\u003csup\u003e25\u003c/sup\u003e) ≈ 7.62 * 10\u003csup\u003e-6\u003c/sup\u003e\n * p(2\u003csup\u003e30\u003c/sup\u003e) ≈ 0.0077\n * p(2\u003csup\u003e36\u003c/sup\u003e) ≈ 0.9999\n\nThat is, by generating 2\u003csup\u003e36\u003c/sup\u003e = 68 719 476 736 identifiers you are almost guaranteed to get a collision.\n\n*For calculations with large numbers, i recommend [this](https://web2.0calc.com/) online calculator.*\n\n## Installation\n\nPretty simple with [Composer](http://packagist.org), run:\n\n```sh\ncomposer require gpslab/base64uid\n```\n\n## Usage\n\n```php\nuse GpsLab\\Component\\Base64UID\\Base64UID;\n\n$uid = Base64UID::generate(); // iKtwBpOH2E\n```\n\nWith length 6 chars (64\u003csup\u003e6\u003c/sup\u003e = 68 719 476 736 combinations).\n\n```php\n$uid = Base64UID::generate(6); // nWzfgA\n```\n\nThe floating-length identifier will give more unique identifiers\n(64\u003csup\u003e8\u003c/sup\u003e + 64\u003csup\u003e9\u003c/sup\u003e + 64\u003csup\u003e10\u003c/sup\u003e = 1 171 217 378 093 039 616 combinations).\n\n```php\n$uid = Base64UID::generate(random_int(8, 10));\n```\n\nYou can customize charset.\n\n```php\n$charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/';\n$uid = Base64UID::generate(11, $charset);\n\n$charset = '0123456789abcdef';\n$uid = Base64UID::generate(11, $charset);\n```\n\n### Other algorithms for generate UID\n\n#### Random char\n\nGenerate random characters of a finite UID from a charset.\n\n```php\n$generator = new RandomCharGenerator();\n$uid = $generator-\u003egenerate(); // iKtwBpOH2E\n```\n\nLimit the length of the UID and the charset.\n\n```php\n$charset = '0123456789abcdef';\n$generator = new RandomCharGenerator(6, $charset);\n$uid = $generator-\u003egenerate(); // fa6c7d\n```\n\n#### Random bytes\n\nGenerate random bytes and encode it in Base64.\n\n```php\n$generator = new RandomBytesGenerator();\n$uid = $generator-\u003egenerate(); // YCfGKBxd9k4\n```\n\n```php\n$generator = new RandomBytesGenerator(5);\n$uid = $generator-\u003egenerate(); // Mm7dpkM\n```\n\n#### Encoded random bits\n\nGenerate bitmap with random bits and encode it in Base64.\nThe bitmap length is 64 bits and it require 64-bit mode of processor architecture.\n\n```php\n$binary_generator = new RandomBinaryGenerator(32);\n$encoder = new HexToBase64BitmapEncoder();\n$generator = new EncodeBitmapGenerator($binary_generator, $encoder);\n$uid = $generator-\u003egenerate(); // 7MWx2BuWJUw\n```\n\n#### Encoded bitmap of time\n\nGenerate bitmap with current time in microseconds and encode it in Base64.\nThe bitmap length is 64 bits and it require 64-bit mode of processor architecture.\n\n```php\n$binary_generator = new TimeBinaryGenerator();\n$encoder = new HexToBase64BitmapEncoder();\n$generator = new EncodeBitmapGenerator($binary_generator, $encoder);\n$uid = $generator-\u003egenerate(); // koLfRhzAoI0\n$uid = $generator-\u003egenerate(); // zALfRhzAovg\n$uid = $generator-\u003egenerate(); // 18LfRhzAoQw\n```\n\nGenerated bitmap has a structure:\n\n```\n{first bit}{random prefix}{current time}{random suffix}\n```\n\n* *first bit* - bitmap limiter for fixed size of bitmap;\n* *prefix* - random bits used in prefix of bitmap. The length of the generated bits can be configured from `$prefix_length`;\n* *time* - bits of current time in microseconds. \n* *suffix* - random bits used in suffix of bitmap. The length is calculated from `64 - 1 - $prefix_length - $time_length`.\n\nResponsibly select the number of bits allocated to store the current time. The `$time_length` defines the limit of the\nstored date:\n\n| Bits limit | Maximum available bitmap | Unix Timestamp | Date |\n|---|---|---|---|\n| 40-bits | `1111111111111111111111111111111111111111`      | `1099511627775`  | 2004-11-03 19:53:48 (UTC) |\n| 41-bits | `11111111111111111111111111111111111111111`     | `2199023255551`  | 2039-09-07 15:47:36 (UTC) |\n| 42-bits | `111111111111111111111111111111111111111111`    | `4398046511103`  | 2109-05-15 07:35:11 (UTC) |\n| 43-bits | `1111111111111111111111111111111111111111111`   | `8796093022207`  | 2248-09-26 15:10:22 (UTC) |\n| 44-bits | `11111111111111111111111111111111111111111111`  | `17592186044415` | 2527-06-23 06:20:44 (UTC) |\n| 45-bits | `111111111111111111111111111111111111111111111` | `35184372088831` | 3084-12-12 12:41:29 (UTC) |\n\nTo reduce the size of the saved time, you can use a `$time_offset` that allows you to move the starting point of time:\n\n| Offset microseconds | Offset date | Maximum available date for 41-bits |\n|---|---|---|\n| 0             | 1970-01-01 00:00:00 (UTC) | 2039-09-07 15:47:36 (UTC) |\n| 1577836800000 | 2020-01-01 00:00:00 (UTC) | 2089-09-06 15:47:36 (UTC) |\n\n#### Encoded bitmap of floating time\n\nIt is similar to the previous generator `TimeBinaryGenerator`, but the position with bits of the current time is\nfloating. That is, the length of the prefix and suffix is randomly generated each time. Simultaneously generated\nidentifiers have less similarity, but the likelihood of collision increases.\n\n```php\n$binary_generator = new FloatingTimeGenerator();\n$encoder = new HexToBase64BitmapEncoder();\n$generator = new EncodeBitmapGenerator($binary_generator, $encoder);\n$uid = $generator-\u003egenerate(); // 5mqhb6MPH7g\n$uid = $generator-\u003egenerate(); // kFvow8joJys\n$uid = $generator-\u003egenerate(); // 8QRC30YeP3E\n```\n\n#### Snowflake-id\n\nSnowflake-id use time in microseconds and generator id. This allows you to customize the\ngenerator to your environment and reduce the likelihood of a collision, but the identifiers are very similar to each\nother and the identifier reveals the scheme of your internal infrastructure. Snowflake-id used in Twitter, Instagram, etc. \n\n```php\n$generator_id = 0; // value 0-1023\n$binary_generator = new SnowflakeGenerator($generator_id);\n$encoder = new HexToBase64BitmapEncoder();\n$generator = new EncodeBitmapGenerator($binary_generator, $encoder);\n$uid = $generator-\u003egenerate(); // gBFKQeuAAAA\n$uid = $generator-\u003egenerate(); // gBFKQeuAAAE\n$uid = $generator-\u003egenerate(); // gBFKQevAAAA\n```\n\n## Domain-driven design (DDD)\n\nHow to usage in your [domain](https://en.wikipedia.org/wiki/Domain-driven_design).\n\nFor example create a `ArticleId` ValueObject:\n\n```php\nclass ArticleId\n{\n    private $id;\n\n    public function __construct(string $id)\n    {\n        $this-\u003eid = $id;\n    }\n\n    public function id()\n    {\n        return $this-\u003eid;\n    }\n}\n```\n\nRepository interface for Article:\n\n```php\ninterface ArticleRepository\n{\n    public function nextId();\n\n    // more methods ...\n}\n```\n\nConcrete repository for Article:\n\n```php\nuse GpsLab\\Component\\Base64UID\\Base64UID;\n\nclass ConcreteArticleRepository implements ArticleRepository\n{\n    public function nextId()\n    {\n        return new ArticleId(Base64UID::generate());\n    }\n\n    // more methods ...\n}\n```\n\nNow we can create a new entity with `ArticleId`:\n\n```php\n$article = new Article(\n    $repository-\u003enextId(),\n    // more article parameters ...\n);\n```\n\n## License\n\nThis bundle is under the [MIT license](http://opensource.org/licenses/MIT). See the complete license in the file: LICENSE\n","funding_links":[],"categories":["Repository app"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgpslab%2Fbase64uid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgpslab%2Fbase64uid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgpslab%2Fbase64uid/lists"}