Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Saving State w/o Cookies

by motomuse (Sexton)
on Oct 20, 2000 at 03:26 UTC ( #37594=perlquestion: print w/replies, xml ) Need Help??

motomuse has asked for the wisdom of the Perl Monks concerning the following question:

Oh wise and beneficent Elder Brethren and Sistren, of your wisdom tell me:

Without getting into a religious debate over the value or not-value of cookies, what would be the best way of saving a session ID without them?

Here's the issue, see: I have a situation where we want our band's online catalog wants to live at the band's site, but the actual (secure) ordering service lives elsenet. The way the admin of the ordering service has set it up is that a person has to sign in, and their session ID gets preserved (in a db store, I think) through all their navigations through the site until they logout again, thereby making sure that their "shopping cart" effectively follows them around. Aforementioned admin doesn't want to use cookies to save state because he (not to say numerous of his friends and colleagues) stands on the anti-cookie side of the aforementioned debate.

But I want to be able to have our customers order from our catalog without necessarily having to have (hm, that was redundant) a pre-existing login on the other site.

BBQ wrote, in the "Who Needs Shopping Carts?" thread:

A real Shopping Cart should be a cookie-free, stateless and still be persistent.
Wonderful! I thought. Just what I need! But specific details of how to set this up (with examples for boneheaded neophyte me) were not forthcoming thereafter. I did read pretty deeply in that thread, and others like it, and it looks, based on what I could glean there, like my offsite ordering guy is on the right track with his login idea. Clearly, he could automatically set a session ID and then pass the ID back and forth in hidden inputs. So I guess the real question is, how specifically do we set up our forms to receive and keep and transmit this number again? This is all across an https connection, by the way.

I have faith that in Perl (and probably even more specifically in CGI.pm) lieth the answer. How may our respective goals be achieved?

Thanks for your attention,

     - Muse

Replies are listed 'Best First'.
Re: Saving State w/o Cookies
by Shayk (Novice) on Oct 20, 2000 at 06:50 UTC
    <agree monk="AgentM" />

    I assume you are familiar with the downside of not using cookies; without a required login by the client you cannot maintain state beyond the current connection. Of course, if you require a login (e.g. "To resume your previous shopping session, please log in!" link), you can get around this.

    Managing state is not so bad without cookies, you don't need to store all the cart data on the form in a <input type=hidden> field, but you do have to store a local sessionID in either a <input type=hidden> field or pass it in the query string. Either way, CGI.pm makes it easy to grab that info back from the client.

    In order to use the sessionID, I would recommend the DB route, although you can do it using a simple text file on your server. Going the DB route, create a SQL table like this one (of course yours will be different, but this is just an example ;) :

    use shopdb; create table sessions ( SessionID int, isComplete bool, SessionData varchar[2000] );

    ...and then you just post to the DB just like you would have been doing to the cookie.

Re: Saving State w/o Cookies
by Trimbach (Curate) on Oct 20, 2000 at 06:54 UTC
    There's lots of ways to setup a shopping cart like you described, but the general idea is you want your CGI to allow a customer to order an item, surf around, order some more, then (eventually) check out. In order to do this the CGI needs a unique way to track who's who. Cookies are one way to do that, because wherever a customer goes, so goes their cookie. Without cookies your CGI will have to compute and assign a unique identifier to anyone who orders anything, and then pass that identifier into every page the person sees on your website.

    This gives you a couple of challenges. First, the identifier must be pretty much guaranteed to be unique (otherwise your CGI will get confused as to who's who.) One way of doing this is to calculate an id off of (say) the current UNIX time, plus maybe the first 3 letters of their first name plus the first 3 letters of their last name. For example, if I order something my unique ID might be "123456789GARBLA". It'd be pretty unlikely that anyone would hit your shopping cart at exactly the same time with exactly the same combination of letters. Bang. Unique identifier.

    After you have an identifier, you'll need to have some way to store the current (incomplete) order somewhere so that your CGI can pick it up where it left off. You can do this by creating a temp file named the same name as the unique id, or you can create a DB entry with the unique id as the row identifier. Either way you'll need to account for the build-up of unfinished orders by cleaning up any temp files/rows after say 6 hours if they don't consumate their order.

    Lastly you'll need to pass this unique identifier to all the customer's pages. Best way to do this probably by modifying the URL of all their future pages like "http://www.coolband.com/index.html?id=123456789GEBBLA" or something. Index.html still gets displayed, but the next time they surf back to the order page (or checkout page) your CGI will know who they are, and then, by accessing their pending order on the server (via temp file or row) your CGI will know what they've ordered up till then.

    You mentioned that your site uses SSL... if so you probably won't have to worry about encrypting your unique id. Reason is that until they check out the only thing recorded is their current order ("T-shirt: 1, Coffee Mug: 5") which isn't exactly top-secret info. You'll only get their credit card information as the last step in the checkout process, and since you're using SSL that part of the transaction will be secure.

    Of course, the easy way around figuring out how to do all this is to simply bag the whole idea of a shopping cart... when a customer wants to order something, just send 'em to a secure order page and have them order everything at once. Saves lots on the overhead... you're going to spend a lot of time ironing out the details of letting them "shop/surf/shop/surf" like the big catalog merchants do. If you don't have a huge catalog, it'll probably be easier to stick to a simple order page.

    Didn't mean to be so long-winded... :-D

    Gary Blackburn
    Trained Killer

      One way of doing this is to calculate an id off of (say) the current UNIX time, plus maybe the first 3 letters of their first name plus the first 3 letters of their last name

      Better yet, use the process idea (handily stored by perl in the variable $$) along with the time (stored by perl as $^T - the time the script started). Using this two ensures for a pretty unique string, since you can't have two processes with the same PID running at the same time.

        The issues involved with generating random IDs have been discussed multiple times on this site. Check out Randomizing Unique ID?, which is one of the more long winded threads. (My particular solution was RE: RE: RE: Randomizing Unique ID? but you should really read the whole thread.)
        Using this two ensures for a pretty unique string, since you can't have two processes with the same PID running at the same time.

        Unless you're running mod_perl...and the process will have the same PID everytime.

Re: Saving State w/o Cookies
by AgentM (Curate) on Oct 20, 2000 at 03:34 UTC
    This came up eariler. If only I knew where. One possible solution of several is to save thestate in a hidden field within the CGIed pages. Of course, you should encrypt these, possibly with two MD5 hashes as mentioned (found it)earlier. This is cookie-free and provides the same save-in-the-browser functionality.
    AgentM Systems nor Nasca Enterprises nor Bone::Easy nor Macperl is responsible for the comments made by AgentM. Remember, you can build any logical system with NOR.
Re: Saving State w/o Cookies
by jptxs (Curate) on Oct 20, 2000 at 07:39 UTC

    Found an interesting bit in perldoc CGI:

    SAVING THE STATE OF THE SCRIPT TO A FILE: $query->save(FILEHANDLE) This will write the current state of the form to the provided filehandle. You can read it back in by providing a filehandle to the new() method. Note that the filehandle can be a file, a pipe, or whatever! The format of the saved file is: NAME1=VALUE1 NAME1=VALUE1' NAME2=VALUE2 NAME3=VALUE3 = Both name and value are URL escaped. Multi-valued CGI parameters are represented as repeated names. A session record is delimited by a single = symbol. You can write out multiple records and read them back in with several calls to new. You can do this across several sessions by opening the file in append mode, allowing you to create primitive guest books, or to keep a history of users' queries. Here's a short example of creating multiple session records: use CGI; open (OUT,">>test.out") || die; $records = 5; foreach (0..$records) { my $q = new CGI; $q->param(-name=>'counter',-value=>$_); $q->save(OUT); } close OUT; # reopen for reading open (IN,"test.out") || die; while (!eof(IN)) { my $q = new CGI(IN); print $q->param('counter'),"\n"; } The file format used for save/restore is identical to that used by the Whitehead Genome Center's data exchange format "Boulderio", and can be manipulated and even databased using Boulderio utilities. See http://www.genome.wi.mit.edu/genome_software/other/boulder.ht +ml for further details.

    Sorry for the long post...thought it could help : )

    -- I'm a solipsist, and so is everyone else. (think about it)

Re: Saving State w/o Cookies
by cianoz (Friar) on Oct 20, 2000 at 14:19 UTC
    Why not using "Basic" authentication?
    Then you could use the supplied username as a session key...
Re: Saving State w/o Cookies
by runrig (Abbot) on Oct 20, 2000 at 04:00 UTC
    Just heard of a new module Apache::SessionManager, though I don't know much about it, and it may be mod_perl only, but I do know it can be configured to cookie or not cookie.

    Update: please ignore that URL, I'm looking for the email where I saw the announcment.

    I found the email, it was not an announcement of CPAN availability (yet), but an announcement of the intention to start a Source Forge project; however, it does sound like its a fairly complete project. Msg me if you want the guy's email address to get the module.
Re: Saving State w/o Cookies
by motomuse (Sexton) on Oct 20, 2000 at 03:32 UTC
    Oh, bother. That's what I get for not re-reading quite closely enough. I meant to say, "We want our band's online catalog to live at the band's site" but didn't quite finish editing that thought out of its previous edition. Nevermind, you get the idea.

        - Muse

RE: Saving State w/o Cookies
by Caillte (Friar) on Oct 20, 2000 at 14:41 UTC
    Expanding on cianoz's idea, if you have a handle on the user, even something like their IP address from $ENV then you could easily set up a database entry for that handle and save the state there. Admittedly this would be a lot more complex than simply dumping a text string into a cookie, but it would allow you a lot of flexability.
      not a good idea, this would be defeated by proxy....
        I did indeed read that node before I posted my initial question, which is why I was careful to say, "But specific details of how to set this up (with examples for boneheaded neophyte me) were not forthcoming thereafter." -- your node set out ways to do it and things to avoid, but without examples. I also poked around in the site to which that node refers, likewise finding nothing quite like what I needed.

        Rightly or wrongly, I learn better by example than by bald expositions of theory. Theory's great, but I need demonstration, it seems, to internalize the lesson.

        Thanks to all who've replied. Now we'll see if I can talk the offsite admin into extrapolating from the replies (a thing that's been somewhat difficult).

        Regards,
            - Muse

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (2)
As of 2022-11-26 08:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?