Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Generate a session ID

by Spidy (Chaplain)
on Dec 02, 2005 at 23:23 UTC ( [id://513752]=CUFP: print w/replies, xml ) Need Help??

I found this inside the Beginning Perl book...very useful if you don't have CGI::Session installed on your system and aren't willing to install it.

Also, collisions are possible with this snippet, so make sure that you check whether or not the ID is already in use before using it. (Thanks perrin)
sub generateSession { # generate random 8 digit hex session ID return sprintf("%0.8x",rand()*0xffffffff); }

Replies are listed 'Best First'.
Re: Generate a session ID
by BrowserUk (Patriarch) on Dec 03, 2005 at 14:55 UTC

    Check the rand function used by your version of Perl. Specifically, check for the number of randbits it is configured for:

    P:\test>Perl -v This is perl, v5.8.7 built for MSWin32-x86-multi-thread (with 7 registered patches, see perl -V for more detail) ... P:\test>Perl -V:randbits randbits='15';

    Which means that with AS perl, this snippet will only ever produce 32768 unique ids:

    #! perl -slw use strict; my %cache; $cache{ sprintf("%0.8x",rand()*0xffffffff) } = undef for 1 .. 1_000_00 +0; printf "1 million attempts produced %d keys\n", scalar keys %cache; printf "between %s and %s\n", (sort keys %cache)[ 0, -1 ]; __END__ P:\test>junk 1 million attempts produced 32768 keys between 00000000 and fffdffff

    I'm not sure what the mathematical probability is for picking duplicates from a pool 2^15 values, but in practice, it produces very, very few unique values before it repeats itself:

    #! perl -slw use strict; my %cache; my $u = sprintf("%0.8x",rand()*0xffffffff); until( exists $cache{ $u } ) { $cache{ $u } = undef; $u = sprintf("%0.8x",rand()*0xffffffff); } printf "Produced %d unique keys before duplicating\n", scalar keys %ca +che; printf "between %s and %s\n", (sort keys %cache)[ 0, -1 ]; __END__ P:\test>junk Produced 454 unique keys before duplicating between 00bdffff and ff89ffff P:\test>junk Produced 273 unique keys before duplicating between 013dffff and feb5ffff P:\test>junk Produced 84 unique keys before duplicating between 0183ffff and fe5bffff P:\test>junk Produced 94 unique keys before duplicating between 001bffff and fbc1ffff

    You can extend the range almost linearly by multiplying two calls to rand:

    #! perl -slw use strict; my %cache; $cache{ sprintf( "%0.8x", rand() * rand() * 0xffffffff ) } = undef for + 1 .. 1_000_000; printf "1 million attempts produced %d keys\n", scalar keys %cache; printf "between %s and %s\n", (sort keys %cache)[ 0, -1 ]; __END__ P:\test>junk 1 million attempts produced 994758 keys between 00000000 and ffae0137

    but even then, the number of uniques you will get before repeats is dismally low:

    Produced 17891 unique keys before duplicating between 00000000 and fba0116f P:\test>junk Produced 1957 unique keys before duplicating between 0008e633 and fb575407 P:\test>junk Produced 30229 unique keys before duplicating between 00000000 and fdeaed07 P:\test>junk Produced 10830 unique keys before duplicating between 0000eedf and ff441eff P:\test>junk Produced 15537 unique keys before duplicating between 00000000 and fe068a77

    All in all, a better session id generator than this would be strongly advisable.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      I'm not sure what the mathematical probability is for picking duplicates from a pool 2^15 values, but in practice, it produces very, very few unique values before it repeats itself:
      This is an application of the Birthday Paradox, which isn't really a paradox, just counter-intuitive. Here's a little code that shows how many you have to pick before your chances are greater than 50% of getting a dupe. The number is quite a bit lower than you would think.
      my $prod = 1; foreach my $num (1..2**15) { printf("%5d => %0.6f\n", $num, $prod); die "Threshold reached\n"if $prod <= 0.5; $prod *= (2**15 - $num)/2**15; }
      Update: In looking back, it may be a little unclear what the program above produces. It prints a list of pairs in the form of "x => y". 'x' is the number of IDs that you've generated, 'y' is the probability that you've chosen a unique one. I also had a typo (one too many '}'s) and a slight logic error (the third line used to be the first).

      thor

      The only easy day was yesterday

      I checked it out on the system I was running it on...I have 48 randbits, and it produces 99,000 keys in 1 million attempts.

      That being said, does anyone know of a good way to generate something like a session ID that's unique? I can't install modules.

        I can't install modules.

        Do what you can to change that parameter.

        It will help you more than a little right now, and we just can't estimate how much it will help in the future.

        Cheers, Sören

        This won't be speedy but you could use fewer rands by adapting your original approach.

        print new_session_id(), $/; sub new_session_id { my $id = ''; for ( 1 .. 32 ) { $id .= sprintf "%x", rand(16); } return $id; }

        You should also see if you've got Digest/Digest::MD5 available on your system. You can do something like:

        use Digest::MD5 "md5_hex"; my @user_info = map { $ENV{$_} } grep { /USER|REMOTE/ } keys %ENV; print md5_hex( rand() . join('', @user_info) );

        Don't forget to do a search for unique ID too, there are many points of departure: Google on the pen for "unique id." Also, try vanilla "unique."

Re: Generate a session ID
by perrin (Chancellor) on Dec 03, 2005 at 01:30 UTC
    Since this is random, you can get collisions from it. Don't use it without checking to see if the ID is already in use.
Re: Generate a session ID
by jonadab (Parson) on Dec 03, 2005 at 11:32 UTC

    Are you really sure you're never going to need more than a couple million sessions at a time? There are only just over four million possible combinations of eight hex digits, and if you're picking at random and checking for collisions you do not want to get anywhere near exhausting the space.

    If sessions expire after a few minutes, 16^8 is enough, assuming you're not one of the dozen top sites. I'd be careful about how long sessions last before they expire, though, and check that the collision detection allows expired sessions to be reused, or that something ensures they are deleted so as not to cause collisions.

      four million possible combinations of eight hex digits

      I think you meant billion, right? There are more than 4 million combinations of plain old integers in 8 digits. Though given BrowserUK's post, it's moot anyway. :)

      $ perl -e 'print 16 ** 8, $/' 4294967296
        Yeah, sorry, got my powers of 1000 crossed momentarily.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://513752]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (3)
As of 2024-04-24 23:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found