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

I did some searching of the Monastery and only found mention of back-button disabling, and some strong advisories against it.

Background:
I've got a cgi script that takes form entered data and sends it over a socket connection to a server thats running a lengthy/robust application.  The socket closes and the client gets a confirmation of request page.  The results (after the application finishes) are then emailed back to the user.

Question:
If the user reloads and repost's the form data of the confirmation page, the socket is opened again and another (duplicate) job is sent to the server side application.  I want to avoid user reload/repost.  Can I disable it?  Any ideas?  Thanks.

Replies are listed 'Best First'.
Re: Reload/Repost Disable
by gregor42 (Parson) on Jun 21, 2001 at 19:22 UTC

    Simple Answer: No.

    Lengthly Answer: You don't really want to do this, though at first you might think that you do. Ask yourself the question of what if the user has a 'flakey' network connection? People still use modems & some backwoods phone networks still drop you to lower baud rates, etc... What if the connection simply wasn't properly made? What if they're hitting BACK for a reason? NO,nonononono. You don't want to even TRY this.

    Further, you'd be messing with the average surfer's normal procedure of 'doing their thing.' That's a great way to become unpopular fast. Don't try to outguess your users & treat them like they're stupid. (even if they are)

    They real way to do this is to have the server see what they're doing, anticipate it, & deal with it gracefully.

    Exception to the rule:So you're dead set on doing this huh?... Simple. Open a new browser window. There will be nothing to go BACK to...



    Wait! This isn't a Parachute, this is a Backpack!
Re: Reload/Repost Disable
by mirod (Canon) on Jun 21, 2001 at 19:32 UTC

    The usual way to deal with this problem is to use a session number.

    • the form is generated by a CGI script, it includes a (hidden) param that identifies the session (a unique number),
    • received session numbers (and possibly session information) are stored in either a DB or in a flat file (be sure that file is properly locked by using the technique described in RE: File Locking),
    • when you receive a new request you can then query the DB, or lock the session archive file and load it, to check that this is the first time that this session is sent to you. If not you can either discard the info or send back a message to the user.

    And of course you can also look at merlyn's Linux Magazine Column (the last one on the page) that deals with this kind of problem.

Re: Reload/Repost Disable
by Eradicatore (Monk) on Jun 21, 2001 at 19:28 UTC
    Ah, I had this same exact problem when creating a "attendance" web page that just used a flat file to keep track of the responses. If the user clicked "record" and then hit reload, on netscape it wanted to repost their last answer and this screwed things all up. I found a good article (don't recall where unfortunatly) that pointed this out to me. You can just redirect the user to the original cgi script after dealing with all the stuff posted, and then if they hit reload on netscape they won't have stuff to repost. Pretty neat. Here is the code:
    #!/usr/local/bin/perl -w use strict; use CGI qw(:standard); my @pnames; if (@pnames = param()) { eval_answers(); print_redirect(); } else { print header; print_my_top(); print_name_table(); print_my_bottom(); print end_html; } exit(); # add sub routines here for what you want to do... sub print_redirect { print "Status: 301 MOVED PERMANENTLY\n"; print 'Location: http://www.some_isp.com/~mylogin/my_most_excellent +_cgi.cgi'; print "\n"; print "\n"; }
    Just a note, I don't think this was a problem on internet exploder. Just netscape. Anyway, good luck. Hope this can help.

    Justin Eltoft

    "If at all god's gaze upon us falls, its with a mischievous grin, look at him" -- Dave Matthews

Re: Reload/Repost Disable
by Masem (Monsignor) on Jun 21, 2001 at 19:35 UTC
    As with most of the other responses in regards to back-button disabling, the better solution is to create a unique ID that is in a hidden field on the submission page; in the large processing script, the uniqueID should be checked to see if it has been processed; if so, don't do anything, if not, process the job and mark the uniqueID as done. There's numerous ways to create the uniqueID as previously described.

    The key thing is that while there is JS code that can disable a back button, there are always ways around it (such as through menu options, key shortcuts, off-beat browsers that don't support such mis-features, etc). It's better to fix the problem on the server side than on the browser side where you have less control.


    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
Re: Reload/Repost Disable
by andye (Curate) on Jun 21, 2001 at 19:15 UTC
    Hide a reference number in the form. Record it server-side when the form is first submitted.

    When the results are available, store them with the reference number.

    If you get a request you've already dealt with, you can serve the results immediately, from your cache.

    Any use to you?

    Andy.

    update: I re-read the question. I guess you'd only need to keep a list of 'used' reference numbers, not each actual results set.

Re: Reload/Repost Disable
by dimmesdale (Friar) on Jun 21, 2001 at 19:13 UTC
    Well, if its a "duplicate" job, then you could just store away the last(or last 5, however secure you want to be) job sent over the socket; then you could do an equality check on them, and if they are equal(or equal enough, it depends on you application), then you can either (a)cancel the job, or (b)(probably a more user-friendly version)tell the user that they accidently hit reload, and caused a duplicate proccess--which was cancelled.

    ORYou could store an array with the last(or last 5, as above) users(assuming that there is some data as such on the form, i.e., unique data describing the user; name, email, etc.). Then, you could match the current user against the array(or scalar), and see if they match; if so, your response can be as above, or whatever suits your purposes.

    These are just a few suggestions; there's more than one way to do it, but its hard to know without some more data.

Re: Reload/Repost Disable
by toddler (Initiate) on Jun 21, 2001 at 19:52 UTC
    Thanks for all the quick responses.  I'm going to go after the log file idea, and then if that doesn't work I'll look at Eradicatore's code a little closer.

    You all need a raise!  I'll put in my 2 bits to the "powers that be," and I'll see what I can do.