Recipe 25.5. Reading Passwords

25.5.1. Problem

You need to read a string from the command line without it being echoed as it's typed'for example, when entering passwords.

25.5.2. Solution

On Unix systems, use /bin/stty to toggle echoing of typed characters:

// turn off echo `/bin/stty -echo`; // read password $password = readline(); // turn echo back on `/bin/stty echo`;

On Windows, use the FFI extension to access _getch( ) from msvcrt.dll:

$ffi = new FFI("[lib='msvcrt.dll'] int _getch();"); while(true) {     // get a character from the keyboard     $c = chr($ffi->_getch());     if ( "\r" == $c ||  "\n" == $c ) {         // if it's a newline, break out of the loop, we've got our password         break;     } elseif ("\x08" == $c) {         /* if it's a backspace, delete the previous char from $password */         $password = substr_replace($password,'',-1,1);     } elseif ("\x03" == $c) {         // if it's Control-C, clear $password and break out of the loop         $password = NULL;         break;     } else {         // otherwise, add the character to the password         $password .= $c;     } }

25.5.3. Discussion

On Unix, you use /bin/stty to control the terminal characteristics so that typed characters aren't echoed to the screen while you read a password. Windows doesn't have /bin/stty, so you use the Foreign Function Interface (FFI) extension to get access _getch( ) in the Microsoft C runtime library, msvcrt.dll. The _getch( ) function reads a character without echoing it to the screen. It returns the ASCII code of the character read, so you convert it to a character using chr( ) . You then take action based on the character typed. If it's a newline or carriage return, you break out of the loop because the password has been entered. If it's a backspace, you delete a character from the end of the password. If it's a Ctrl-C interrupt, you set the password to NULL and break out of the loop. If none of these things are true, the character is concatenated to $password. When you exit the loop, $password holds the entered password.

The FFI extension is available as part of PECL. Windows users can download a pre-built DLL at Make sure you're using a version of FFI greater than 0.3, or this code won't work correctly.

The following code displays Login: and Password: prompts, and compares the entered password to the corresponding encrypted password stored in /etc/passwd. This requires that the system not use shadow passwords:

print "Login: "; $fh = fopen('php://stdin','r')   or die($php_errormsg); $username = rtrim(fgets($fh,64)) or die($php_errormsg); preg_match('/^[a-zA-Z0-9]+$/',$username)     or die("Invalid username: only letters and numbers allowed"); print 'Password: '; `/bin/stty -echo`; $password = rtrim(fgets($fh,64)) or die($php_errormsg); `/bin/stty echo`; print "\n"; // nothing more to read from the keyboard fclose($fh); // find corresponding line in /etc/passwd $fh = fopen('/etc/passwd','r')   or die($php_errormsg); $found_user = 0; while (! ($found_user || feof($fh))) {     $passwd_line = fgets($fh,256);     if (preg_match("/^$username:/",$passwd_line)) {         $found_user = 1;     } } fclose($fh); $found_user or die ("Can't find user \"$username\""); // parse the correct line from /etc/passwd $passwd_parts = split(':',$passwd_line); /* encrypt the entered password and compare it to the password in    /etc/passwd */ $encrypted_password = crypt($password,                             substr($passwd_parts[1],0,CRYPT_SALT_LENGTH)); if ($encrypted_password == $passwd_parts[1]) {     print "login successful"; } else {     print "login unsuccessful"; }

25.5.4. See Also

Documentation on readline( ) at, chr( ) at, on the FFI at, and on _getch( ) at; on Unix, see your system's stty(1) manpage.

PHP Cookbook, 2nd Edition
PHP Cookbook: Solutions and Examples for PHP Programmers
ISBN: 0596101015
EAN: 2147483647
Year: 2006
Pages: 445

Similar book on Amazon © 2008-2017.
If you may any questions please contact us: