HTTP authentication with PHP

In my last article I showed you how to Password Protect with htaccess and htpasswd, and how to use PHP to add to your htpasswd file. In this article, I’ll show you how to use HTTP authentication, just like using htaccess, but this time you’ll be able to verify the login against a database.

So why would you want to do it this way? Well using htpasswd files to store logins can be quick and easy for a small number of logins, but if you get over 100 then things will begin to slow down. The way apache checks the file is by starting from the beginning, and checking against each line. So that means if the username and password they entered was invalid, it would go through ALL 100 lines. AND on top of that, it checks every time they access a page.

The Code

<?php
  if (!isset($_SERVER['PHP_AUTH_USER'])) {
   header('WWW-Authenticate: Basic realm="My Realm"');
   header('HTTP/1.0 401 Unauthorized');
   echo 'Text to send if user hits Cancel button';
   exit;
  } else {
   echo "<p>Hello {$_SERVER['PHP_AUTH_USER']}.</p>";
   echo "<p>You entered {$_SERVER['PHP_AUTH_PW']} as your password.</p>";
  }
?>

The Explaination
Lines 2-6: This simply sends out the headers to make that login prompt appear if they aren’t logged in.

Lines 8-9: This outputs the login they used. Note that in a real site you would check the login against a database of some sort.

Quick Tip
Once the user has been verified, you could set some kind of session up and then check the session information each page view instead of re-checking the database every time.

PHP Password Protection

Learning how to use Password Protection with htaccess and htpasswd files can make it very easy to protect a large website, without modifying anything or playing with sessions. In this tutorial I’ll show you just how to do that, and how to easily add users to the htpasswd file.

htaccess

AuthName "Restricted Area" 
AuthType Basic 
AuthUserFile /home/username/hiddenfiles/.htpasswd
AuthGroupFile /dev/null 
require valid-user

This example .htaccess file should be placed within the folder you want protected. Notice the AuthUserFile – This should be the full path to your .htpasswd file, and it should be below your public_html folder so users cannot view it.

htpasswd Script

<?
$cryptedpw = crypt($password, substr(rand(), 0, 2));

$fp = fopen("/home/username/hiddenfiles/.htpasswd","a");
fwrite($fp, "$username:$cryptedpw\n");
fclose($fp);
?>

This script is pretty simple – it is just appending “username:encryptedpassword” to the .htpasswd file. Just remember to have the path the same as in the htaccess file, so it adds the users to the correct one.

To encrypt the password we just pass it through PHP’s crypt function, with a random 2 digit salt.

PHP HTML Email Sender

Tired of the same old boring text newsletter? Well send your next out in HTML using this PHP script.

The Code

<?
$theboundary = md5(uniqid(""));

$header = "From: \"$fromname\" <$fromemail>";
$header .= "\nMIME-Version: 1.0";
$header .= "\nContent-Type: multipart/alternative;";
$header .= "\n        boundary=\"----=_NextPart_$theboundary\"";
$header .= "\nX-Priority: 3";
$header .= "\nX-MSMail-Priority: Normal";

$htmlmessage = file_get_contents("htmlemail.html");
$textmessage = file_get_contents("htmlemail.txt");

$body = "This is a multi-part message in MIME format.\n\n";
$body = "------=_NextPart_$theboundary\nContent-Type: text/plain;\n\n";
$body .= $textmessage;
$body .= "\n------=_NextPart_$theboundary\nContent-Type: text/html;\n\n";
$body .= $htmlmessage;
$body .= "\n\n";

mail($to, $subject, $body, $header);
?>

The Explaination
Line 2: Creates a string to be used as a boundary between different sections of the email.

Line 4: “From” Header
Line 5: MIME Version Header
Line 6: Header declaring multiple parts
Line 7: Header declaring part boundary
Line 8-9: Sets the email priority

Line 12: Gets the HTML version of email
Line 13: Gets the TEXT version of email

Line 15: Tells viewer its in multiple parts
Line 16: Begins TEXT part
Line 18: Begins HTML part

Conclusion
Sending HTML emails is very easy, once you know the format of sending one. Just remember to not overdo the HTML page, as it will increase bandwidth if you do a mass mail, and some people dont like big emails ;-)

PHP Image Sizes

You might need the size of an image for many reasons – in this tutorial I’ll go over the simple task of getting this information.

The Code

<?
$info = getimagesize("image.gif");
$width = $info[0];
$height = $info[1];
$type = $info[2];
$attr = $info[3];
?>

The function getimagesize returns an array with 4 values. I’ve written the above example so you can clearly see which indexes return which information – below you can see a shorter way of getting the same result.

<?
list($width, $height, $type, $attr)
       = getimagesize("image.gif");
?>

Using the Sizes
If you want to use the output to display an image, with the correct html width and height, you can do the following..

<?
echo "<img src=\"image.gif\" width=\"$width\"".
     " height=\"$height\">";
?>

Or if you want you can use the $attr which contains the html width & height code already:

<?
echo "<img src=\"image.gif\" $attr>";
?>

Uploading with PHP

There are all sorts of cool things you can do with a file upload script – upload banners for a banner rotator, upload avatars for a forum, upload zips for a download site, the list goes on.

You may not have realized it, but uploading in PHP is very easy. Here we’ll go over the two basic parts of uploading, the upload form, and the upload script.

Upload Form

<form enctype="multipart/form-data" action="upload.php" method="POST">
    <input type="hidden" name="MAX_FILE_SIZE" value="30000" />
    Send this file: <input name="userfile" type="file" />
    <input type="submit" value="Send File" />
    <input type="hidden" name="action" value="submit">
</form>

This is your basic upload form. Some key things to point out: MAX_FILE_SIZE is what sets the max size. Note that if the PHP ini has a smaller max file size, the ini size is used. enctype If the data encoding type is not defined in this way, it just won’t work.

Upload Script

<?
if ($action == "submit") {
$uploaddir = '/full/path/to/final/folder/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
   echo "Success: File uploaded.";
} else {
   echo "Error: File not uploaded.";
}
exit();
}
?>

As you can see, PHP handles the uploading of the file automatically – it is just up to you to move the file from the temporary location to the final destination using move_uploaded_file.

PHP URL Rotator

With a URL Rotator you can advertise one URL, and spread the traffic over multiple sites. Or if you have a database of websites, you could make a “Random Site” link – a fun thing to use with blogs.

The Code

<?
$global_dbh = mysql_connect("localhost","username","password");
mysql_select_db("mydatabasename", $global_dbh);

$query = "SELECT * FROM `urls` ORDER BY `lasttime` ASC LIMIT 1";
$result = mysql_query($query, $global_dbh);
$row = mysql_fetch_array($result);

$query = "UPDATE `urls` SET `lasttime`='".time()."' WHERE `ID`='{$row["ID"]}'";
$result = mysql_query($query, $global_dbh);

Header("Location: {$row["URL"]}\n\n");
exit();
?>

Database Requirements
In this example, you only need a table having two basic fields – ID, URL, and lasttime. The ID will make it easy to update the time, make sure that it is an auto-incrementing integer. lasttime is what we will use to make this a rotator, and not a random site. You simply pick the URL that has the smallest last time.

The Explaination
The first 3 lines should be easy to understand by now, if not you’ll want to read a basic PHP/MySQL tutorial.

Lines 5-7 select a url, but pick the URL with the smallest last time, which means it is the URL that hasn’t been viewed in the longest.

Lines 9-10 update the database with the current time for the URL choses. We use the ID, and not the URL, in case there are multiple entries for the same URL.

Line 12 is a simple redirection. Remember to keep the {}’s as those allow you to use the array inside the quotes.

Lines 13-14 simply end the script execution. This really isn’t needed with a standalone script, but remember that redirecting the user doesn’t stop execution of the script – and it could become an easy way to bypass a login script if you forget, so its always good to be in the habit of using exit() after a redirect, even when its a simple script.