I'm trying to create globally-unique identifiers in Javascript. I'm not sure what routines are available on all browsers, how "random" and seeded the built-in random number generator is, etc..
The GUID / UUID should be at least 32 characters and should stay in the ASCII range to avoid trouble when passing them around.
Source: Tips4all
There have been a couple attempts at this. The question is: do you want actual GUIDs, or just random numbers that look like GUIDs? It's easy enough to generate random numbers. From http://note19.com/2007/05/27/javascript-guid-generator/:
ReplyDeletefunction S4() {
return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
}
function guid() {
return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
}
However, note in the comments that such values are not genuine GUIDs. There's no way to generate real GUIDs in Javascript, because they depend on properties of the local computer that browsers do not expose. You'll need to use OS-specific services like ActiveX: http://p2p.wrox.com/topicindex/20339.htm
Group to one function:
function guidGenerator() {
var S4 = function() {
return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
};
return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
}
Use:
guidGenerator();
For an rfc4122 version 4 compliant solution, this one-liner(ish) solution is the most compact I could come up with.:
ReplyDelete'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
E.g:
>>> 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {var r = Math.random()*16|0,v=c=='x'?r:r&0x3|0x8;return v.toString(16);});
"3bce4931-6c75-41ab-afe0-2ec108a30860"
Here's some code based on RFC 4122, section 4.4 (Algorithms for Creating a UUID from Truly Random or Pseudo-Random Number).
ReplyDeletefunction createUUID() {
// http://www.ietf.org/rfc/rfc4122.txt
var s = [];
var hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = "-";
var uuid = s.join("");
return uuid;
}
There's a nice compact function for creating rfc4122-compliant random UUIDs posted on my blog at:
ReplyDeletehttp://www.broofa.com/2008/09/javascript-uuid-function/
Math.uuid.js is small (~400bytes), and has no dependencies on other libs, so can drop into just about any JS project. It can be used to produce either RFC4122-compliant v4 (random) uuids, or more compact, non-standard IDs of arbitrary length and base. For example:
>>> Math.uuid() // RFC4122 v4 UUID
"4FAC90E7-8CF1-4180-B47B-09C3A246CB67"
>>> Math.uuid(17) // 17 digits, base 62 (0-9,a-Z,A-Z)
"GaohlDbGYvOKd11p2"
>>> Math.uuid(5, 10) // 5 digits, base 10
"84274"
>>> Math.uuid(8, 16) // 8 digits, base 16
"19D954C3"
P.S. That blog post also links to a test page that shows the number of possible UUIDs there are for a variety of arguments, and that includes a performance test for those that care about that sort of thing.
A web service would be useful.
ReplyDeleteQuick Google found: http://www.hoskinson.net/GuidGenerator/
Can't vouch for this implementation, but SOMEONE must publish a bonafide GUID generator.
With such a web service, you could develop a REST web interface that consumes the GUID web service, and serves it through AJAX to javascript in a browser.
Here's a solution dated Oct. 9, 2011 from a comment by user jed at https://gist.github.com/982883:
ReplyDeleteUUIDv4 = function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}
This accomplishes the same goal as the current highest-rated answer, but in 50+ fewer bytes by exploiting coercion, recursion, and exponential notation. For those curious how it works, here's the annotated form of an older version of the function:
UUIDv4 =
function b(
a // placeholder
){
return a // if the placeholder was passed, return
? ( // a random number from 0 to 15
a ^ // unless b is 8,
Math.random() // in which case
* 16 // a random number from
>> a/4 // 8 to 11
).toString(16) // in hexadecimal
: ( // or otherwise a concatenated string:
[1e7] + // 10000000 +
-1e3 + // -1000 +
-4e3 + // -4000 +
-8e3 + // -80000000 +
-1e11 // -100000000000,
).replace( // replacing
/[018]/g, // zeroes, ones, and eights with
b // random hex digits
)
}
From good ol' wikipedia there's a link to a javascript implementation of UUID.
ReplyDeleteIt looks fairly elegant, and could perhaps be improved by salting with a hash of the client's IP address. This hash could perhaps be inserted into the html document server-side for use by the client-side javascript.
UPDATE : The original site has had a shuffle, here is the updated version
This create version 4 UUID (created from pseudo random numbers) :
ReplyDeletefunction uuid()
{
var chars = '0123456789abcdef'.split('');
var uuid = [], rnd = Math.random, r;
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
uuid[14] = '4'; // version 4
for (var i = 0; i < 36; i++)
{
if (!uuid[i])
{
r = 0 | rnd()*16;
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r & 0xf];
}
}
return uuid.join('');
}
Here is a sample of the UUIDs generated :
682db637-0f31-4847-9cdf-25ba9613a75c
97d19478-3ab2-4aa1-b8cc-a1c3540f54aa
2eed04c9-2692-456d-a0fd-51012f947136
From sagi shkedy's technical blog:
ReplyDeletefunction generateGuid() {
var result, i, j;
result = '';
for(j=0; j<32; j++) {
if( j == 8 || j == 12|| j == 16|| j == 20)
result = result + '-';
i = Math.floor(Math.random()*16).toString(16).toUpperCase();
result = result + i;
}
return result;
}
There are other methods that involve using an ActiveX control, but stay away from these!
EDIT: I thought it was worth pointing out that no GUID generator can guarantee unique keys (check the wikipedia article). There is always a chance of collisions. A GUID simply offers a large enough universe of keys to reduce the change of collisions to almost nil.
That being said, I think that the note19 solution posted by John Millikin is much more elegant that the one I found. Go with that.
It's just a simple AJAX call...
ReplyDeleteIf anyone is still interested, here's my solution.
On the server side:
[WebMethod()]
public static string GenerateGuid()
{
return Guid.NewGuid().ToString();
}
On the client side:
var myNewGuid = null;
PageMethods.GenerateGuid(
function(result, userContext, methodName)
{
myNewGuid = result;
},
function()
{
alert("WebService call failed.");
}
);
David Bau provides a much better, seedable random number generator at http://davidbau.com/archives/2010/01/30/random_seeds_coded_hints_and_quintillions.html
ReplyDeleteI wrote up a slightly different approach to generating UUIDs at http://blogs.cozi.com/tech/2010/04/generating-uuids-in-javascript.html
// RFC 4122
ReplyDelete//
// A UUID is 128 bits long
//
// String representation is five fields of 4, 2, 2, 2, and 6 bytes.
// Fields represented as lowercase, zero-filled, hexadecimal strings, and
// are separated by dash characters
//
// A version 4 UUID is generated by setting all but six bits to randomly
// chosen values
var uuid = [
Math.random().toString(16).slice(2, 10),
Math.random().toString(16).slice(2, 6),
// Set the four most significant bits (bits 12 through 15) of the
// time_hi_and_version field to the 4-bit version number from Section
// 4.1.3
(Math.random() * .0625 /* 0x.1 */ + .25 /* 0x.4 */).toString(16).slice(2, 6),
// Set the two most significant bits (bits 6 and 7) of the
// clock_seq_hi_and_reserved to zero and one, respectively
(Math.random() * .25 /* 0x.4 */ + .5 /* 0x.8 */).toString(16).slice(2, 6),
Math.random().toString(16).slice(2, 14)].join('-');
function guidGenerator() {
ReplyDeletevar buf = new Uint16Array(8);
window.crypto.getRandomValues(buf);
var S4 = function(num) {
var ret = num.toString(16);
while(ret.length < 4){
ret = "0"+ret;
};
return ret;
};
return (S4(buf[0])+S4(buf[1])+"-"+S4(buf[2])+"-"+S4(buf[3])+"-"+S4(buf[4])+"-"+S4(buf[5])+S4(buf[6])+S4(buf[7]));
}
Done with the proposed, and in Chrome, Firefox available, API for secure random numbers. I have not read the RFC, korpus taken from John Millikin.
Here is a combination of the most voted answer, with a workaround for Chrome's collisions:
ReplyDeletegenerateGUID = (typeof(window.crypto) != 'undefined' &&
typeof(window.crypto.getRandomValues) != 'undefined') ?
function() {
// If we have a cryptographically secure PRNG, use that
// http://stackoverflow.com/questions/6906916/collisions-when-generating-uuids-in-javascript
var buf = new Uint16Array(8);
window.crypto.getRandomValues(buf);
var S4 = function(num) {
var ret = num.toString(16);
while(ret.length < 4){
ret = "0"+ret;
}
return ret;
};
return (S4(buf[0])+S4(buf[1])+"-"+S4(buf[2])+"-"+S4(buf[3])+"-"+S4(buf[4])+"-"+S4(buf[5])+S4(buf[6])+S4(buf[7]));
}
:
function() {
// Otherwise, just use Math.random
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
};
On jsbin if you want to test it.
When looking about for a solution, don't just search on "GUID" but also try "UUID".
ReplyDeleteI really like how clean Broofa's answer is, but it's unfortunate that poor implementations of Math.random leave the chance for collision.
ReplyDeleteHere's a similar RFC4122 version 4 compliant solution that solves that issue by offsetting the first 13 hex numbers by a hex portion of the timestamp. That way, even if Math.random is on the same seed, both clients would have to generate the UUID at the exact same millisecond (or 10,000+ years later) to get the same UUID:
function generateUUID(){
var d = new Date().getTime();
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = (d + Math.random()*16)%16 | 0;
d = d/16 | 0;
return (c=='x' ? r : (r&0x7|0x8)).toString(16);
});
return uuid;
};
Here's a fiddle to test.
Adjusted my own UUID/GUID generator with some extras here.
ReplyDeleteI'm using the following Kybos random number generator to be a bit more cryptographically sound.
Below is my script with the Mash and Kybos methods from baagoe.com excluded.
//UUID/Guid Generator
// use: UUID.create() or UUID.createSequential()
// convenience: UUID.empty, UUID.tryParse(string)
(function(w){
// From http://baagoe.com/en/RandomMusings/javascript/
// Johannes Baagøe <baagoe@baagoe.com>, 2010
//function Mash() {...};
// From http://baagoe.com/en/RandomMusings/javascript/
//function Kybos() {...};
var rnd = Kybos();
//UUID/GUID Implementation from http://frugalcoder.us/post/2012/01/13/javascript-guid-uuid-generator.aspx
var UUID = {
"empty": "00000000-0000-0000-0000-000000000000"
,"parse": function(input) {
var ret = input.toString().trim().toLowerCase().replace(/^[\s\r\n]+|[\{\}]|[\s\r\n]+$/g, "");
if ((/[a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12}/).test(ret))
return ret;
else
throw new Error("Unable to parse UUID");
}
,"createSequential": function() {
var ret = new Date().valueOf().toString(16).replace("-","")
for (;ret.length < 12; ret = "0" + ret);
ret = ret.substr(ret.length-12,12); //only least significant part
for (;ret.length < 32;ret += Math.floor(rnd() * 0xffffffff).toString(16));
return [ret.substr(0,8), ret.substr(8,4), "4" + ret.substr(12,3), "89AB"[Math.floor(Math.random()*4)] + ret.substr(16,3), ret.substr(20,12)].join("-");
}
,"create": function() {
var ret = "";
for (;ret.length < 32;ret += Math.floor(rnd() * 0xffffffff).toString(16));
return [ret.substr(0,8), ret.substr(8,4), "4" + ret.substr(12,3), "89AB"[Math.floor(Math.random()*4)] + ret.substr(16,3), ret.substr(20,12)].join("-");
}
,"random": function() {
return rnd();
}
,"tryParse": function(input) {
try {
return UUID.parse(input);
} catch(ex) {
return UUID.empty;
}
}
};
UUID["new"] = UUID.create;
w.UUID = w.Guid = UUID;
}(window || this));
Check this out if you are generating random GUIDs in Google Chrome http://devoluk.com/google-chrome-math-random-issue.html
ReplyDeleteThere is a jQuery plugin that handles Guid's nicely @ http://plugins.jquery.com/project/GUID_Helper
ReplyDeletejQuery.Guid.Value()
Returns value of internal Guid. If no guid has been specified, returns a new one (value is then stored internally).
jQuery.Guid.New()
Returns a new Guid and sets it's value internally.
jQuery.Guid.Empty()
Returns an empty Guid 00000000-0000-0000-0000-000000000000.
jQuery.Guid.IsEmpty()
Returns boolean. True if empty/undefined/blank/null.
jQuery.Guid.IsValid()
Returns boolean. True valid guid, false if not.
jQuery.Guid.Set()
Retrns Guid. Sets Guid to user specified Guid, if invalid, returns an empty guid.
The better way:
ReplyDeletefunction(
a,b // placeholders
){
for( // loop :)
b=a=''; // b - result , a - numeric variable
a++<36; //
b+=a*51&52 // if "a" is not 9 or 14 or 19 or 24
? // return a random number or 4
(
a^15 // if "a" is not 15
? // genetate a random number from 0 to 15
8^Math.random()*
(a^20?16:4) // unless "a" is 20, in which case a random number from 8 to 11
:
4 // otherwise 4
).toString(16)
:
'-' // in other cases (if "a" is 9,14,19,24) insert "-"
);
return b
}
Minimized:
function(a,b){for(b=a='';a++<36;b+=a*51&52?(a^15?8^Math.random()*(a^20?16:4):4).toString(16):'-');return b}
I know this topic is old but if you really wanted to create a GUID you could obvioulsy do it without straight javascript. You could cause a page expiration every load and create a GUID on the server side then populate that into a javascript variable at page run time. Just an idea.
ReplyDelete