More questions after redirect-receiving, what am I doing wrong

I am rewriting a bunch of forms around a new paradigm, trying to simplify the mechanism used to prevent reprocessing of obsolete form data if the user plays with the back button. I redid it to the minimum test case that works in FF21, i.e. .10 (!), Opera12.15, but the only way with Chrome 27.0 and Safari 5.1.7 - not in browsers, which I would expect problems with, so that this is probably my own mistake.

Form view.php always sends post.php, which does all the work, and then redirects to view.php. (Some of them are design pages where some users repeat many times.) My goals were to avoid the message โ€œThe browser should resend dataโ€ so that the browser does not use cached views and does not allow view.php to leave a long trace in the history. (Some sources claim that PRG prevents this.) All three goals are implemented in FF, Opera, and IE, where the story does not grow. Chrome and Safari show a trail of identical pageviews in history. Looking at the request / response headers, it looks like Chrome does a full GET of any historical page, but displays a mixture of historical and current field values โ€‹โ€‹on one page (!). It seems to me that the most difficult aspect for me is the presentation of a combination of values โ€‹โ€‹that never coexisted on one page. Viewing the source in Chrome always shows an updated copy. And I'm talking about the behavior of accurate distilled examples below, and not about their more complex version.

Field 1 echoes the internal counter and ignores user input. It acts in the same strange way, whether it is read-only or not.

Field two user echoes. Usually I copy or add a field to it.

view.php

<?php session_start(); header('Cache-Control:private,no-store,no-cache,must-revalidate,post-check=0,pre-check=0'); header('Pragma: no-cache'); $cval = !isset($_SESSION['counter']) ? 0 : $_SESSION['counter']; $word = !isset($_SESSION['word']) ? '' : htmlentities($_SESSION['word'],ENT_QUOTES,'UTF-8',FALSE); echo <<<HTM <pre> <form method='POST' action='post.php'> <input type='text' name='count' value='$cval'/> <input type='text' name='word' value='$word'/> <input type='submit' name='doit' value='Submit'/> </form> </pre> HTM; ?> 

post.php

 <?php session_start(); if(!isset($_SESSION['counter'])): $_SESSION['counter'] = 1; else: $_SESSION['counter'] += 1; endif; $_SESSION['word'] = !isset($_POST['word']) ? '' : $_POST['word']; header('Location: view.php'); ?> 

If I start backing up my history, Chrome typically displays the updated Field-one value, but it displays the historical Field-two values. Sometimes it shows historical on both. Without this inconsistency, I assume that it was an inability to prevent the server (in paired networks) or the proxy server from caching the page.

It does the same if I add the heading "Expires: -1".

I can handle the recognition of an obsolete form; what I cannot do is not allow the user to reach or send it. An increment of the GET argument in view.php will prevent unpredictable cached views, but it will create an explicit history in all browsers and suggest people turn the ratchet again.

Why is this happening and being fixed?

+4
source share
1 answer

In the absence of the opposite advice, there seemed to be nothing wrong with my implementation of the prg model. Firefox, IE, and Opera work exactly as intended, and Safari just blindly puts every GET in history. But the Safari story is easy to handle by inserting hidden or freshness freshness tokens into the form so you can recognize the outdated form.

The stumbling block is the Chrome trick, and I don't see a pure PHP / HTML path in it. (BTW reportedly.)

Here is the new code, only the more complex smidgen, which makes the behavior very clear. Just do a few submissions, each time typing something else in the Inval field, and then look back at the story.

Chrome always correctly retrieves a new copy of a view, even if you go back in history. But if you go to visit # x, Chrome will override the pre-population values โ€‹โ€‹for any fields that you touched by visiting #x, adding outdated data instead of what is indicated in the new view. (Check the discrepancy between the data in the Inval field and the preopulation value shown on the right.) This can be resolved by using JavaScript to re-fill the damaged fields by copying the preload data into them from the hidden elements that you insert on the page.

New VIEW.PHP

 <?php # view.php session_start(); header('Cache-Control: private, no-store, no-cache, must-revalidate, max-age=0'); header('Pragma: no-cache'); header('Expires: -1'); # Format timestamp and counter $tval = date("H:i:s"); $cval = !isset($_SESSION['counter']) ? 0 : $_SESSION['counter']; # Format last-posted values for display but (mostly) not for prepopulation $lphiddn = !isset($_SESSION['xhiddn']) ? '' : htmlentities($_SESSION['xhiddn'],ENT_QUOTES,'UTF-8',FALSE); $lpcount = !isset($_SESSION['xcount']) ? '' : htmlentities($_SESSION['xcount'],ENT_QUOTES,'UTF-8',FALSE); $lpinval = !isset($_SESSION['xinval']) ? '' : htmlentities($_SESSION['xinval'],ENT_QUOTES,'UTF-8',FALSE); # Format pre-population data $phiddn = "H $tval"; // H 00:00:00 $pcount = "(#$cval) $tval"; // (#1) 00:00:00 $pinval = $lpinval; // whatever was last posted for this field echo <<<HTM <pre style='font-family: monospace;'> <form method='POST' action='post.php'> Hiddn <input type='hidden' name='hiddn' value='$phiddn'/> prepop=$phiddn lastpost=$lphiddn Count <input type='text' name='count' value='$pcount'/> prepop=$pcount lastpost=$lpcount Inval <input type='text' name='inval' value='$pinval'/> prepop=$pinval = lastpost=$lpinval Submt <input type='submit' name='doit' value='Submit'/> </form> </pre> HTM; ?> 

New POST.PHP

 <?php # post.php session_start(); header('Cache-Control: private, no-store, no-cache, must-revalidate, max-age=0'); header('Pragma: no-cache'); header('Expires: -1'); if(!isset($_SESSION['counter'])): $_SESSION['counter'] = 1; else: $_SESSION['counter'] += 1; endif; $_SESSION['xhiddn'] = !isset($_POST['hiddn']) ? '' : $_POST['hiddn']; $_SESSION['xcount'] = !isset($_POST['count']) ? '' : $_POST['count']; $_SESSION['xinval'] = !isset($_POST['inval']) ? '' : $_POST['inval']; header("HTTP/1.1 303 See Other"); header('Location: view.php'); ?> 
0
source

Source: https://habr.com/ru/post/1487591/


All Articles