No HTML and no output of any kind (using echo or print) can be put above the header function.
It is requirement of the HTTP protocol that all HTTP messages have a header.
The header function lets you modify the header information that is sent to the browser before the message body (the HTML).
Each time you send HTML to the browser, without specifying a header, a header is automatically generated and sent with the HTML, so that the server sends a valid HTTP message.
So when you try to modify the header afterwards, you cause an error because the header has already been sent, even if you didn't want it so. That's why any header manipulation must take place in the script above any HTML and any echo or print instruction.
You can move your function definition and the isset test above the doctype declaration.
You don't need to put the HTML in an else block because the script will exit if the authentication fails anyway :
<?php
function authenticate() {
header('WWW-Authenticate: Basic realm="Test Authentication System"');
header('HTTP/1.0 401 Unauthorized');
echo "You must enter a valid login ID and password to access this resource\n";
exit;
}
if (!isset($_SERVER['PHP_AUTH_USER']) ||
($_POST['SeenBefore'] == 1 && $_POST['OldAuth'] == $_SERVER['PHP_AUTH_USER'])) {
authenticate();
}
?>
<!doctype html public "-//W3C//DTD HTML 4.0 //EN">
<html>
<head>
<title>Title here!</title>
</head>
<body>
<?php
echo "<p>Welcome: {$_SERVER['PHP_AUTH_USER']}<br>";
echo "Old: {$_REQUEST['OldAuth']}";
echo "<form action='{$_SERVER['PHP_SELF']}' METHOD='POST'>\n";
echo "<input type='hidden' name='SeenBefore' value='1'>\n";
echo "<input type='hidden' name='OldAuth' value='{$_SERVER['PHP_AUTH_USER']}'>\n";
echo "<input type='submit' value='Re Authenticate'>\n";
echo "</form></p>\n";
?>
</body>
</html>