Deprecating uniqid()

php.internals

AllenJB

6 years ago
Hi all, I'd like to discuss deprecating uniqid() I believe it's dangerously bad a doing "what it says on the tin". New developers still reach for it and do not read the warnings on the manual page (or if they do, don't fully understand how bad it is). For older codebases that still rely on it, a userland replacement can be easily implemented (and could be published on Packagist). I noticed there was an RFC [0][1] brought up 2 years ago, but was never voted on. Does anyone know why this was? [0] https://externals.io/message/102097 [1] https://wiki.php.net/rfc/deprecate-uniqid Is there interest in deprecating this function? If not deprecation, how could it be (further) "improved"? My first thought is to make the "more entropy" option enabled by default (the argument could remain so that it can be disabled by codebases that rely on the lower length and can take the tradeoffs). AllenJB

Ben Ramsey

6 years ago
> On May 2, 2020, at 13:57, AllenJB <php.lists@allenjb.me.uk> wrote: > > Hi all, > > I'd like to discuss deprecating uniqid() > > I believe it's dangerously bad a doing "what it says on the tin". New developers still reach for it and do not read the warnings on the manual page (or if they do, don't fully understand how bad it is). > > For older codebases that still rely on it, a userland replacement can be easily implemented (and could be published on Packagist). > > I noticed there was an RFC [0][1] brought up 2 years ago, but was never voted on. Does anyone know why this was? > > [0] https://externals.io/message/102097 > [1] https://wiki.php.net/rfc/deprecate-uniqid > > Is there interest in deprecating this function? > > If not deprecation, how could it be (further) "improved"? My first thought is to make the "more entropy" option enabled by default (the argument could remain so that it can be disabled by codebases that rely on the lower length and can take the tradeoffs).
Instead of deprecating and removing it, would anyone be opposed to replacing the internals of the function so that it uses `random_bytes()` under the hood, while all other functionality remains the same? Cheers, Ben

Ben Ramsey

6 years ago
> On May 2, 2020, at 14:13, Ben Ramsey <ben@benramsey.com> wrote: > >> On May 2, 2020, at 13:57, AllenJB <php.lists@allenjb.me.uk> wrote: >> >> Hi all, >> >> I'd like to discuss deprecating uniqid() >> >> I believe it's dangerously bad a doing "what it says on the tin". New developers still reach for it and do not read the warnings on the manual page (or if they do, don't fully understand how bad it is). >> >> For older codebases that still rely on it, a userland replacement can be easily implemented (and could be published on Packagist). >> >> I noticed there was an RFC [0][1] brought up 2 years ago, but was never voted on. Does anyone know why this was? >> >> [0] https://externals.io/message/102097 >> [1] https://wiki.php.net/rfc/deprecate-uniqid >> >> Is there interest in deprecating this function? >> >> If not deprecation, how could it be (further) "improved"? My first thought is to make the "more entropy" option enabled by default (the argument could remain so that it can be disabled by codebases that rely on the lower length and can take the tradeoffs). > > > Instead of deprecating and removing it, would anyone be opposed to replacing the internals of the function so that it uses `random_bytes()` under the hood, while all other functionality remains the same?
Of course, if we did this, it would break anyone’s ability to do this: date('r', hexdec(substr(uniqid(), 0, 8))); But I would argue that no one should be relying on these identifiers for date/time purposes. Cheers, Ben

Nikita Popov

6 years ago
On Sat, May 2, 2020 at 9:13 PM Ben Ramsey <ben@benramsey.com> wrote:
> > On May 2, 2020, at 13:57, AllenJB <php.lists@allenjb.me.uk> wrote: > > > > Hi all, > > > > I'd like to discuss deprecating uniqid() > > > > I believe it's dangerously bad a doing "what it says on the tin". New > developers still reach for it and do not read the warnings on the manual > page (or if they do, don't fully understand how bad it is). > > > > For older codebases that still rely on it, a userland replacement can be > easily implemented (and could be published on Packagist). > > > > I noticed there was an RFC [0][1] brought up 2 years ago, but was never > voted on. Does anyone know why this was? > > > > [0] https://externals.io/message/102097 > > [1] https://wiki.php.net/rfc/deprecate-uniqid > > > > Is there interest in deprecating this function? > > > > If not deprecation, how could it be (further) "improved"? My first > thought is to make the "more entropy" option enabled by default (the > argument could remain so that it can be disabled by codebases that rely on > the lower length and can take the tradeoffs). > > > Instead of deprecating and removing it, would anyone be opposed to > replacing the internals of the function so that it uses `random_bytes()` > under the hood, while all other functionality remains the same? >
I believe this has been discussed in the past, and the basic problem is that uniqid() currently only returns 13 hex characters, so we can encode at most 52 bits of entropy without changing the output format. This is insufficient. Changing the format could break assumptions, such as database column sizes. Personally, I would be in favor of deprecating the function. I've run into an issue caused by non-unique uniqid() somewhat recently myself as well. Regards, Nikita

Jakob Givoni

6 years ago
On Sat, May 2, 2020 at 9:58 PM Nikita Popov <nikita.ppv@gmail.com> wrote:
> > On Sat, May 2, 2020 at 9:13 PM Ben Ramsey <ben@benramsey.com> wrote: > > > > On May 2, 2020, at 13:57, AllenJB <php.lists@allenjb.me.uk> wrote: > > > > > > Hi all, > > > > > > I'd like to discuss deprecating uniqid() > > > > > > I believe it's dangerously bad a doing "what it says on the tin". New > > developers still reach for it and do not read the warnings on the manual > > page (or if they do, don't fully understand how bad it is). > > > > > > For older codebases that still rely on it, a userland replacement can be > > easily implemented (and could be published on Packagist). > > > > > > I noticed there was an RFC [0][1] brought up 2 years ago, but was never > > voted on. Does anyone know why this was? > > > > > > [0] https://externals.io/message/102097 > > > [1] https://wiki.php.net/rfc/deprecate-uniqid > > > > > > Is there interest in deprecating this function? > > > > > > If not deprecation, how could it be (further) "improved"? My first > > thought is to make the "more entropy" option enabled by default (the > > argument could remain so that it can be disabled by codebases that rely on > > the lower length and can take the tradeoffs). > > > > > > Instead of deprecating and removing it, would anyone be opposed to > > replacing the internals of the function so that it uses `random_bytes()` > > under the hood, while all other functionality remains the same? > > > > I believe this has been discussed in the past, and the basic problem is > that uniqid() currently only returns 13 hex characters, so we can encode at > most 52 bits of entropy without changing the output format. This is > insufficient. Changing the format could break assumptions, such as database > column sizes. > > Personally, I would be in favor of deprecating the function. I've run into > an issue caused by non-unique uniqid() somewhat recently myself as well. > > Regards, > Nikita
I'm using this function frequently, but I am ok with deprecating it as I think the name is dangerously misleading - basically, anything that mentions "unique" without saying to what, is a misnomer. However, as it's useful to have a function in core that gives you a random string with a fixed length that is unique within some well-defined boundaries, I'd like to be sure there is an easy replacement for the function when the time comes to upgrade php. Ideally something that is guaranteed to be unique within the current php process and takes the same arguments as uniqid. Best, Jakob

Rowan Collins

6 years ago
On 03/05/2020 09:54, Jakob Givoni wrote:
> I'm using this function frequently, but I am ok with deprecating it as > I think the name is dangerously misleading - basically, anything that > mentions "unique" without saying to what, is a misnomer. > However, as it's useful to have a function in core that gives you a > random string with a fixed length that is unique within some > well-defined boundaries, I'd like to be sure there is an easy > replacement for the function when the time comes to upgrade php. > Ideally something that is guaranteed to be unique within the current > php process and takes the same arguments as uniqid.
I definitely think that all deprecations should come with clear guidance of either "use this instead" or "what you're doing is fundamentally wrong". I'm not sure it needs to retain the same arguments, or even the same output format, though, just fit the same use cases. The prefix can be added trivially, and the "hex, dot, numeric" output of the "more entropy" version is not often particularly helpful. A common suggestion is to use binhex(random_bytes($desired_length / 2)), which isn't particularly elegant, and in my experience, the main requirement is "a unique string of printable/alphanumeric characters, so limiting to [0-9a-f] is just limiting entropy for no reason. I wonder if we could add a parameter to random_bytes, or an accompanying function, that would return only alphanumeric characters; or perhaps accept a range of characters to allow in some form. Regards,
-- Rowan Tommins (né Collins) [IMSoP]

Jakob Givoni

6 years ago
On Sun, May 3, 2020 at 2:57 PM Rowan Tommins <rowan.collins@gmail.com> wrote:
> > A common suggestion is to use binhex(random_bytes($desired_length / 2)), > which isn't particularly elegant, and in my experience, the main > requirement is "a unique string of printable/alphanumeric characters, so > limiting to [0-9a-f] is just limiting entropy for no reason. >
Yes, a base_convert(..., 16, 32) around that would help but I'd really prefer a simple function than a chain of 3 functions (even if we had Larry's pipe operator :-p)

Andreas Heigl

6 years ago
Hey Ben, hey all Am 02.05.20 um 21:13 schrieb Ben Ramsey:
>> On May 2, 2020, at 13:57, AllenJB <php.lists@allenjb.me.uk> wrote: >> >> Hi all, >> >> I'd like to discuss deprecating uniqid() >> >> I believe it's dangerously bad a doing "what it says on the tin". New developers still reach for it and do not read the warnings on the manual page (or if they do, don't fully understand how bad it is). >> >> For older codebases that still rely on it, a userland replacement can be easily implemented (and could be published on Packagist). >> >> I noticed there was an RFC [0][1] brought up 2 years ago, but was never voted on. Does anyone know why this was? >> >> [0] https://externals.io/message/102097 >> [1] https://wiki.php.net/rfc/deprecate-uniqid >> >> Is there interest in deprecating this function? >> >> If not deprecation, how could it be (further) "improved"? My first thought is to make the "more entropy" option enabled by default (the argument could remain so that it can be disabled by codebases that rely on the lower length and can take the tradeoffs). > > > Instead of deprecating and removing it, would anyone be opposed to replacing the internals of the function so that it uses `random_bytes()` under the hood, while all other functionality remains the same?
I'D rather deprecate it and give a clear advice on what to use instead (i.e. in the docs) than changing the internal behaviour and break code. As replacement I could think of showing people the way to UUIDs. As the function itself was never intended for cryptographically secure values I would not see random_* functions or the like as a replacement. My 0.02 € Cheers Andreas
-- ,,, (o o) +---------------------------------------------------------ooO-(_)-Ooo-+ | Andreas Heigl | | mailto:andreas@heigl.org N 50°22'59.5" E 08°23'58" | | http://andreas.heigl.org http://hei.gl/wiFKy7 | +---------------------------------------------------------------------+ | http://hei.gl/root-ca | +---------------------------------------------------------------------+

Rowan Collins

6 years ago
On Mon, 4 May 2020 at 06:27, Andreas Heigl <andreas@heigl.org> wrote:
> > As replacement I could think of showing people the way to UUIDs. >
Although the name sounds similar, I don't think UUID would be a good replacement for uniqid(). In my experience, it's used for things like generating ID attributes for HTML elements, or suffixes for table names, or even file names; applications that really just need a few alphanumeric characters that are different each time.
> As the function itself was never intended for cryptographically secure > values I would not see random_* functions or the like as a replacement. >
Firstly, while everyone *should* understand the phrase "cryptographically secure", I don't think most users do. Despite the warning in the manual, I would put money on people using uniqid() for things that really should use "strong" randomness. Secondly, is there actually a *disadvantage* to using cryptographically secure randomness when you don't need it? Speed? There's no advice in the manual for random_int or random_bytes saying *not* to use them, and their names seem deliberately chosen to imply they are the go-to functions for randomness. The only downside I can see suggesting something like random_string(13, '0-9a-f') as a direct replacement for uniqid() is that without a time input it might happen to generate the same string twice in a request. On the other hand, uniqid actually disclaims any guarantee of uniqueness anyway. Regards,
-- Rowan Tommins [IMSoP]

Niklas Keller

6 years ago
Rowan Tommins <rowan.collins@gmail.com> schrieb am Mo., 4. Mai 2020, 10:59:
> On Mon, 4 May 2020 at 06:27, Andreas Heigl <andreas@heigl.org> wrote: > > > > > As replacement I could think of showing people the way to UUIDs. > > > > > Although the name sounds similar, I don't think UUID would be a good > replacement for uniqid(). In my experience, it's used for things like > generating ID attributes for HTML elements, or suffixes for table names, or > even file names; applications that really just need a few alphanumeric > characters that are different each time. >
Seems like UUIDs would be a good fit for all of these.
> > > As the function itself was never intended for cryptographically secure > > values I would not see random_* functions or the like as a replacement. > > > > > Firstly, while everyone *should* understand the phrase "cryptographically > secure", I don't think most users do. Despite the warning in the manual, I > would put money on people using uniqid() for things that really should use > "strong" randomness. > > Secondly, is there actually a *disadvantage* to using cryptographically > secure randomness when you don't need it? Speed? There's no advice in the > manual for random_int or random_bytes saying *not* to use them, and their > names seem deliberately chosen to imply they are the go-to functions for > randomness. > > The only downside I can see suggesting something like random_string(13, > '0-9a-f') as a direct replacement for uniqid() is that without a time input > it might happen to generate the same string twice in a request. On the > other hand, uniqid actually disclaims any guarantee of uniqueness anyway. >
UUIDs have enough length to make collisions practically irrelevant, so again, they seem to be the best replacement. Best, Niklas Regards,

Peter Bowyer

6 years ago
On Tue, 5 May 2020 at 07:38, Niklas Keller <me@kelunik.com> wrote:
> Rowan Tommins <rowan.collins@gmail.com> schrieb am Mo., 4. Mai 2020, > 10:59: > > Although the name sounds similar, I don't think UUID would be a good > > replacement for uniqid(). In my experience, it's used for things like > > generating ID attributes for HTML elements, or suffixes for table names, > or > > even file names; applications that really just need a few alphanumeric > > characters that are different each time. > > > > Seems like UUIDs would be a good fit for all of these. >
For file names, absolutely. In many cases they have to be unique across all processes, and that's important. For the others I say a UUID is only a good replacement if taking a substring of a UUID is going to be unique. Take HTML element IDs. My experience is UUIDs (random data) doesn't compress well, and so shorter unique strings are preferable (also for reading the HTMl when debugging). The number of elements you're adding IDs to matters: if you add 10 then the UUID overhead is negligible; if you're adding to thousands it's different. For table name suffixes (if needed), the maximum length of a table name is 64 characters in MySQL. It's easier to cope with all systems if the table name pre-suffix can be more than 28 characters (27 if you put a separator between the table name and the suffix) For these reasons, I support adding a nice way to generate semi-unique data, preferably of user-defined length, and that doesn't have the drawbacks of uniqid(). And deprecating uniqid(). Peter

Rowan Collins

6 years ago
On Tue, 5 May 2020 at 08:52, Peter Bowyer <phpmailinglists@gmail.com> wrote:
> > On Tue, 5 May 2020 at 07:38, Niklas Keller <me@kelunik.com> wrote: > >> Rowan Tommins <rowan.collins@gmail.com> schrieb am Mo., 4. Mai 2020, >> 10:59: >> > Although the name sounds similar, I don't think UUID would be a good >> > replacement for uniqid(). In my experience, it's used for things like >> > generating ID attributes for HTML elements, or suffixes for table >> names, or >> > even file names; applications that really just need a few alphanumeric >> > characters that are different each time. >> >> Seems like UUIDs would be a good fit for all of these. >> > > For file names, absolutely. In many cases they have to be unique across > all processes, and that's important. For the others I say a UUID is only a > good replacement if taking a substring of a UUID is going to be unique. >
As well as being nearly 3 times as long as the current uniqid() output, a UUID is generally formatted with hyphens, which may be disallowed or require careful quoting in various contexts. If you have to strip those out, or otherwise manipulate the result to fit the use case, you've failed at the original aim of having a single function that doesn't need further processing. (Leaving aside the fact that we don't actually have any UUID functions in core.) Regards,
-- Rowan Tommins [IMSoP]

Arvids Godjuks

6 years ago
On Tue, 5 May 2020 at 10:26, Rowan Tommins <rowan.collins@gmail.com> wrote:
> On Tue, 5 May 2020 at 08:52, Peter Bowyer <phpmailinglists@gmail.com> > wrote: > > > > > On Tue, 5 May 2020 at 07:38, Niklas Keller <me@kelunik.com> wrote: > > > >> Rowan Tommins <rowan.collins@gmail.com> schrieb am Mo., 4. Mai 2020, > >> 10:59: > >> > Although the name sounds similar, I don't think UUID would be a good > >> > replacement for uniqid(). In my experience, it's used for things like > >> > generating ID attributes for HTML elements, or suffixes for table > >> names, or > >> > even file names; applications that really just need a few alphanumeric > >> > characters that are different each time. > >> > >> Seems like UUIDs would be a good fit for all of these. > >> > > > > For file names, absolutely. In many cases they have to be unique across > > all processes, and that's important. For the others I say a UUID is only > a > > good replacement if taking a substring of a UUID is going to be unique. > > > > > As well as being nearly 3 times as long as the current uniqid() output, a > UUID is generally formatted with hyphens, which may be disallowed or > require careful quoting in various contexts. If you have to strip those > out, or otherwise manipulate the result to fit the use case, you've failed > at the original aim of having a single function that doesn't need further > processing. (Leaving aside the fact that we don't actually have any UUID > functions in core.) > > Regards, > -- > Rowan Tommins > [IMSoP] >
The same notion here. UUID's and random_bytes sometimes are overkill, too slow or you can just exhaust the random source. I have a use-case where I needed exactly the way uniqid worked (with more_entropy = true) - a serial incrementing random value that I needed to create for 20-30 thousand items in one request. It was fast, efficient and there was absolutely no need to have a truly random value. And it needed to be human-readable easily because it was also sent via SMS in some cases. So in my opinion, a better replacement for uniqid is needed - have it generate a bigger string with more entropy and better underline algorithm, but it being time-based should be a thing stiff. And do not call it a "random_string" or something, cause it's not that :) Thanks!
-- Arvīds Godjuks +371 26 851 664 arvids.godjuks@gmail.com Skype: psihius Telegram: @psihius https://t.me/psihius

Rowan Collins

6 years ago
On 5 May 2020 09:42:19 BST, Arvids Godjuks <arvids.godjuks@gmail.com> wrote:
>So in my opinion, a better replacement for uniqid is needed - have it >generate a bigger string with more entropy and better underline algorithm, >but it being time-based should be a thing stiff. And do not call it a >"random_string" or something, cause it's not that :)
A question just got posted on Stack Overflow asking for pretty much exactly what we've been discussing: https://stackoverflow.com/q/61634022/157957 You're right that the requirements for "random" and "unique" are distinct. Perhaps what we need is a unique_string function that allows you to specify the format (length and some control over allowed characters) and uses a mix of randomness and time (perhaps using the same time source as hrtime()?). Then uniqid() could be deprecated, and anyone relying on its exact format could write a polyfill, while people wanting other formats wouldn't need to mess around with binhex, hexdec, etc. Regards,
-- Rowan Tommins [IMSoP]

Dan Ackroyd

6 years ago
On Wed, 6 May 2020 at 13:34, Rowan Tommins <rowan.collins@gmail.com> wrote:
> > On 5 May 2020 09:42:19 BST, Arvids Godjuks <arvids.godjuks@gmail.com> wrote: > >So in my opinion, a better replacement for uniqid is needed - > > You're right that the requirements for "random" and "unique" are distinct. Perhaps what we need is a unique_string function that allows you to specify the format (length and some control over allowed characters) and uses
This is a problem that would be better solved in userland rather than trying to design and evolve inside core PHP. And already has a very good solution: https://hashids.org/php/ That library is, in my opinion, a much better solution for the vast majority of people who are (mis)using uniqid. cheers Dan Ack

Nikita Popov

6 years ago
On Wed, May 6, 2020 at 2:34 PM Rowan Tommins <rowan.collins@gmail.com> wrote:
> On 5 May 2020 09:42:19 BST, Arvids Godjuks <arvids.godjuks@gmail.com> > wrote: > >So in my opinion, a better replacement for uniqid is needed - have it > >generate a bigger string with more entropy and better underline algorithm, > >but it being time-based should be a thing stiff. And do not call it a > >"random_string" or something, cause it's not that :) > > > A question just got posted on Stack Overflow asking for pretty much > exactly what we've been discussing: > https://stackoverflow.com/q/61634022/157957 > > You're right that the requirements for "random" and "unique" are distinct. > Perhaps what we need is a unique_string function that allows you to specify > the format (length and some control over allowed characters) and uses a mix > of randomness and time (perhaps using the same time source as hrtime()?). > > Then uniqid() could be deprecated, and anyone relying on its exact format > could write a polyfill, while people wanting other formats wouldn't need to > mess around with binhex, hexdec, etc. >
A possible candidate for this would be ULID (https://github.com/ulid/spec), which is basically timestamp + random + base32 encoding. The timestamp part makes ULIDs approximately lexicographically orderable, the random part makes sure things are unique when generated in parallel and the base32 encoding avoids people having to deal with raw binary data. Regards, Nikita

Niklas Keller

6 years ago
Hey Allen, there's been discussion on whether we should deprecate or replace its functionality. Without changing the output format, it's impossible to have enough entropy. Without consensus on the best way forward, I've just never cared to put this to a vote. I'll happily collaborate on moving this RFC forward for PHP 8. Best, Niklas Am Sa., 2. Mai 2020 um 20:57 Uhr schrieb AllenJB <php.lists@allenjb.me.uk>: