.htpasswd在线生成PHP程序
在线管理.htpasswd里的用户和密码,有验证,添加,删除,更改的功能.
这是我写的应用例子:
<style type="text/css">
* {font: 12px Tahoma;}
h1 {font: 14px Tahoma bold; text-align: center; color: blue;}
h2 {font: 14px Tahoma bold ; text-align: center; color: blue;}
body {padding: 0; text-align: center;}
strong {color: blue;}
em {color: red;}
#form {margin: 20px auto; text-align: left; width: 260px; padding: 10px 30px; background: #F9F9F9; border: 8px solid #EEE;}
#msg {margin: 20px auto; text-align: center; width: 260px; padding: 30px; background: #F9F9F9; border: 8px solid #EEE;}
hr {border: 1px solid #EEE; height: 1px;}
</style>
<div id="form">
<h1>.htpasswd用户管理</h1>
<form action="<?php echo $_SERVER['PHP_SELF']?>" method="post">
用户 : <input name="username" type="text" /><br />
密码 : <input name="password" type="text" /><br />
<input name="action" value="verify" checked="checked" type="radio" /> 校验密码 <br />
<input name="action" value="add" type="radio" /> 添加新用户<br />
<input name="action" value="delete" type="radio" /> 删除用户 <br />
<input name="action" value="change" type="radio" /> 更改密码 <br /><br />
<input type="submit" name="Submit" value="提交" />
</form>
</div>
<?php
include("class_htpasswd.php");
$htpasswdfile = ".htpasswd";
if (!$_POST) exit;
if (!$_POST['action'] || !$_POST['username'] || !$_POST['password']) exit('<h1>提交数据不完整!</h1>');
$action = $_POST['action'];
$username = $_POST['username'];
$password = $_POST['password'];
$hp = new Htpasswd($htpasswdfile);
switch ($action) {
case 'add':
$action_txt = '添加用户';
$retval = $hp->addUser($username, $password);
if($retval) {
$msg = "<strong>用户 $username 密码 $password 添加成功!</strong>";
} else {
$msg = "<em>用户 $username 密码 $password 添加失败.</em>";
}
break;
case 'change':
$action_txt = '更改密码';
$retval = $hp->changePass($username, $password);
if($retval) {
$msg = "<strong>用户 $username 的密码更改为 $password 成功!</strong>";
} else {
$msg = "<em>用户 $username 的密码更改为 $password 失败.</em>";
}
case 'delete':
$action_txt = '删除用户';
$retval = $hp->deleteUser($username);
if($retval) {
$msg = "<strong>用户 $username 删除成功!</strong>";
} else {
$msg = "<em>用户 $username 删除失败.</em>";
}
break;
case 'verify':
$action_txt = '校验密码';
$retval = $hp->verifyUser($username, $password);
if($retval) {
$msg = "<strong>用户 $username 密码 $password 校验成功!</strong>";
} else {
$msg = "<em>用户 $username 密码 $password 校验失败.</em>";
}
break;
default:
break;
}
echo <<< ANDY
<div id="msg">
您刚进行了此项操作,请核查<hr />
<h2>$action_txt</h2>
<p>$msg</p>
</div>
ANDY;
* {font: 12px Tahoma;}
h1 {font: 14px Tahoma bold; text-align: center; color: blue;}
h2 {font: 14px Tahoma bold ; text-align: center; color: blue;}
body {padding: 0; text-align: center;}
strong {color: blue;}
em {color: red;}
#form {margin: 20px auto; text-align: left; width: 260px; padding: 10px 30px; background: #F9F9F9; border: 8px solid #EEE;}
#msg {margin: 20px auto; text-align: center; width: 260px; padding: 30px; background: #F9F9F9; border: 8px solid #EEE;}
hr {border: 1px solid #EEE; height: 1px;}
</style>
<div id="form">
<h1>.htpasswd用户管理</h1>
<form action="<?php echo $_SERVER['PHP_SELF']?>" method="post">
用户 : <input name="username" type="text" /><br />
密码 : <input name="password" type="text" /><br />
<input name="action" value="verify" checked="checked" type="radio" /> 校验密码 <br />
<input name="action" value="add" type="radio" /> 添加新用户<br />
<input name="action" value="delete" type="radio" /> 删除用户 <br />
<input name="action" value="change" type="radio" /> 更改密码 <br /><br />
<input type="submit" name="Submit" value="提交" />
</form>
</div>
<?php
include("class_htpasswd.php");
$htpasswdfile = ".htpasswd";
if (!$_POST) exit;
if (!$_POST['action'] || !$_POST['username'] || !$_POST['password']) exit('<h1>提交数据不完整!</h1>');
$action = $_POST['action'];
$username = $_POST['username'];
$password = $_POST['password'];
$hp = new Htpasswd($htpasswdfile);
switch ($action) {
case 'add':
$action_txt = '添加用户';
$retval = $hp->addUser($username, $password);
if($retval) {
$msg = "<strong>用户 $username 密码 $password 添加成功!</strong>";
} else {
$msg = "<em>用户 $username 密码 $password 添加失败.</em>";
}
break;
case 'change':
$action_txt = '更改密码';
$retval = $hp->changePass($username, $password);
if($retval) {
$msg = "<strong>用户 $username 的密码更改为 $password 成功!</strong>";
} else {
$msg = "<em>用户 $username 的密码更改为 $password 失败.</em>";
}
case 'delete':
$action_txt = '删除用户';
$retval = $hp->deleteUser($username);
if($retval) {
$msg = "<strong>用户 $username 删除成功!</strong>";
} else {
$msg = "<em>用户 $username 删除失败.</em>";
}
break;
case 'verify':
$action_txt = '校验密码';
$retval = $hp->verifyUser($username, $password);
if($retval) {
$msg = "<strong>用户 $username 密码 $password 校验成功!</strong>";
} else {
$msg = "<em>用户 $username 密码 $password 校验失败.</em>";
}
break;
default:
break;
}
echo <<< ANDY
<div id="msg">
您刚进行了此项操作,请核查<hr />
<h2>$action_txt</h2>
<p>$msg</p>
</div>
ANDY;
?>
导入
<?php/* **************************************************************
* $Id: class.htpasswd.php,v 1.5 2002/11/11 07:27:40 phps Exp $
Revision 0.9 1999/01/27 16:41:00 cdi@thewebmasters.net
Public Methods:
initialize version
sane do_not_blame_cdi cryptPass
isUser getPass verifyUser
changePass addUser genSalt
deleteUser getUserNum assignPass
renameUser
Internal Methods:
utime htReadFile htWriteFile
error genPass
*/
// **************************************************************
/* History
**************************************************************
Rev 0.9 +renameUser(), -$UID
Added the renameUser() method per a request
from Rainer Scholz <jrs@startrek.franken.de>
(A good idea :)
Cleaned up some variables that were declared
but no longer in use. Changed a few error msgs.
It's amazing how much junk you can spot if you
step away from the code for a week. :)
Removed the UID global. It was used during some
of the more anal sane() checks and should have
been removed when sane() was changed in 0.7
**************************************************************
**************************************************************
Revision 0.8 1999/01/17 15:20:00 cdi@thewebmasters.net
Rev 0.8 Fixed the new() method so that it could
be called with an empty value, rather
than requiring the htpasswd file info.
**************************************************************
Revision 0.7 1999/01/14 15:34:00 cdi@thewebmasters.net
Rev 0.7 -chconvert(), +Htpasswd()
Added the Htpasswd() method. Initialize() can
now be done if the new() method is given the
path and filename as in
$Htpasswd = new Htpasswd("/path/to/file");
This makes it easier to port Perl programs that
used Apache::Htpasswd. Besides, the method is
much cleaner this way. Initialize() can still
be called manually if you want to force a
refresh on the $FILE contents.
Removed a LOT of the sane() stuff. It finally
dawned on me that it just isn't my job to make
sure the programmer knows what the hell they're doing.
sane() now only makes 4 basic checks. (is_writeable,
is_readable, is_directory and is_symlink). If the
first 2 fail or if the last 2 succeed, sane() fails.
The mods to sane() removed the need for chconvert()
Added some Win32 checking. Basicly it won't try to
do a "*nix" thing to a Win box if WIN32 is set to
true. Other than that, you're on your own.
Fixed genSalt() to keep it from generating invalid
salts. (Outside the range [a-zA-Z./] )
Fixed cryptPass() so that it no longer needs the
salt passed to it, even if the salt is empty.
It will use the salt it's given and if no salt
is given, will generate a random one.
Started work on the man page.
**************************************************************
Revision 0.6 1999/01/13 19:21:00 cdi@thewebmasters.net
Rev 0.6 +assignPass(), +genPass(), +genUser()
Cleaned up the rand() functions. Now it's
properly seeded in the initialize() method
and much more robust. Effects genPass() and genSalt()
genPass() generates a random 5 to 8 char password
genUser() generates a random 5 to 8 char UserID
assignPass(UserID) adds $UserID to password file
using a genPass() password. Returns the plain text
version of the password. genUser() just returns
a randomly generated User Name using A-Za-z0-9
genPass() generates a random password using
A-Za-z0-9 and the !@#$%^&*()-+./ characters.
**************************************************************
Revision 0.5 1999/01/12 21:07:00 cdi@thewebmasters.net
Rev 0.5 +verifyUser(), -checkPass()
Deprecated checkPass() in favor of verifyUser()
Removed the need for the $salt in verifyUser()
If salt not passed to cryptPass(), it now
automatically calls genSalt()
Removed the need for the $salt in addUser()
Added global DEBUG - set to false to not
log errors.
General code clean up, better commenting
**************************************************************
Revision 0.4 1999/01/08 14:20:00 cdi@thewebmasters.net
Rev 0.4 Hey neat - it works.
**************************************************************
Revision 0.3 1999/01/08 13:10:00 cdi@thewebmasters.net
Rev 0.3 +addUser(), +genSalt(), +deleteUser(), +utime(),
+getUserNum()
**************************************************************
Revision 0.2 1999/01/07 09:55:00 cdi@thewebmasters.net
Rev 0.2 +isUser(), +getPass(), +checkPass(), +htWriteFile(),
+changePass()
**************************************************************
Revision 0.1 1999/01/05 12:34:00 cdi@thewebmasters.net
Rev 0.1 Start - +initialize(), +version(), +error(), +sane(),
+do_not_blame_cdi(), +cryptPass(), +htReadFile(),
+chconvert()
*/
// **************************************************************
//
//
class Htpasswd {
// Globally accessable variables
var $VERSION = 'Revision 0.8 1999/01/17 15:20:00 cdi@thewebmasters.net';
//var $UID = getmyuid();
// Set this to the user ID of the process
// this program runs as. Used for sanity
// checking. Defaults to same ID as
// the file calling it.
// UID deprecated 0.9 - it was used for some of the more anal
// sane() routines - forgot to take it out in 0.7 when I should have
var $WIN32 = false; // Set to true for M$ BloatWare servers
var $FILE = ""; // Filename Holder
var $ERROR = ""; // Last error message
var $EMPTY = false; // Is the FILE empty?
var $CONTENTS = ""; // Raw htpasswd contents
var $EXISTS = false; // Boolean. True if $FILE exists
var $SANE = false; // Boolean. True if $FILE passes all tests
var $IDIOT = false; // Boolean. True if user is an idiot.
var $DEBUG = false; // Boolean. Logs errors to error_log if set
var $USERS = array(); // Array of [index#][(user|pass)]=value
var $USERCOUNT = 0; // Counter - total number of users in $FILE
// Zero based indexing on $USERS
// **************************************************************
// An auto-constructor, can initilize the filename when
// called from new()
function Htpasswd ($passwdFile = "")
{
if(!empty($passwdFile))
{
$this->initialize($passwdFile);
}
return;
}
// **************************************************************
// The Initialize function sets up the FILE, checks it
// for sanity, then loads it into the processes memory
// htReadFile() should only be called using this method.
function initialize ($passwdFile)
{
$this->FILE = $passwdFile;
srand((double)microtime()*1000000); // Seed the random number gen
if(empty($passwdFile))
{
// PHP is going to bitch about this, this is here just because
$this->error("Invalid initialize() or new() method: No file specified!",1);
exit; // Just in case
}
if(file_exists($this->FILE))
{
$this->EXISTS = true;
if($this->sane($this->FILE))
{
$this->SANE = true;
$this->htReadFile();
}
else
{
// Preserve the error generated by sane()
return;
}
}
else
{
$this->SANE=true; // Non-existant files are safe
}
return;
}
// **************************************************************
// Turns off sanity checking. Needless to say if you do this
// you're an idiot, but I'll give you the rope...
function do_not_blame_cdi ()
{
$this->IDIOT = true;
$this->error("No sanity checking on files",0);
return;
}
// **************************************************************
// Checks file sanity. Can be called publicly, giving the
// full path to the file to be checked.
// Can be disabled if you're an idiot by
// calling $Htpasswd->do_not_blame_cdi()
// Tons of junk removed Rev 0.7
function sane ($filename)
{
if ($this->IDIOT)
{
return true;
}
// If it's a Win32 box, there's no sense in doing all this
if ($this->WIN32)
{
// You're on your own
return true;
}
// Some kind of *nix machine - let's do some
// rudimentary checks
if (!(is_readable($filename)))
{
$this->error("File [$filename] not readable",0);
return false;
}
if (!(is_writeable($filename)))
{
$this->error("File [$filename] not writeable",0);
return false;
}
if(is_dir($filename))
{
$this->error("File [$filename] is a directory",0);
return false;
}
if(is_link($filename))
{
$this->error("File [$filename] is a symlink",0);
return false;
}
// I had a lot of routines in here to do a lot of checking
// on the file permissions and you know what? That
// ain't my job. It's yours.
// File is assumed to be sane - too bad I'm not.
return true;
}
// **************************************************************
// Not really needed but it's a legacy thing...
function version ()
{
return $this->VERSION;
}
// **************************************************************
// Error handling. Fatals immediately exit the program (very
// few errors generate a fatal exit. Most just carp a warning
// and continue. Logged via error_log method.
function error ($errMsg,$die)
{
$this->ERROR = $errMsg;
// croak or carp?
// If logging is turned off AND this is not
// a Fatal error, just return
if( (!($this->DEBUG)) && ($die != 1) ){
return;
}
if ($this->DEBUG)
{
error_log($this->ERROR,0);
}
if($die == 1)
{
echo "<b> ERROR $this->ERROR </b> <br /> \n";
exit;
}
return;
}
// **************************************************************
// Internal function to read the FILE and process it's contents
// Can be called publicly to re-read the file, but why would
// you want to introduce another series of system calls like that?
// This does the lions share of the work. This should only be
// called once per process, and it should be called internally
// by the initialize method. Have I mentioned that enough yet?
function htReadFile ()
{
global $php_errormsg;
$Mytemp = array();
$Myjunk = array();
$Junk = array();
$count = 0;
$user = "";
$pass = "";
$temp = "";
$key = "";
$val = "";
$filesize = 0;
$errno = 0;
$empty = false;
$contents = "";
$filename = $this->FILE;
$filesize = filesize($filename);
if($filesize < 3) { $empty = true; }
// Why did I pick 3? I dunno - seemed like the number
// to use at the time.
// (Actually, think [char]:[\n], the absolute smallest
// size a "legitimate" password file can ever be.)
if(!($empty))
{
$this->EMPTY = false;
$fd = fopen( $filename, "r" );
if(empty($fd))
{
$this->error("FATAL File access error [$php_errormsg]",1);
exit; // Just in case
}
$contents = fread( $fd, filesize( $filename ) );
fclose( $fd );
$this->CONTENTS = $contents;
$Mytemp = split("\n",$contents);
for($count=0;$count<count($Mytemp);$count++)
{
$user = "";
$pass = "";
if(empty($Mytemp[$count])) { break; }
if(ereg("^(\n|\W)(.?)",$Mytemp[$count])) { break; }
if(!(ereg(":",$Mytemp[$count])))
{
$user = $Mytemp[$count];
$errno=($count+1);
$this->error("FATAL invalid user [$user] on line [$errno] in [$filename]",1);
}
list ($user,$pass) = split(":",$Mytemp[$count]);
if ( ($user != "") and ($pass != "") )
{
$Myjunk[$count]["user"] = $user;
$Myjunk[$count]["pass"] = $pass;
}
}
$this->USERS = $Myjunk;
$this->USERCOUNT = $count;
}
else
{
// Empty file. Label it as such
$this->USERS = $Myjunk;
$this->USERCOUNT = -1;
$this->EMPTY = true;
}
return;
} // end htReadFile()
// **************************************************************
// Given a plain text password and salt, returns crypt() encrypted
// version. If salt is not passed or referenced, it will generate
// a random salt automatically.
function cryptPass ($passwd, $salt = "")
{
if (!($passwd))
{
// Return what we were given
// If calling this directly, do something like
// $enc_pass = $Htpasswd->cryptPass($pass);
// if (empty($enc_pass)) { BARF! }
// You should really verify the data before calling
// this though - I do.
return "";
}
if (!empty($salt))
{
//# Make sure only use 2 chars
$salt = substr ($salt, 0, 2);
}
else
{
// If no salt, generate a (pseudo) random one
$salt = $this->genSalt();
}
return (crypt($passwd, $salt));
} // end cryptPass
// **************************************************************
// Returns true if UserID is found in the password file. False
// otherwise.
function isUser ($UserID)
{
$key = "";
$val = "";
$user = "";
$pass = "";
$found = false;
if (empty($UserID)) { return false; }
if ($this->EMPTY) { return false; }
for($count=0; $count < $this->USERCOUNT; $count++ )
{
if($UserID == $this->USERS[$count]["user"])
{
$found = true;
}
}
return $found;
} // end isUser
// **************************************************************
// Fetches the encrypted password from the password file and
// returns it. Returns null on failure.
function getPass ($UserID)
{
$key = "";
$val = "";
$user = "";
$pass = "";
$usernum = -1;
if ($this->EMPTY) { return $pass; }
if (empty($UserID)) { return $pass; }
if (!($this->isUser($UserID))) { return $pass; }
$usernum = $this->getUserNum($UserID);
if($usernum == -1) { return false; }
$pass = $this->USERS[$usernum]["pass"];
return $pass;
} // end getPass
// **************************************************************
// Returns true if Users password matches the password in
// the password file.
//
// method deprecated 0.5 <cdi>
// use verifyUser() instead
//
function checkPass ($UserID, $Pass)
{
$retval = $this->verifyUser($UserID,$Pass);
return $retval;
} // end checkPass
// **************************************************************
// Returns true if Users password is authenticated, false otherwise
//
// $Pass should be passed in un-encrypted
function verifyUser ($UserID,$Pass)
{
$pass = "";
$match = false;
$usernum = -1;
$salt = "";
if ($this->EMPTY) { return false; }
if (empty($UserID)) { return false; }
if (empty($Pass)) { return false; }
if (!($this->isUser($UserID))) { return false; }
$usernum = $this->getUserNum($UserID);
if($usernum == -1) { return false; }
$pass = $this->USERS[$usernum]["pass"];
$salt = substr($pass,0,2);
$Pass = $this->cryptPass($Pass,$salt);
if ($pass == $Pass)
{
$match = true;
}
return $match;
} // end verifyUser
// **************************************************************
// Changes an existing users password. If "oldPass" is null, or
// if oldPass is not passed to this method, there is no checking
// to be sure it matches their old password.
//
// Needless to say, you shouldn't do dat, but I'll give you
// the rope...
//
// NewPass should be passed to this method un-encrypted.
//
// Returns true on success, false on failure
function changePass ($UserID, $newPass, $oldPass = "")
{
// global $php_errormsg;
$passwdFile = $this->FILE;
$pass = "";
$newname;
$newpass;
// Can't very well change the password of a non-existant
// user now can we?
if ($this->EMPTY) { return false; }
if (empty($UserID)) { return false; }
if (!($this->isUser($UserID)))
{
// No sniffing for valid user IDs please
$this->error("changePass failure for [$UserID]: Authentication Failure",0);
return false;
}
if(empty($newPass))
{
$this->error("changePass failure - no new password submitted",0);
return false;
}
$newname = strtolower($UserID);
$newpass = strtolower($newPass);
if($newname == $newpass)
{
$this->error("changePass failure: UserID and password cannot be the same",0);
return false;
}
// If no old Password, don't force it to match
// their existing password. NOT RECOMMENDED!
// Be SURE to always send the oldPass!
if(!(empty($oldPass)))
{
// Must validate the user now
if (!($this->verifyUser($UserID,$oldPass)))
{
$this->error("changePass failure for [$UserID] : Authentication Failed",0);
return false;
}
// OK - so the password is valid - are we planning
// on actually changing it ?
if($newPass == $oldPass)
{
// Passwords are the same, no sense wasting time here
return true;
}
}
// Valid user with new password, OK to change.
$usernum = $this->getUserNum($UserID);
if($usernum == -1) { return false; }
// No salt to cryptPass - generates a random one for us
$this->USERS[$usernum]["pass"] = $this->cryptPass($newPass);
if(!($this->htWriteFile()))
{
$this->error("FATAL could not save new password file! [$php_errormsg]",1);
exit; // just in case
}
return true;
} // end changePass
// **************************************************************
// A modified copy of changePass - changes the users name.
// If $Pass is sent, it authenticates before allowing the change.
// Returns true on success, false if;
//
// The OldID is not found
// The NewID already exists
// The Password is sent and auth fails
function renameUser ($OldID, $NewID, $Pass = "")
{
if ($this->EMPTY) { return false; }
if (empty($OldID)) { return false; }
if (empty($NewID)) { return false; }
if (!($this->isUser($OldID)))
{
// Send an auth failure - prevents people from fishing for
// valid userIDs.
// YOU will know its's because User is Unknown -
// this error is slightly different than the real
// authentication failure message. Compare the two.
// Security through obscurity sucks but oh well..
$this->error("renameUser failure for [$OldID]: Authentication Failure",0);
return false;
}
if($this->isUser($NewID))
{
$this->error("Cannot change UserID, [$NewID] already exists",0);
return false;
}
// If no Password, force a name change,
// otherwise authenticate first.
// Be SURE to always send the Pass!
if(!(empty($Pass)))
{
// Must validate the user now
if (!($this->verifyUser($OldID,$Pass)))
{
$this->error("renameUser failure for [$OldID] : Authentication Failed",0);
return false;
}
// OK - so the password is valid - are we planning
// on actually changing our name ?
if($NewID == $OldID)
{
// Nice new name ya got there Homer...
return true;
}
}
// Valid user, OK to change.
$usernum = $this->getUserNum($OldID);
if($usernum == -1) { return false; }
$this->USERS[$usernum]["user"] = $NewID;
if(!($this->htWriteFile()))
{
$this->error("FATAL could not save password file! [$php_errormsg]",1);
exit; // just in case
}
return true;
} // end renameUser
// **************************************************************
// Writes the new password file. Writes a temp file first,
// then attempts to copy the temp file over the existing file
// Original file not harmed if this fails.
// Also kinda sorta gets around the lack of file locking in PHP
// Hey, You there - PHP maintainer - FLOCK damn it! Not -everything-
// in life is inside a friggen database.
// On success, re-calls the initialize method to re-read
// the new password file and returns true. False on failure
function htWriteFile ()
{
global $php_errormsg;
$filename = $this->FILE;
// On WIN32 box this should -still- work OK,
// but it'll generate the tempfile in the system
// temporary directory (usually c:\windows\temp)
// YMMV
$tempfile = tempnam( "/tmp", "fort" );
$name = "";
$pass = "";
$count = 0;
$fd;
$myerror = "";
if($this->EMPTY)
{
$this->USERCOUNT = 0;
}
if (!copy($filename, $tempfile))
{
$this->error("FATAL cannot create backup file [$tempfile] [$php_errormsg]",1);
exit; // Just in case
}
$fd = fopen( $tempfile, "w" );
if(empty($fd))
{
$myerror = $php_errormsg; // In case the unlink generates
// a new one - we don't care if
// the unlink fails - we're
// already screwed anyway
unlink($tempfile);
$this->error("FATAL File [$tempfile] access error [$myerror]",1);
exit; // Just in case
}
for($count=0; $count <= $this->USERCOUNT; $count++ )
{
$name = $this->USERS[$count]["user"];
$pass = $this->USERS[$count]["pass"];
if ( ($name != "") && ($pass != "") )
{
fwrite($fd, "$name:$pass\n");
}
}
fclose( $fd );
if (!copy($tempfile, $filename))
{
$myerror = $php_errormsg; // Stash the error, see above
unlink($tempfile);
$this->error("FATAL cannot copy file [$filename] [$myerror]",1);
exit; // Just in case
}
// Update successful
unlink($tempfile);
if(file_exists($tempfile))
{
// Not fatal but it should be noted
$this->error("Could not unlink [$tempfile] : [$php_errormsg]",0);
}
// Update the information in memory with the
// new file contents.
$this->initialize($filename);
return true;
}
// **************************************************************
// Should be fairly obvious - adds a user to the htpasswd file
// Returns true on success, false on failure
function addUser ($UserID, $newPass)
{
// global $php_errormsg;
$count = $this->USERCOUNT;
if(empty($UserID))
{
$this->error("addUser fail. No UserID",0);
return false;
}
if(empty($newPass))
{
$this->error("addUser fail. No password",0);
return false;
}
if($this->isUser($UserID))
{
$this->error("addUser fail. UserID already exists",0);
return false;
}
if($this->EMPTY)
{
$count = 0;
}
$this->USERS[$count]["user"] = $UserID;
// No salt to cryptPass() - will generate a random one for us
$this->USERS[$count]["pass"] = $this->cryptPass($newPass);
if(!($this->htWriteFile()))
{
$this->error("FATAL could not add user due to file error! [$php_errormsg]",1);
exit; // Just in case
}
// Successfully added user
return true;
} // end addUser
// **************************************************************
// Same as addUser, but adds the user to the password file
// with a randomly generated password.
//
// Returns plain text password on success, null on failure
function assignPass ($UserID)
{
$pass = "";
$count = $this->USERCOUNT;
if(empty($UserID))
{
$this->error("assignPass fail. No UserID",0);
return "";
}
if($this->EMPTY)
{
$count = 0;
}
if($this->isUser($UserID))
{
$this->error("assignPass fail. UserID already exists. Use genPass instead",0);
return "";
}
$pass = $this->genPass();
$this->USERS[$count]["user"] = $UserID;
// No salt to cryptPass() - will generate a random one for us
$this->USERS[$count]["pass"] = $this->cryptPass($pass);
if(!($this->htWriteFile()))
{
$this->error("FATAL could not add user due to file error! [$php_errormsg]",1);
exit; // Just in case
}
// Successfully added user
return($pass);
} // end assignPass
// **************************************************************
// Again, fairly obvious - deletes a user from the htpasswd file
// Returns true on success, false on failure
function deleteUser ($UserID)
{
// global $php_errormsg;
$found = false;
// Can't delete non-existant UserIDs
if($this->EMPTY) { return false; }
if(empty($UserID))
{
// PHP should complain about this, but just in case
$this->error("deleteUser fail. No UserID to delete.",0);
return false;
}
if(!($this->isUser($UserID)))
{
$this->error("Cannot delete : [$UserID] not found.",0);
return false;
}
$usernum = $this->getUserNum($UserID);
if($usernum == -1) { return false; }
$this->USERS[$usernum]["user"] = "";
$this->USERS[$usernum]["pass"] = "";
if(!($this->htWriteFile()))
{
$this->error("FATAL could not remove user due to file error! [$php_errormsg]",1);
exit; // Just in case
}
// Successfully deleted user
return true;
} // end deleteUser
// **************************************************************
// Returns the user's UserID in the password file.
// (Glorified line number)
// Returns -1 if not found or errors
function getUserNum ($UserID)
{
$count = 0;
$usernum = -1;
$name = "";
if ($this->EMPTY) { return $usernum; }
if (empty($UserID)) { return $usernum; }
if (!($this->isUser($UserID))) { return $usernum; }
for($count=0; $count <= $this->USERCOUNT; $count++ )
{
$name = $this->USERS[$count]["user"];
if ($name != "")
{
if ($name == $UserID)
{
$usernum = $count;
break;
}
}
}
return $usernum;
}
// **************************************************************
// Calculates current microtime
function utime()
{
$time = explode( " ", microtime());
$usec = (double)$time[0];
$sec = (double)$time[1];
return $sec + $usec;
}
// **************************************************************
// Generates a pseudo random 2 digit salt. Method will
// generate different salts when called multiple times by
// the same process.
function genSalt ()
{
$random = 0;
$rand64 = "";
$salt = "";
$random=rand(); // Seeded via initialize()
// Crypt(3) can only handle A-Z a-z ./
$rand64= "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
$salt=substr($rand64,$random % 64,1).substr($rand64,($random/64)% 64,1);
$salt=substr($salt,0,2); // Just in case
return($salt);
}
// **************************************************************
// Generates a pseudo random 5 to 8 digit password. Method will even
// generate different passwords when called multiple times by
// the same process.
function genPass ()
{
$random = 0;
$rand78 = "";
$randpass = "";
$pass = "";
$maxcount = rand(4,9);
// The rand() limits (min 4, max 9) don't actually limit the number
// returned by rand, so keep looping until we have a password that's
// more than 4 characters and less than 9.
if ( ($maxcount > 8) or ($maxcount < 5) )
{
do
{
$maxcount = rand(4,9);
} while ( ($maxcount > 8) or ($maxcount < 5) );
}
$rand78= "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()-=_+abcdefghijklmnopqrstuvwxyz";
for($count=0; $count <= $maxcount; $count++)
{
$random=rand(0,77);
$randpass=substr($rand78,$random,1);
$pass = $pass.$randpass;
}
$pass = substr($pass,0,8); // Just in case
return($pass);
} // end genPass
// **************************************************************
// Generates a pseudo random 5 to 8 digit User ID. Method will
// generate different User IDs when called multiple times by
// the same process.
function genUser ()
{
$random = 0;
$rand78 = "";
$randuser = "";
$userid = "";
$maxcount = rand(4,9);
if ( ($maxcount > 8) or ($maxcount < 5) )
{
do
{
$maxcount = rand(4,9);
} while ( ($maxcount > 8) or ($maxcount < 5) );
}
$rand62= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for($count=0; $count <= $maxcount; $count++)
{
$random=rand(0,61);
$randuser=substr($rand62,$random,1);
$userid = $userid.$randuser;
}
$userid = substr($userid,0,8); // Just in case
return($userid);
} // end genUser
// **************************************************************
// **************************************************************
} // END CLASS.HTPASSWD
?>