I thought I’d test out this syntax highlighter by showing an example of creating a secure download site in PHP…

So, let me preface this by saying that I wanted a dead simple way to manage multiple users, each with separate files and passwords, all with some resemblance to a secured site using Auth-Digest authentication.  To me that meant no databases involved and no files accessible directly from the site root.

What I ended up with was this – a folder located outside the site root that contains sub-folders for each user.  Each sub-folder represents a particular user – at the moment, the folder name is the user name, however that could easily be changed.  Within that folder is a password file called “.auth.txt” which, obviously, contains the users password.

Update:

I realized that I screwed up the logic that actually retrieved the file for the user, so that is fixed now.

So, here we go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
<?php
 
$realm = 'Restricted area';
$logged_in = false;
 
$users = loadUsers("/home/dhm116/Secured");
//var_dump($users);
 
if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
    header('HTTP/1.1 401 Unauthorized');
    header('WWW-Authenticate: Digest realm="'.$realm.
           '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
 
    die('You may not access this area without properly authenticating');
}
 
 
// analyze the PHP_AUTH_DIGEST variable
if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) ||
    !isset($users[$data['username']]))
	{
		header('HTTP/1.1 401 Unauthorized');
		header('WWW-Authenticate: Digest realm="'.$realm.
			   '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
		die('Wrong Credentials!');
	}
 
// generate the valid response
$A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]["pwd"]);
$A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
$valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);
 
if ($data['response'] != $valid_response)
{
	header('HTTP/1.1 401 Unauthorized');
	header('WWW-Authenticate: Digest realm="'.$realm.
		   '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
	die('Wrong Credentials!');
}
 
// ok, valid username & password
//echo 'Your are logged in as: ' . $data['username'];
$logged_in = true;
 
// function to parse the http auth header
function http_digest_parse($txt)
{
    // protect against missing data
    $needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
    $data = array();
    $keys = implode('|', array_keys($needed_parts));
 
    preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER);
 
    foreach ($matches as $m) {
        $data[$m[1]] = $m[3] ? $m[3] : $m[4];
        unset($needed_parts[$m[1]]);
    }
 
    return $needed_parts ? false : $data;
}
 
if(isset($_GET["file"]) && $logged_in)
{
	send_download($_GET["file"]);
}
 
function send_download($filename)
{
	$file_path = '/home/dhm116/Secured/'.$_GET["user"].'/'. $filename;
 
	if(file_exists($file_path))
	{
		$file_size=@filesize($file_path);
		header("Content-Type: application/x-zip-compressed");
		header("Content-disposition: attachment; filename=\"$filename\"");
		header("Content-Length: $file_size");
		readfile($file_path);
		exit;
	}
} 
 
function loadUsers ($directory) 
{
    // create a handler for the directory
    $handler = opendir($directory);
 
    // keep going until all files in directory have been read
    while (false !== ($file = readdir($handler))) {
        // if $file isn't this directory or its parent, 
        // add it to the results array
        if ($file != '.' && $file != '..' && is_dir($directory."/".$file))
		{
			$myFile = $directory."/".$file."/.auth.txt";
 
			if(file_exists($myFile))
			{
				$fh = fopen($myFile, 'r');
 
				// Load and set the user password
				$users[$file]["pwd"] = fread($fh, filesize($myFile)-1);
 
				fclose($fh);	
 
				// Set the files within that user directory
				$users[$file]["files"] = dirList($directory."/".$file);
			}
		}
    }
 
    // tidy up: close the handler
    closedir($handler);
 
    // done!
    return $users;
}
 
function dirList ($directory) 
{
    // create an array to hold directory list
    $results = array();
 
    // create a handler for the directory
    $handler = opendir($directory);
 
    // keep going until all files in directory have been read
    while (false !== ($file = readdir($handler))) {
 
        // if $file isn't this directory or its parent, 
        // add it to the results array
        if ($file != '.' && $file != '..' && $file != '.auth.txt')
            $results[] = $file;
    }
 
    // tidy up: close the handler
    closedir($handler);
 
    // done!
    return $results;
 
}
?>
<html>
	<head><h1>Secure Download Area</h1></head>
	<body>
		<p>Files available for <?php echo $data['username']; ?></p>
		<ul>
		<?php
			$filelist = $users[$data["username"]]["files"];
 
			foreach($filelist as $i => $value)
			{
		?>
			<li><a href="securedownload.php?user=<?php echo $data['username'] ?>&file=<?php echo $value; ?>">Download <?php echo $value; ?></a></li>
		<?php
			}
		?>
		</ul>
	</body>
</html>