Questions about using apache's built-in basic HTTP authentication with PHP scripts are commonplace on PHP mailing lists and USENET groups like comp.lang.php.
For information on apache's authentication, please reference the following pages from the documentation:
This article does not go into detail about setting up your Apache web server to use .htaccess files, and only briefly describes how to create a basic authentication password file (.htpasswd). For more information about setting this type of functionality, use the reference links in column to the right. This article does, however demonstrate how to use an apache htpasswd-generated file for user authentication through PHP.
HTTP authentication works through the manipulation of the response headers returned from the server to the client (or browser).
The header that defines the authentication type is called WWW-Authenticate. A typical response header asking for
"Basic" authentication for the "HTTP Auth Test" realm would look like this:
WWW-Authenticate: Basic realm="HTTP Auth Test"
When a browser receives this response from the server, it then attempts to send a user name and password to the server. If the information is not availabe (or is incorrect), the server will send the response header again. When the browser receives this information a second time, the user is prompted to enter the credentials for authentication to this realm. This is accomplished most commonly by having a dialog window pop up with the fields for the user to fill in. When the user submits the information, the browser then sends it to the web server. If the user name and password are accepted, the request is completed. If authentication fails, the web server will then respond with a header similar to this:
HTTP/1.0 401 Unauthorized
The first thing that needs to be done is to create your password file by using apache's htpasswd. In our case, we will name the file
.htpasswd and add a user named testing. Since our file does not exist yet, we need to pass the -c
option to our call. First, we will open a shell on the server (ssh, local, telnet, whichever you prefer or have access to). In the
command exmaples below, I have changed my working directory to where I want the password file to be stored.
htpasswd -c .htpasswd testing New password: Re-type new password: Adding password for user testing
To add a user to an existing password file, simply omit the create flag:
htpasswd .htpasswd tester New password: Re-type new password: Adding password for user tester
When you have completed this profess, the contents of your password file should look something similar to the following:
tester:NO/etHNQPJq2. tester2:6RcAW5mkHgVWk tester3:zDqGjrMFrAPkE
By using PHP to modify the server response to include the correct headers, a programmer can bypass the need to use a .htaccess file
or define the authentication in a Directory directive in the web site's server or VirtualHost definition.
This allows the programmer to force authentication for specific files rather than for whole directories.
When a user has submitted the authentication credentials, entries are made in PHP's super global $_SERVER array.
These entries are PHP_AUTH_USER and PHP_AUTH_PW. They are also included with each subseqent request.
We can take advantage of this by constructing a simple function that takes the user name and password and compares them to what is found in the htpasswd file. Below is an example function that does just that. Currently, this function only supports DES and PLAIN encryption types. Apache's default is to use DES encryption, and PLAIN (plain text) is only supported on Windows platforms.
<?php
/**
* Authenticate a user against a password file generated by Apache's httpasswd
* using PHP rather than Apache itself.
*
* @param string $user The submitted user name
* @param string $pass The submitted password
* @param string $pass_file='.htpasswd' The system path to the htpasswd file
* @param string $crypt_type='DES' The crypt type used to create the htpasswd file
* @return bool
*/
function http_authenticate($user,$pass,$pass_file='.htpasswd',$crypt_type='DES'){
// the stuff below is just an example useage that restricts
// user names and passwords to only alpha-numeric characters.
if(!ctype_alnum($user)){
// invalid user name
return FALSE;
}
if(!ctype_alnum($pass)){
// invalid password
return FALSE;
}
// get the information from the htpasswd file
if(file_exists($pass_file) && is_readable($pass_file)){
// the password file exists, open it
if($fp=fopen($pass_file,'r')){
while($line=fgets($fp)){
// for each line in the file remove line endings
$line=preg_replace('`[\r\n]$`','',$line);
list($fuser,$fpass)=explode(':',$line);
if($fuser==$user){
// the submitted user name matches this line
// in the file
switch($crypt_type){
case 'DES':
// the salt is the first 2
// characters for DES encryption
$salt=substr($fpass,0,2);
// use the salt to encode the
// submitted password
$test_pw=crypt($pass,$salt);
break;
case 'PLAIN':
$test_pw=$pass;
break;
case 'SHA':
case 'MD5':
default:
// unsupported crypt type
fclose($fp);
return FALSE;
}
if($test_pw == $fpass){
// authentication success.
fclose($fp);
return TRUE;
}else{
return FALSE;
}
}
}
fclose($fp);
}else{
// could not open the password file
return FALSE;
}
}else{
return FALSE;
}
}
?>
To see this code in use, check out the password protected page. The user is tester
and the password is testing.
All code and scripts available for download on http://koivi.com are written by Justin Koivisto, ZCE and fall under the GNU Lesser General Public License (LGPL) Version 2.1 (unless noted otherwise). The full license agreement can be found within the LICENSE file within each distribution package.
© 2004 - Justin Koivisto, ZCE
Valid XHTML 1.0