In my earlier post about .htaccess I had described about authentication using .htaccess and command to generate .htpasswd file. However, when we want to add passwords for many users that method will take too long, since we will have to add passwords for each user one at a time. However, there is an easier way to generate the .htpasswd file using PHP. In this post I will show the different algorithms which can be used to generate the .htpasswd file.
Method 1: Using crypt() function.
This uses method uses crypt() encryption for passwords. This used to be the default algorithm used by Apache (2.2.17 and older). The password generated by this method will not work on Windows systems as they use MD5 based passwords. This method is same as using the command :
htpasswd -d /usr/local/etc/apache/.htpasswd user1
The output of the code below can be directly added to the .htpasswd file.
<?php // Password to be used for the user $username = 'user1'; $password = 'password1'; // Encrypt password $encrypted_password = crypt($password, base64_encode($password)); // Print line to be added to .htpasswd file echo $username . ':' . $encrypted_password;
user1:MzKS62M/K9HSs
Method 2: Using APR1-MD5 algorithm
MD5 encryption method is more secure than the crypt method. This is the default method since Apache 2.2.18. The password generated by using this method can be used on both Windows and Linux based systems. This method is same as using the command :
htpasswd -m /usr/local/etc/apache/.htpasswd user1
Here is a script which I created based on the function I found on Stack Overflow.
<?php // APR1-MD5 encryption method (windows compatible) function crypt_apr1_md5($plainpasswd) { $salt = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz0123456789"), 0, 8); $len = strlen($plainpasswd); $text = $plainpasswd.'$apr1$'.$salt; $bin = pack("H32", md5($plainpasswd.$salt.$plainpasswd)); 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) : $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; } // Password to be used for the user $username = 'user1'; $password = 'password1'; // Encrypt password $encrypted_password = crypt_apr1_md5($password); // Print line to be added to .htpasswd file echo $username . ':' . $encrypted_password;
user1:$apr1$e5cytbnu$ps.bh8zF0tkJpEgkGtYcf0
// Array for usernames and password. $users = array(); // User 1 $users[0]['username'] = 'user1'; $users[0]['password'] = 'password1'; // User 2 $users[1]['username'] = 'user2'; $users[1]['password'] = 'password2'; // User 3 $users[2]['username'] = 'user3'; $users[2]['password'] = 'password3'; foreach($users as $user => $data) { $username = $data['username']; $password = $data['password']; // Encrypt password $encryptedpwd = crypt_apr1_md5($password); // Print line to be added to .htpasswd file $content = $username . ':' . $encryptedpwd; echo $content . '<br />'; }
user1:$apr1$9qrj2x80$p2L32fS0tO7JgwzUISW8b. user2:$apr1$hmay01vn$uIHCNVBgF5qH5jmNBIzw4/ user3:$apr1$v2tohm9c$3TtZAPuaD4dhPF62kPOwO/
By using PHP we can easily generate the code to be added to .htpasswd file for many users very easily. All the usernames and passwords in my examples are just sample users. Make use the username that you want and a different, more secure, password.
Update: Newer versions of Apache can use BCRPYT for password hash so here is another posts about Generating bcrypt .htpasswd passwords using PHP.
Thanks for your work, in method 1 there a 2 different $var for the username, in line 3 you use “$username”, but in line 10 you use just “$user”, perhaps you want to edit this ? greetings !
Thanks for finding it. I have updated the post.
is your algorithm match what apache internally do?
Yes it does. However, this is the older hash that Apache used. Now they can use bcrypt. Here is an updated post about generating the passwords with the bcrypt logic. https://www.virendrachandak.com/techtalk/using-php-bcrypt-algorithm-for-htpasswd-generation/
the APR1-MD5 method worked on my servers, unfortunately the new modern and more concise way with bcrypt don’t
I am not very sure why it is. It working. I have used it on Apache 2.4 on Centos as well as fedora machines and it works. May be for some reason your system doesn’t support bcrypt. Can you try to use the command line command and see if it works.
E.g. htpasswd -nbB myName myPassword
Thank you for this post, this is exactly what I was looking for !