Programming PHPProgramming PHPSearch this book

7.5. Setting Response Headers

As we've already discussed, the HTTP response that a server sends back to a client contains headers that identify the type of content in the body of the response, the server that sent the response, how many bytes are in the body, when the response was sent, etc. PHP and Apache normally take care of the headers for you, identifying the document as HTML, calculating the length of the HTML page, and so on. Most web applications never need to set headers themselves. However, if you want to send back something that's not HTML, set the expiration time for a page, redirect the client's browser, or generate a specific HTTP error, you'll need to use the header( ) function.

The only catch to setting headers is that you must do so before any of the body is generated. This means that all calls to header( ) (or setcookie( ), if you're setting cookies) must happen at the very top of your file, even before the <html> tag. For example:

<?php
 header('Content-Type: text/plain');
?>
Date: today
From: fred
To: barney
Subject: hands off!
  
My lunchbox is mine and mine alone. Get your own,
you filthy scrounger!

Attempting to set headers after the document has started results in this warning:

Warning:  Cannot add header information - headers already sent

7.5.3. Expiration

A server can explicitly inform the browser, and any proxy caches that might be between the server and browser, of a specific date and time for the document to expire. Proxy and browser caches can hold the document until that time or expire it earlier. Repeated reloads of a cached document do not contact the server. However, an attempt to fetch an expired document does contact the server.

To set the expiration time of a document, use the Expires header:

header('Expires: Fri, 18 Jan 2002 05:30:00 GMT');

To expire a document three hours from the time the page was generated, use time( ) and gmstrftime( ) to generate the expiration date string:

$now = time( );
$then = gmstrftime("%a, %d %b %Y %H:%M:%S GMT", $now + 60*60*3);
header("Expires: $then");

To indicate that a document "never" expires, use the time a year from now:

$now = time( );
$then = gmstrftime("%a, %d %b %Y %H:%M:%S GMT", $now + 365*86440);
header("Expires: $then");

To mark a document as already expired, use the current time or a time in the past:

$then = gmstrftime("%a, %d %b %Y %H:%M:%S GMT");
header("Expires: $then");

This is the best way to prevent a browser or proxy cache from storing your document:

header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");

For more information on controlling the behavior of browser and web caches, see Chapter 6 of Web Caching, by Duane Wessels (O'Reilly).

7.5.4. Authentication

HTTP authentication works through request headers and response statuses. A browser can send a username and password (the credentials ) in the request headers. If the credentials aren't sent or aren't satsifactory, the server sends a "401 Unauthorized" response and identifies the realm of authentication (a string such as "Mary's Pictures" or "Your Shopping Cart") via the WWW-Authenticate header. This typically pops up an "Enter username and password for ..." dialog box on the browser, and the page is then re-requested with the updated credentials in the header.

To handle authentication in PHP, check the username and password (the PHP_AUTH_USER and PHP_AUTH_PW elements of $_SERVER) and call header( ) to set the realm and send a "401 Unauthorized" response:

header('WWW-Authenticate: Basic realm="Top Secret Files"');
header("HTTP/1.0 401 Unauthorized");

You can do anything you want to authenticate the username and password; for example, you could consult a database, read a file of valid users, or consult a Microsoft domain server. This example checks to make sure that the password is the username, reversed:

$auth_ok = 0;
$user = $_SERVER['PHP_AUTH_USER'];
$pass = $_SERVER['PHP_AUTH_PW'];
if (isset($user) && isset($pass) && $user === strrev($pass)) {
  $auth_ok = 1;
}
if (!$auth_ok) {
  header('WWW-Authenticate: Basic realm="Top Secret Files"');
  header('HTTP/1.0 401 Unauthorized');
}

Putting this into a document gives something like:

<?php
 $auth_ok = 0;
 $user = $_SERVER['PHP_AUTH_USER'];
 $pass = $_SERVER['PHP_AUTH_PW'];
 if (isset($user) && isset($pass) && $user === strrev($pass)) {
   $auth_ok = 1;
 }
 if (!$auth_ok) {
   header('WWW-Authenticate: Basic realm="Top Secret Files"');
   header('HTTP/1.0 401 Unauthorized');
   // anything else printed here is only seen if the client hits "Cancel"
 }
?>
}<!-- your password-protected document goes here -->

If you're protecting more than one page, put the above code into a separate file and include it at the top of every protected page.



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.