It is very common to handle form posts at the top of a PHP script that prints HTML. This happens most frequently on CRUD screens where a form will post back to itself to handle the updates. There are several reasons why this is not good practice including:

  • Page reloads. If the user reloads this page, the form will be resubmitted along with the post parameters. This will cause your script to execute the CRUD logic again, and also causes confusion with the end user.
  • Maintainability. This is doesn’t do proper separation of display and logic. In order to promote readable and maintainable code, it is usually best to keep all your processing functions separate from your display.

Here’s a simple example of how to do this poorly:

<?php
  include_once("classes/UserDao.php");
  $username = $_POST['username'];
  $password = $_POST['password'];
  if (UserDao::authenticate($username, $password)) {
      echo "Invalid username or password.";
      exit;
  }

  echo "<html><body>";
  echo "<p>Congrats! You signed in!</p>";
  echo "</body></html>";
?>

A better way to handle form posts is to create separate scripts to handle the POST processing and the display. In my PHP sites, scripts that process a post are prefixed with an underscore and they use Location redirects with the header() function. These scripts do not echo anything, they simply process the request and forward on to a display page. Usually, they will update session variables or save to the database.

Another convention I use is to never use SQL inside of the web root. Since the POST scripts are inside my web root, this forces me to write classes to encapsulate all my database logic. In fact, most logic is encapsulated in classes to make unit testing easier.

Reworking our previous example above, I’ve created a script called “_authenticate.php” that a sign in form would post to. Notice it doesn’t display anything, and all SQL and authentication logic has been abstracted into the UserDao class.

<?php
include_once("classes/UserDao.php");
session_start();
$username = $_POST['username'];
$password = $_POST['password'];
if (UserDao::authenticate($username, $password)) {
    $_SESSION['username'] = $username;
    header("Location: /dashboard.php");
} else {
    $_SESSION['username'] = null;
    $_SESSION['flash_error'] = "Bad username or password.";
    header("Location: /signin.php");
}
?>

Using this method will make your code more readable and understandable, and whoever has to maintain your code later will thank you.