Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

developerWorks Community:

  • Close [x]

Learning PHP, Part 3: Authentication, objects, exceptions, and streaming

Nicholas Chase is the founder and creator of NoTooMi. In addition to technical writing for large corporations, he has been involved in website development for companies such as Lucent Technologies, Sun Microsystems, Oracle, and the Tampa Bay Buccaneers. He has been a high school physics teacher, a low-level-radioactive waste facility manager, an online science fiction magazine editor, a multimedia engineer, an Oracle instructor, and the chief technology officer of an interactive communications company. He is the author of several books, including XML Primer Plus (Sams 2002).

Summary:  This tutorial is Part 3 of a three-part "Learning PHP" series teaching you how to use PHP through building a simple workflow application. In this tutorial, you will learn about using HTTP authentication, streaming files, and how to create objects and exceptions.

03 Jan 2013 - Nicholas Chase updated content throughout this tutorial to reflect current PHP technology.

View more content in this series

Date:  03 Jan 2013 (Published 12 Jul 2005)
Level:  Intermediate PDF:  A4 and Letter (792 KB | 36 pages)Get Adobe® Reader®

Comments:  

Using HTTP authentication

In this section, you'll set up the server for HTTP authentication, so your web server can control the login process for the PHP application.

HTTP authentication

Up to now, you used a login system in which the user enters a username and password into a form, and when the user submits the form, that information is checked against the MySQL database. If it matches, the application creates a session within PHP and assigns a username to the $_SESSION array for later use.

While this process works just fine, you run into a problem when you integrate with other systems. For example, if your workflow application was part of an intranet in which users might log in with usernames from other systems, you may not want to require them to log in again. Instead, you want them to already be logged in when they get there, if they've already logged in elsewhere. This is known as a single sign-on system.

To accomplish that here, you will switch to a system in which the web server actually controls the login process. Instead of simply serving the page, the server checks for a username and password within the request from the browser, and if it doesn't see them, it tells the browser to pop up a username and password box so you can enter that information. Once you enter the information, you won't have to do it again because the browser sends it with subsequent requests.

Let's start by setting up the server.


Enabling HTTP authentication

Before you start, be aware that if you use a server other than Apache 2.X, you must check the documentation for HTTP authentication to learn how to set it up. XAMPP uses HTTP authentication, so if you use XAMPP, you're all set. (Alternatively, you can simply skip this section. You'll build in the appropriate steps so the application works with either type of authentication.)

But how does HTTP authentication actually work? First of all, the server knows what kind of security it needs to provide for each directory. One way to change that for a particular directory is to set things up in the main configuration for the server. Another way is to use an .htaccess file, which contains instructions for the directory in which it resides.

For example, you want the server to make sure all users who access your user-specific files have valid usernames and passwords. First create a directory called loggedin inside the directory in which you currently have your files. For example, if your files reside in /usr/local/apache2/htdocs, you create a /usr/local/apache2/htdocs/loggedin directory.

Now you need to tell the server that you want to override the overall security for that directory, so open the httpd.conf file and add the code in Listing 3 to it.


Listing 3. Overriding security for a directory
<Directory /usr/local/apache2/htdocs/loggedin>
 AllowOverride AuthConfig
</Directory>

(You should use the correct directory for your own setup.)

Now it's time to prepare the actual directory.


Setting authentication

Next, create a new text file and save it in the loggedin directory with the name .htaccess. Add the code in Listing 4 to it.


Listing 4. Creating the .htaccess file
AuthName "Registered Users Only"
AuthType Basic
AuthUserFile /usr/local/apache2/password/.htpasswd
Require valid-user

In Listing 4, the AuthName is the text that appears at the top of the username and password box. The AuthType specifies that you're using Basic authentication, which means that you'll send the username and password in clear text. (If you create a high-security application you'll want to investigate other options.) The AuthUserFile is the file that contains the allowable usernames and passwords. (You'll create that file in a moment.) Finally, the Require directive lets you specify who actually gets to see this content. Here, you say that you will show it to any valid user, but you also have the option to require specific users or user groups.

Restart the HTTP server so these changes can take effect.

(For XAMPP, you can do this from the XAMPP control menu, or from the Services control panel, if you've set it up as a service. For all installations of Apache V2.0, you can also call <APACHE_HOME>/bin/apachectl stop, followed by <APACHE_HOME>/bin/apachectl start.)

Next, create the password file.


Creating the password file

For all this to work, you need to have a password file that the server can check. In Adding new users to the password file, you'll look at manipulating this file from within PHP, but for now, if you have access to the command line, you can create the file directly.

First, choose a location for your .htpasswd file. It should not be in a directory that's web accessible. It's not very secure if someone can simply download and analyze it. It should also be in a location where PHP can write to it. For example, you might create a password directory in your apache2 directory. Whichever location you choose, make sure you have the correct information in your .htaccess file.

To create the password file, you need the htpasswd application, which comes with Apache. If you use XAMPP, look for it in <XAMPP_HOME>/apache/bin. Execute the following command in Listing 5, substituting your own directory and username: htpasswd -c /usr/local/apache2/password/.htpasswd roadnick.

You are then prompted to type, then repeat, the password, as in Listing 5.


Listing 5. Creating the .htpasswd file
htpasswd -c /usr/local/apache2/password/.htpasswd NickChase
New password:
Re-type new password:
Adding password for user NickChase

The -c switch tells the server to create a new file, so after you add the new user, the file looks something like this: NickChase:IpoRzCGnsQv.Y.

Note that this version of the password is encrypted, and you must keep that in mind when you add passwords from your application.

Now let's see it in action.


Logging in

To see this in action, you need to access a file in the protected directory. Move the uploadfile.php and uploadfile_action.php files into the loggedin directory, and copy index.php into the loggedin directory as display_files.php.

In each of the three files, change the include() statements to account for the new location, as in Listing 6.


Listing 6. Displaying files
<?php

   session_start();
   include ("../top.txt");
   include ("../scripts.txt");

   echo "Logged in user is ".$_SERVER['PHP_AUTH_USER'];

   display_files();

   include ("../bottom.txt");

?>

In this case, you fix the references to the included files, but you also reference a variable that should be set when the browser sends the username and password. Point your browser to http://localhost/loggedin/display_files.php to see this in action. As you can see in Figure 3, you should get a username and password box.


Figure 3. Username and password box
Screen capture of the username and password box

Enter the username and password you used in Creating the password file to see the actual page.


Using the login information

At this point, you've entered the username and login, so you can see the page. As Figure 3 shows, while the message says the user has logged in, the actual content doesn't seem to agree. You still see the Register and Login links, and the list of files still shows only those that an administrator has approved—and not those that the current user has uploaded and are still pending, as you can see in Figure 4.


Figure 4. Logged in ... sort of
Screen capture of a log in ... sort of

To solve these problems, you have two choices. The first is to go back and recode every instance in which the application references the username to look for the $_SERVER['PHP_AUTH_USER'], instead of $_SESSION["username"]. Good programmers are inherently lazy, however, so that's not a particularly attractive option.

The second choice is to simply set $_SESSION["username"] based on $_SERVER['PHP_AUTH_USER'] so everything will continue to work as it did before. You can do this in top.txt, right after you start a new session or join the existing one (see Listing 7).


Listing 7. Setting the current user
<?php

  if (isset($_SESSION["username"])){
      //Do nothing
  } elseif (isset($_SERVER['PHP_AUTH_USER'])) {
      $_SESSION["username"] = $_SERVER['PHP_AUTH_USER'];
  }

?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  <head>
...

The only way to make the browser "forget" the username and password you entered is to close the browser so you give the $_SESSION["username"] variable precedence. That way, you have the option to enable users to log in as someone else. (You won't do that here, but you do have the option.)

Next, if neither the $_SESSION nor $_SERVER variable is set, nothing happens, and the page continues on as though the user isn't logged in, which happens to be the case. Making this one simple change fixes your login problem, as you can see in Figure 5.


Figure 5. The corrected page
Screen capture of the corrected page

Fixing the interface

Before you add a new user, you need to make a couple of quick fixes to top.txt to accommodate the new structure. For one thing, you need to change the Login link so that rather than pointing to your old login.php page, it points to the newly secured display_files.php file. When the user attempts to access it, the browser will provide a way to log in (see Listing 8).


Listing 8. Adjusting the navigation
...
<div id="nav1">
   <ul style='float: left'>
      <li><a href="#" shape="rect">Home</a></li>
      <li><a href="/uploadfile.php" shape="rect">Upload</a></li>
      ><li><a href="/loggedin/display_files.php" shape="rect">Files
</a></li>>
       <?php
          if (isset($_SESSION["username"]) || isset($username)){
             if (isset($_SESSION["username"])){
                $usernameToDisplay =  $_SESSION["username"];
             } else {
                $usernameToDisplay = $username;
             }
      ?>
      ><!--> <li><a href="logout.php" shape="rect">Logout</a>
</li>   -->
            <li><p style='color:white;'>&nbsp;&nbsp;&nbsp;
Welcome,
                   <b><?=$usernameToDisplay?></b>.</p></li>
       <?php
          } else {
       ?>
            <li><a href="/registration.php" shape="rect">
Register</a></li>
            <li><a href=">/loggedin/display_files.php" 
shape="rect">Login</a></li>
       <?php
          }
       ?>
   </ul>
</div>
...

Notice that in addition to fixing the login reference and adding a new option for displaying the list of files, I commented out the message about logging out, because that subject is beyond the scope of this tutorial.

Now you just need to integrate the registration process with the password file.


Adding new users to the password file

The last step in this process is to integrate your registration with the .htpasswd file. To do that, you simply need to add a new entry to .htpasswd once you save the user to the database. Open registration_action.php and add the contents of Listing 9.


Listing 9. Creating the user on the server at registration
...
    if ($checkUserStmt->rowCount() == 0) {

        $stmt = $dbh->prepare("insert into users (username, email, password) ".
                                                                 "values (?, ?, ?)");

        $stmt->bindParam(1, $name);
        $stmt->bindParam(2, $email);
        $stmt->bindParam(3, $pword);

        $name = $_POST["name"];
        $email = $_POST["email"];
        $pword = $passwords[0];

        $stmt->execute();

        $pwdfile = '/usr/local/apache2/password/.htpasswd';
        if (is_file($pwdfile)) {
            $opencode = "a";
        } else {
            $opencode = "w";
        }
        $fp = fopen($pwdfile, $opencode);
        $pword_crypt = crypt($passwords[0]);
        fwrite($fp, $_POST['name'] . ":" . $pword_crypt . "\n");
        fclose($fp);

        echo "<p>Thank you for registering!</p>";

    } else {

        echo "<p>There is already a user with that name: </p>";
...

Before you start, if you have a .htpasswd file already, make sure the user running Apache can write to it on your web server. If not, make sure the user can write to the appropriate directory.

First, check to see if the file exists and use that information to determine whether you will write a new file or append information to an existing file. Once you know, go ahead and open the file.

As you saw in Creating the password file, the password is stored in encrypted form, so you can use the crypt() function to get that string. Finally, write the username and password out to the file and close the file.

To test this, quit the browser to clear out any cached passwords, then open http://localhost/index.php.

Click Register and create a new account. When you finish creating the account, quit the browser again and try to access a protected page. Your new username and password should work.

3 of 11 | Previous | Next

Comments



static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source, Linux, XML
ArticleID=133669
TutorialTitle=Learning PHP, Part 3: Authentication, objects, exceptions, and streaming
publish-date=01032013
author1-email=ibmquestions@nicholaschase.com
author1-email-cc=