Here is some code I wrote to add, remove, and change user names and passwords in .htpasswd with PHP: function adduser($user, $pass) { try { $htpasswd = '.htpasswd'; //$hash = '{SHA}'.crypt($pass, base64_encode($pass)); $hash = crypt_apr1_md5($pass); //APR1-MD5 $contents = $user . ':' . $hash; $lines = explode(PHP_EOL, file_get_contents($htpasswd)); // get .htpasswd print('<h4>input:</h4><pre>'.print_r(implode(PHP_EOL, $lines),true).'</pre>'); $exists = false; foreach($lines as $line){ $existing_user = explode( ':', $line ); if ($existing_user[0] == $user) { //checks if user exists $contents = str_replace($line, $contents, $lines); //changes password for user $contents = implode(PHP_EOL, $contents); $exists = true; if ($pass == '') { // removes user if password is empty $contents = str_replace($line, '', $lines); //removes user $contents = array_filter($contents); // cleans empty space in array $contents = implode(PHP_EOL, $contents); $exists = true; } } } if ($exists == false) { $contents = implode(PHP_EOL, $lines) . PHP_EOL . $contents; } file_put_contents($htpasswd, $contents); print('<h4>output:</h4><pre>'.print_r($contents,true).'</pre>'); }catch(Exception $e) { echo '<h3>fail: </h3>' . $e->getMessage(); } } if(isset($_GET['user'])){ adduser($_GET['user'], $_GET['pass']); echo '<h3>success</h3>'; }else{ $htpasswd = '.htpasswd'; $lines = explode(PHP_EOL, file_get_contents($htpasswd)); // get .htpasswd print('<h4>.htpasswd:</h4><pre>'.print_r(implode(PHP_EOL, $lines),true).'</pre>'); echo '<h3>no user set</h3>'; } I would love to streamline it and clean it up.