PHP Command-Line PHP Reading Passwords - Supercoders | Web Development and Design | Tutorial for Java, PHP, HTML, Javascript PHP Command-Line PHP Reading Passwords - Supercoders | Web Development and Design | Tutorial for Java, PHP, HTML, Javascript

Breaking

Post Top Ad

Post Top Ad

Wednesday, July 17, 2019

PHP Command-Line PHP Reading Passwords

PHP Command-Line PHP


Reading Passwords

Problem

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

Solution

If the ncurses extension is available, use ncurses_getch() to read each character, making sure “noecho” mode is turned on:

       $password = '';
       ncurses_init();
       ncurses_addstr("Enter your password:\n");
       /* Do not display the keystrokes as they are typed */
       ncurses_noecho();
       while (true) {
              // get a character from the keyboard
              $c = chr(ncurses_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;
              }
       }
       ncurses_end();

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

       // turn off echo
       `/bin/stty -echo`;

       // read password
       $password = trim(fgets(STDIN));

       // turn echo back on
       `/bin/stty echo`;

Neither ncurses nor stty is available on Windows platforms.

Discussion

Because ncurses gives character-by-character control over input (and because it’s easy to toggle whether input is echoed to the screen), it makes it a great solution for reading passwords. The ncurses_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.

If you’re using a Unix system but don’t have the ncurses extension available, use /bin/stty to control the terminal characteristics so that typed characters aren’t echoed to the screen while you read a password.

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: ";
       $username = rtrim(fgets(STDIN)) 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(STDIN)) or die($php_errormsg);
       `/bin/stty echo`;
       print "\n";

       // find corresponding line in /etc/passwd
       $fh = fopen('/etc/passwd','r') or die($php_errormsg);
       $found_user = 0;
       $pattern = '/^' . preg_quote($username) . ':/';
       while (! ($found_user || feof($fh))) {
              $passwd_line = fgets($fh,256);
              if (preg_match($pattern,$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, $password_parts[1]);
       if ($encrypted_password == $passwd_parts[1]) {
              print "login successful";
       } else {
              print "login unsuccessful";
       }

No comments:

Post a Comment

Post Top Ad