.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 (! $_POSTexit;
     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 
[email protected]
 
    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 <
[email protected] >
                    (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 
[email protected]
 
    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 
[email protected]
 
 
    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 
[email protected]
 
    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 
[email protected]
 
    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 
[email protected]
 
    Rev 0.4            Hey neat - it works.
 
 
    **************************************************************
    Revision 0.3 1999/01/08 13:10:00 
[email protected]
 
    Rev 0.3            +addUser(), +genSalt(), +deleteUser(), +utime(),
                    +getUserNum()
 
    **************************************************************
    Revision 0.2 1999/01/07 09:55:00 
[email protected]
 
    Rev 0.2            +isUser(), +getPass(), +checkPass(), +htWriteFile(),
                    +changePass()
 
 
    **************************************************************
    Revision 0.1 1999/01/05 12:34:00 
[email protected]
 
    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 [email protected] ' ;
 
    
//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
 
 
 
?> 

 

 

 

 

你可能感兴趣的:(passwd)