<?php
/**
 * .htpasswd update tool
 *
 * @author        HSDN Team
 * @copyright    Copyright (c) 2011-2018 Information Networks Ltd.
 * @link        http://www.hsdn.org
 * @version        1.1
 */

/*
Use next contents for .htacces file for secure this tool:

<Files "update.php">
   AuthType Basic
   AuthName "Account management interface"
  AuthUserFile .htpasswd
  Require valid-user
</Files>
*/

// ------------------------------------------------------------------------

// Real path to .htacces file
$htpasswd './.htpasswd';

// ------------------------------------------------------------------------

$login = isset($_POST['login']) ? trim($_POST['login']) : '';
$password = isset($_POST['password']) ? trim($_POST['password']) : '';

if (!
file_exists($htpasswd) OR !is_writable($htpasswd))
{
    die(
"<p style=\"color:red\">.htpasswd file is not found or not writable!</p>\n");
}

if (!
preg_match('/^[^\s]{1,1024}$/is'$password) AND isset($_POST['add']))
{
    
$error 'Incorrect password!';
}

if (!
preg_match('/^[-0-9a-z]{3,32}/is'$login))
{
    
$error 'Incorrect user name!';
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>.htpasswd update tool</title>
</head>
<body>
<h1>.htpasswd update tool</h1>
<p>Opened .htpasswd file: <b><?php echo realpath($htpasswd?></b></p>
<br />
<h2>Add or modify user</h2>
<form action="" method="post">
User:<br />
<input type="text" name="login" /><br />
Password:<br />
<input type="text" name="password" /><br />
<br />
<input type="submit" name="add" value="Add/Update" />
</form>
<?php
if (isset($_POST['add']))
{
    if (!isset(
$error))
    {
        if (
user_modify($htpasswd$login$password))
        {
            echo 
"<p style=\"color:green\">Modify success!</p>\n";
        }
        else
        {
            echo 
"<p style=\"color:red\">Modify error!</p>\n";
        }
    }
    else
    {
        echo 
'<p style="color:red">'.$error."</p>\n";
    }
}
?>
<br />
<h2>Delete user</h2>
<form action="" method="post">
User:<br />
<input type="text" name="login" /><br />
<br />
<input type="submit" name="delete" value="Delete" />
</form>
<?php
if (isset($_POST['delete']))
{
    if (!isset(
$error))
    {
        if (
user_delete($htpasswd$login))
        {
            echo 
"<p style=\"color:green\">Delete success!</p>\n";
        }
        else
        {
            echo 
"<p style=\"color:red\">Delete error!</p>\n";
        }
    }
    else
    {
        echo 
'<p style="color:red">'.$error."</p>\n";
    }
}
?>
<br />
<h2>Current .htpasswd file contents</h2>
<p><pre>
<?php
foreach (open_file($htpasswd) as $user => $password)
{
    echo 
'<b>'.$user.'</b>:'.$password."\n";
}
?>
</pre></p>
<hr />
<i>Copyright &copy; 2011 Information Networks Ltd.</i>
</html>
<?php

/**
 * Modify or add user
 *
 * @param    string
 * @param    string
 * @param    string
 * @return    bool
 */
function user_modify($htpasswd$user$password
{
    if (!
$array open_file($htpasswd))
    {
        return 
FALSE;
    }

    
$array[$user] = crypt_apr1_md5($password);

    if (!
write_file($htpasswd$array))
    {
        return 
FALSE;
    }

    return 
TRUE;
}

/**
 * Delete user
 *
 * @param    string
 * @param    string
 * @return    bool
 */
function user_delete($htpasswd$user
{
    if (!
$array open_file($htpasswd))
    {
        return 
FALSE;
    }
    
    if (!isset(
$array[$user]))
    {
        return 
FALSE;
    }

    unset(
$array[$user]);

    if (!
write_file($htpasswd$array))
    {
        return 
FALSE;
    }

    return 
TRUE;
}

/**
 * Open and parse .htpasswd file
 *
 * @param    string
 * @return    array|bool
 */
function open_file($htpasswd
{
    if ((
$contents = @file_get_contents($htpasswd)) === FALSE)
    {
        return 
FALSE;
    }

    
$lines explode("\n"$contents);
    
$return = array();

    foreach (
$lines as $line)
    {
        if (
$line != '')
        {
            list(
$user$password) = explode(':'$line2);
        
            
$return[$user] = $password;
        }
    }

    return 
$return;
}

/**
 * Build and write .htpasswd file
 *
 * @param    string
 * @param    array
 * @return    bool
 */
function write_file($htpasswd$array
{
    
$string '';

    foreach (
$array as $user => $password)
    {
        
$string .= $user.':'.$password."\n";
    }

    return (@
file_put_contents($htpasswd$string) !== FALSE) ? TRUE FALSE;
}

/**
 * Crypt plain password
 *
 * @author    mikey_nich@hotmail.com
 * @url        http://php.net/manual/en/function.crypt.php
 *
 * @param    string
 * @param    array
 * @return    bool
 */
function crypt_apr1_md5($plainpasswd
{
    
$tmp '';
    
$salt substr(str_shuffle('abcdefghijklmnopqrstuvwxyz0123456789'), 08);
    
$len strlen($plainpasswd);
    
$text $plainpasswd.'$apr1$'.$salt;
    
$bin pack('H32'md5($plainpasswd.$salt.$plainpasswd));

    for(
$i $len$i 0$i -= 16) { $text .= substr($bin0min(16$i)); }
    for(
$i $len$i 0$i >>= 1) { $text .= ($i 1) ? chr(0) : $plainpasswd{0}; }

    
$bin pack('H32'md5($text));

    for(
$i 0$i 1000$i++) 
    {
        
$new = ($i 1) ? $plainpasswd $bin;

        if (
$i 3$new .= $salt;
        if (
$i 7$new .= $plainpasswd;

        
$new .= ($i 1) ? $bin $plainpasswd;
        
$bin pack('H32'md5($new));
    }

    for (
$i 0$i 5$i++) 
    {
        
$k $i 6;
        
$j $i 12;

        if (
$j == 16$j 5;

        
$tmp $bin[$i].$bin[$k].$bin[$j].$tmp;
    }

    
$tmp chr(0).chr(0).$bin[11].$tmp;
    
$tmp strtr(strrev(substr(base64_encode($tmp), 2)),
    
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
    
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");

    return 
'$apr1$'.$salt.'$'.$tmp;
}

/* End of file */