开发者

how to edit .htpasswd using php?

i have a protected directory where only user on .htpasswd can access, but sometimes it requires the user to change password or username, edit a specific username password to his username him self

sample users
kevien : kka
mike : mike

And let say i want to change kevien to XYZ

And 开发者_运维知识库same thing goes to password


I have modified function to use all types of crypt alghoritms. Someone may find it useful:

/*
Function change password in htpasswd.
Arguments:
$user    > User name we want to change password to.
$newpass > New password
$type    > Type of cryptogrphy: DES, SHA, MD5. 
$salt    > Option: Add your custom salt (hashing string). 
           Salt is applied to DES and MD5 and must be in range 0-9A-Za-z
$oldpass > Option: Add more security, user must known old password to change it. 
           This option is not supported for DES and MD5 without salt!!!
$path    > Path to .htaccess file which contain the password protection. 
           Path to password file is obtained from this .htaccess file. 
*/  

function changePass($user, $newpass, $type="SHA", $salt="", $oldpass="", $path=".htaccess")
{
    switch ($type) {
        case "DES" :
            $salt = substr($salt,0,2);  // Salt must be 2 char range 0-9A-Za-z
            $newpass = crypt($newpass,$salt);
            if ($oldpass != null) {
                $oldpass = crypt($oldpass,$salt);
            }
            break;

        case "SHA" :
            $newpass = '{SHA}'.base64_encode(sha1($newpass, TRUE));
            if ($oldpass != null) {
                $oldpass = '{SHA}'.base64_encode(sha1($oldpass, TRUE));
            }
            break;

        case "MD5" :
            $salt = substr($salt,0,8);  //Salt must be max 8 char range 0-9A-Za-z
            $newpass = crypt_apr1_md5($newpass, $salt);
            if ($oldpass != null) {
                $oldpass = crypt_apr1_md5($oldpass, $salt);
            }
            break;

        default:
            return false;
            break;
    }

    $hta_arr = explode("\n", file_get_contents($path));

    foreach ($hta_arr as $line) {
        $line = preg_replace('/\s+/','',$line); // remove spaces
        if ($line) {
            $line_arr = explode('"', $line);
            if (strcmp($line_arr[0],"AuthUserFile") == 0) {
                $path_htaccess = $line_arr[1];
            }   
        }
    }  
    $htp_arr = explode("\n", file_get_contents($path_htaccess));

    $new_file = "";
    foreach ($htp_arr as $line) {
        $line = preg_replace('/\s+/', '', $line); // remove spaces
        if ($line) {
            list($usr, $pass) = explode(":", $line, 2);
            if (strcmp($user, $usr) == 0) {
                if ($oldpass != null) {
                    if ($oldpass == $pass) {
                        $new_file .= $user.':'.$newpass."\n";
                    } else {
                        return false;
                    }
                } else {
                    $new_file .= $user.':'.$newpass."\n";
                }
            } else {
                $new_file .= $user.':'.$pass."\n";
            }
        }
    }
    $f = fopen($path_htaccess,"w") or die("couldn't open the file");
    fwrite($f, $new_file);
    fclose($f);
    return true;
}

Function for generating Apache like MD5:

/**
 * @param string $password
 * @param string|null $salt
 * @ref https://stackoverflow.com/a/8786956
 */
function crypt_apr1_md5($password, $salt = null)
{
    if (!$salt) {
        $salt = substr(base_convert(bin2hex(random_bytes(6)), 16, 36), 1, 8);
    }
    $len = strlen($password);

    $text = $password . '$apr1$' . $salt;

    $bin = pack("H32", md5($password . $salt . $password));

    for ($i = $len; $i > 0; $i -= 16) {
        $text .= substr($bin, 0, min(16, $i));
    }

    for ($i = $len; $i > 0; $i >>= 1) {
        $text .= ($i & 1) ? chr(0) : $password[0];
    }

    $bin = pack("H32", md5($text));

    for ($i = 0; $i < 1000; $i++) {
        $new = ($i & 1) ? $password : $bin;

        if ($i % 3) {
            $new .= $salt;
        }

        if ($i % 7) {
            $new .= $password;
        }

        $new .= ($i & 1) ? $bin : $password;
        $bin = pack("H32", md5($new));
    }

    $tmp = '';

    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;
}

Demo of crypt_apr1_md5() is available here.

Note that as of Apache 2.4, bcrypt is supported, so you can (and SHOULD) just use password_hash() on newer versions of Apache for this purpose.


Ofc this is just a sample, that will read your current file, find the given username and change either it is password of username.

Please keep in mind that this code is not safe and you would still need to parse the username and password so it does not break your file.

    $username = $_POST['user'];
    $password = $_POST['pass'];
    $new_username = $_POST['newuser'];
    $new_password = $_POST['newpass'];
    $action = $_POST['action'];
    //read the file into an array
    $lines = explode("\n", file_get_contents('.htpasswd'));

    //read the array and change the data if found
    $new_file = "";
    foreach($lines as $line)
    {
        $line = preg_replace('/\s+/','',$line); // remove spaces
        if ($line) {
            list($user, $pass) = split(":", $line, 2);
            if ($user == $username) {
                if ($action == "password") {
                    $new_file .= $user.':'.$new_password."\n";
                } else {
                    $new_file .= $new_username.':'.$pass."\n";
                }
            } else {
                $new_file .= $user.':'.$pass."\n";
            }
        }
    }

    //save the information
    $f=fopen(".htpasswd","w") or die("couldn't open the file");
    fwrite($f,$new_file);
    fclose($f);


Don't. Store your authdb in a database instead, via e.g. mod_auth_mysql.


Googled "php generate htpasswd", got this article: How to create a password for a .htpasswd file using PHP.

The key line seems to be:

$password = crypt($clearTextPassword, base64_encode($clearTextPassword));

So I imagine you'd read in the file contents with file_get_contents, parse it into an associative array, modify the relevant entries (encrypting the password as shown above), write the array back into a string, and use file_put_contents to write the file back out.

This is most definitely not standard practice, however. Sounds like the job for a database. If you feel weird about setting up a whole database server, and your host supports it, SQLite might be a good choice.


Just in case someone is just looking for a working script, here is a solution.

It is the script published here by Kavoir with a minor change: http://www.kavoir.com/backyard/showthread.php?28-Use-PHP-to-generate-edit-and-update-htpasswd-and-htgroup-authentication-files

<?php
/*
 $pairs = array(
  'username' = 'password',
 );
*/

// Algorithm: SHA1

class Htpasswd {

private $file = '';

public function __construct($file) {
    if (file_exists($file)) {
        $this -> file = $file;
    } else {
        return false;
    }
}

private function write($pairs = array()) {
    $str = '';
    foreach ($pairs as $username => $password) {
        $str .= "$username:{SHA}$password\n";
    }
    file_put_contents($this -> file, $str);
}

private function read() {
    $pairs = array();
    $fh = fopen($this -> file, 'r');
    while (!feof($fh)) {
        $pair_str = str_replace("\n", '', fgets($fh));
        $pair_array = explode(':{SHA}', $pair_str);
        if (count($pair_array) == 2) {
            $pairs[$pair_array[0]] = $pair_array[1];
        }
    }
    return $pairs;
}

public function addUser($username = '', $clear_password = '') {
    if (!empty($username) && !empty($clear_password)) {
        $all = $this -> read();
      //  if (!array_key_exists($username, $all)) {
            $all[$username] = $this -> getHash($clear_password);
            $this -> write($all);
     //   }
    } else {
        return false;
    }
}

public function deleteUser($username = '') {
    $all = $this -> read();
    if (array_key_exists($username, $all)) {
        unset($all[$username]);
        $this -> write($all);
    } else {
        return false;
    }
}

public function doesUserExist($username = '') {
    $all = $this -> read();
    if (array_key_exists($username, $all)) {
        return true;
    } else {
        return false;
    }
}

private function getHash($clear_password = '') {
    if (!empty($clear_password)) {
        return base64_encode(sha1($clear_password, true));
    } else {
        return false;
    }
}

}  

You can use this script like:

$htp = new Htpasswd('.htpasswd');
$htp -> addUser('username1', 'clearpassword1');  // this will add or edit the user
$htp -> deleteUser('username1');  
// check if a certain username exists
if ($htp -> doesUserExist('username1')) {
 // user exists
}  
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜