Simple PHP Post-Redirect-Get code example

Php

Php Problem Overview


I have found many sites that describes PRG, but no simple PHP code example.


Here's what I implemented:

  1. The form.php has an action: validate.php.
  2. The validate.php is never seen by the user; if validates all $_GET and, if valid writes it to database and generates the HTML of a confirmation page / if not valid, it generates the HTML of an error page explaining what is wrong.
  3. Whichever HTML is generated get stored in a $_SESSION variable and then validate.php calls header('Location: <as appropriate>);.
  4. The submitted.php of invalid_input.php (in case the user reads the URL) consists only of echo $_SESSION['form_html'];.

That seems to me like protection against both page reload and back button problems.

Did I goof by trying to reinvent the wheel?

Php Solutions


Solution 1 - Php

Simplest scenario:

if ($_POST) {
   // Execute code (such as database updates) here.

   // Redirect to this page.
   header( "Location: {$_SERVER['REQUEST_URI']}", true, 303 );
   exit();
}

Use REQUEST_URI. Do not use PHP_SELF as in most CMS systems and frameworks PHP_SELF would refer to /index.php.

Solution 2 - Php

A snippet of code:

if (count($_POST)) {
    // process the POST data
    // your code here- so for example to log a user in, register a new account..
    // ...make a payment...etc

    // redirect to the same page without the POST data, including any GET info you
    // want, you could add a clause to detect whether processing the post data has 
    // been successful or not, depending on your needs

    $get_info = "?status=success";

    // if not using rewrite
    // header("Location: ".$_SERVER['PHP_SELF'].$get_info);

    // if using apache rewrite
    header("Location: ".$_SERVER['REQUEST_URI'].$get_info);
    exit();
}

Solution 3 - Php

    Browser
   HTML form
  method=POST
       |
       v
    PHP app
  reads $_POST
sends 303 header
       |
       v
    Browser
receives header
 redirected to
   new page
       |
       v
    PHP app
  reads $_GET
 does whatever

A common use is in login authentication. That's the process flow when user submits the login form. PHP app authenticates user via $_POST vars. Sends a 303 header back to browser when the user has successfully authenticated. So user is redirected to a new page.

Solution 4 - Php

I would like to introduce you to a method that is often used on a greater scale and in much more detail in frameworks.

What we are going to do

We have a file called index.php.

  • We are going to submit a form
  • We are going to check for this submit
  • We will add the POST data to a session
  • We will redirect the user to a confirmation page
  • We will display the data and let the user confirm.
  • We will submit, and finally process the data.
  • We will redirect back to index.php and show a notification.
The code
<?php
if (!isset($_SESSION)) session_start();

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
	switch ($_POST['submit']) {
		case 'add':
			// This is where our first POST will end up
			// We can perform actions such as checking the data here

			// After that we will add the POST data to a session
			$_SESSION['postdata'] = $_POST;
			// and unset the $_POST afterwards, to prevent refreshes from resubmitting.
			unset($_POST);

			// Now we will redirect...
			header("Location: ".$_SERVER['PHP_SELF']);
			break;
		case 'confirm':
			// We can now insert the data into the database or email it

			// Then we will unset the session and redirect back
			unset($_SESSION['postdata']);

			// This is to display our notification
			$_SESSION['success'] = true;

			// And there we go again...
			header("Location: ".$_SERVER['PHP_SELF']);
			break;
	}
	// We will exit here because we don't want the script to execute any further.
	exit;
}
?>

<?php if (isset($_SESSION['success']) && $_SESSION['success'] == true): ?>
	<p>Our data has been processed succesfully</p>
	<?php unset($_SESSION['success']); ?>
<?php endif; ?>

<?php if (isset($_SESSION['postdata'])): ?>
	<p>
		You want to add the following data:<br />
		<pre><?php print_r($_SESSION['postdata']); ?></pre>
		Is this correct?<br />
		<form method="POST" action="<?= $_SERVER['PHP_SELF']; ?>">
			<button type="submit" name="submit" value="confirm">Yes</button>
		</form>
	</p>
<?php else: ?>
	<p>
		<form method="POST" action="<?= $_SERVER['PHP_SELF']; ?>">
			<input type="text" name="..."><br />
			<input type="text" name="..."><br />
			<input type="text" name="..."><br />
			<input type="text" name="..."><br />
			<button type="submit" name="submit" value="add">Add something</button>
		</form>
	</p>
<?php endif; ?>

Solution 5 - Php

Here is form.php

<?php
session_start();
// 1) _____________________________________________ POST _____________________________
if ( count($_POST) ) {
    $ermsg ='';
    …
    check data, write some data to database(s), set error message(s) if any
    …
    $userdata1 = $_POST['htUserdata1'];
    $userdata2 = $_POST['htUserdata2'];
    …

    $_SESSION['PRG'] = array('field1'=>$userdata1,'field2'=>$userdata1,…,'ermsg'=>$ermsg);
    session_write_close();
    header('Location: ' . $_SERVER['REQUEST_URI'].'?z',true,303);
    exit;
// 2) _____________________________________________ REDIRECT ________________________
} else if ( array_key_exists('PRG',$_SESSION) ) {
    $userdata1 = $_SESSION['PRG']['field1'];
    $userdata2 = $_SESSION['PRG']['field2'];
    …
    $ermsg = $_SESSION['PRG']['ermsg'];
    unset($_SESSION['PRG']);
// 3) _____________________________________________ GET ______________________________
} else {
    …
    retrieve data from database(s)
    …
    $userdata1 = dbGet1();
    $userdata2 = dbGet2();
    …
    $ermsg = '';
}
// 4) _____________________________________________ DISPLAY _________________________
?>
<!DOCTYPE html>
<html lang="fr"><form method="post" action="form.php" accept-charset="utf-8">
    	<input id="htUserdata1" name="htUserdata1" type="text"/>
    	<input id="htUserdata2" name="htUserdata2" type="text"/></form>
<script language="javascript">
"use strict";
<?php
$G['htUserdata1'] = $userdata1;
$G['htUserdata2'] = $userdata2;
    …
$G['ermsg'] = $ermsg;
$myJSON = json_encode($G);
echo "var G=$myJSON;";
?>
document.getElementById('htUserdata1').value = G.htUserdata1;
document.getElementById('htUserdata2').value = G.htUserdata2;
    …
if ( G.ermsg !=='')    alert(G.ermsg);
</script></body></html>

Solution 6 - Php

Caller.htm

<form method="post" action="Callee.php?Query1">
    <input type="text" 	 name="PostData" />
    <input type="submit" value="Go"      />
</form>

Callee.php (Is called twice.)

if ($_POST) {
    header("Location: ". $_SERVER['REQUEST_URI']. 'Query2'); 
    // PART1: Use $_POST and $_GET to execute database updates here...

    // Now any display (i.e. echo or print) will come after the header.
    // ...

   
   die;  // When done, GET 'myself' to execute PART2 below.
}


// PART2: Results page goes here...
echo 'PART 2 display output: '; var_dump($_GET);

Notice there are two query strings involved

Look what var_dump says about $_GET:

PART 2 display output: array(1) { ["Query1Query2"]=> string(0) "" } 

Issues with putting header at the end of the POST section like this:

header("Location: ". $_SERVER['REQUEST_URI']. 'Query2'); die;

The php manual says: "Remember that header() must be called before any actual output is sent, either by normal HTML tags, blank lines in a file, or from PHP. It is a very common error to read code with include, or require, functions, or another file access function, and have spaces or empty lines that are output before header() is called. The same problem exists when using a single PHP/HTML file."

However if you need to build 'Query2' based on what happens in the POST section, it may need to be at the bottom of the POST section. This is ok, so long as you don't try to insert any echo's above it, not even for testing.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMawg says reinstate MonicaView Question on Stackoverflow
Solution 1 - PhpHannesView Answer on Stackoverflow
Solution 2 - PhpSW4View Answer on Stackoverflow
Solution 3 - PhpbcoscaView Answer on Stackoverflow
Solution 4 - PhpPeterView Answer on Stackoverflow
Solution 5 - PhpPierreView Answer on Stackoverflow
Solution 6 - PhpElliptical viewView Answer on Stackoverflow