personally i do not use PRG. the rules of thumb that i use is as follows:
GET for idempotent actions. i.e. actions that do not 'DO' anything (such as database activities) - NOTE I have one exception to this rule (see below).
POST for everything else.
to protect against double actions i attach a nonce to all actions that are not idempotent. a nonce is a number used once. you set a nonce as a hidden field in the form and in the session handler. then compare their values before allowing a database (or non idempotent) action. search for wordpress nonces for good explanations on what these are. i have also published a simple nonce handler. it is found
here as part of my non-image based captcha post. A 'proper' nonce handler will store a reference to the precise action that is to be permitted, and the time for which the action will be permitted. you can see that this is a very simple overlay on my code.
the exception to my general rule is for delete actions. i prefer delete actions to be triggered via a simple hyperlink coupled with some JS confirmation dialog. the reason is partly coding ease and partly that i don't care if a delete action is committed twice. as the second and subsequent actions are idempotent in themselves (nothing left to delete). to be 'proper' and less lazy i should add a simple ajax handler to the link to post the delete request rather than send it via GET.
note that a 'proper' nonce implementation will stop you from resubmitting forms whilst bug checking (or rather stop the resubmission from having any effect). the workaround for this is simply to stub out the nonce checking script to return true before processing. just remember to remove the stub before publshing.
the 'resend messages'. more difficult, frankly, as they are generated by the browser rather than anything that you can control. one easy workaround, however, is to deploy jQuery core in your pages and just add an event handler to submit the forms by ajax rather than via a browser refresh. off the top of my head some simple code such as this should sort you out (untested).
Code:
jQuery(document).ready(function(){
rebind();
});
function rebind(){
jQuery("form").bind(
'submit',
function(e){
e.stopPropagation(); //stop event propagation
e.preventDefault(); //stop the form from submitting
jQuery.post(
this.attrib('action'), //url
this.serialize(), //data to be posted
replacePage(t),
'html');
return false;
});
}
function replacePage(t){
document.write(t);
rebind();
}
function newPage(t){
var w = jQuery(window).open();
w.html(t);
}
function popUp(t){
jQuery('body').append('<div id="popup" style="display: none;"></div><div id="window" style="display: none;"><div id="popup_content"><a href="#" onclick="Close_Popup();">Close</a>' + t + '</div></div>');
jQuery('#popup').css( {'height': '100%',
'width' : '100%',
'background': '#000000',
'position': 'absolute',
'top': '0',
'-moz-opacity':'0.75',
'-khtml-opacity': '0.75',
'opacity': '0.75',
'filter':'alpha(opacity=75)'});
jQuery('#window').css( {'width': '600px',
'height': '300px',
'margin': '0 auto',
'border': '1px solid #000000',
'background': '#ffffff',
'position': 'absolute',
'top': '200px',
'left': '25%'});
jQuery('#popup').fadeIn( 'fast',
jQuery('#windows').fadeIn('fast')
);
}
function closeUp(){
jQuery('#window').fadeOut( 'fast',
jQuery('#popup').fadeOut( 'fast',
jQuery('#popup').remove()));
}
please note that if you are not using any other js frameworks you may be able to substitute the jQuery references with a $ sign. i prefer the longhand, however.
if i have misunderstood the requirement for the ajax code then another alternative is the ajax method but write the output in a dialog (change the replacePage(t) reference to popUp(t) ) or to open the resulting page in a new window (change the replacePage(t) to a newPage(t))
as said, the above code is totally untested so feel free to post back with bug reports.
the popup styles and html are thanks to
this site