Ich schreibe ein Befehlszeilentool, um meiner Web-App zu helfen. Es benötigt ein Passwort, um eine Verbindung zum Dienst herzustellen. Ich möchte, dass das Skript eine Kennwortabfrage anzeigt, damit ich sie nicht als Befehlszeilenargument übergeben muss.
Das ist einfach genug, aber ich möchte, dass das Passwort nicht während der Eingabe auf dem Bildschirm angezeigt wird. Wie kann ich das mit PHP machen?
Bonuspunkte für reines PHP (nein system('stty')
) und Ersetzen der Charaktere durch *
.
BEARBEITEN:
Das Skript wird unter einem Unix-ähnlichen System (Linux oder Mac) ausgeführt. Das Skript ist in PHP geschrieben und wird höchstwahrscheinlich so bleiben.
Für die Aufzeichnung ist die stty
Art und Weise, wie es gemacht wird:
echo "Password: ";
system('stty -echo');
$password = trim(fgets(STDIN));
system('stty echo');
// add a new line since the users CR didn't echo
echo "\n";
Ich würde es vorziehen, die system()
Anrufe dort nicht zu haben .
Antworten:
Auf Sitepoint gefunden .
function prompt_silent($prompt = "Enter Password:") { if (preg_match('/^win/i', PHP_OS)) { $vbscript = sys_get_temp_dir() . 'prompt_password.vbs'; file_put_contents( $vbscript, 'wscript.echo(InputBox("' . addslashes($prompt) . '", "", "password here"))'); $command = "cscript //nologo " . escapeshellarg($vbscript); $password = rtrim(shell_exec($command)); unlink($vbscript); return $password; } else { $command = "/usr/bin/env bash -c 'echo OK'"; if (rtrim(shell_exec($command)) !== 'OK') { trigger_error("Can't invoke bash"); return; } $command = "/usr/bin/env bash -c 'read -s -p \"" . addslashes($prompt) . "\" mypassword && echo \$mypassword'"; $password = rtrim(shell_exec($command)); echo "\n"; return $password; } }
quelle
rtrim
Sie können gültige Zeichen entfernen (dh alle Leerzeichen, die die Zeichenfolge beenden), aber Sie können sie weglassen undecho -n
stattdessen verwenden.Abhängig von Ihrer Umgebung (dh nicht unter Windows) können Sie die Bibliothek ncurses (insbesondere die Funktion ncurses_noecho () zum Stoppen des Tastaturechos und ncurses_getch () zum Lesen der Eingabe) verwenden, um das Kennwort abzurufen, ohne es auf dem Bildschirm anzuzeigen.
quelle
Sie können meine Datei hiddeninput.exe verwenden, um echte versteckte Eingaben zu erhalten, ohne die Informationen irgendwo auf dem Bildschirm zu verlieren .
<?php echo 'Enter password: '; $password = exec('hiddeninput.exe'); echo PHP_EOL; echo 'Password was: ' . $password . PHP_EOL;
Wenn Sie das letzte Echo entfernen, sollte das Passwort niemals angezeigt werden, aber Sie können es offensichtlich zur Validierung verwenden.
quelle
Die folgende Methode funktioniert unter Linux CLI, jedoch nicht unter Windows CLI oder Apache. Es funktioniert auch nur mit Zeichen in der Standard-Ascii-Tabelle (es würde jedoch nicht viel kosten, um es mit erweiterten Zeichensätzen kompatibel zu machen).
Ich habe ein bisschen Code eingegeben, um mich vor dem Kopieren und Einfügen von Passwörtern zu schützen. Wenn das Bit zwischen den beiden Kommentaren entfernt wird, kann ein Passwort eingefügt / eingefügt werden.
Ich hoffe das hilft jemandem.
<?php echo("Password: "); $strPassword=getObscuredText(); echo("\n"); echo("You entered: ".$strPassword."\n"); function getObscuredText($strMaskChar='*') { if(!is_string($strMaskChar) || $strMaskChar=='') { $strMaskChar='*'; } $strMaskChar=substr($strMaskChar,0,1); readline_callback_handler_install('', function(){}); $strObscured=''; while(true) { $strChar = stream_get_contents(STDIN, 1); $intCount=0; // Protect against copy and paste passwords // Comment \/\/\/ to remove password injection protection $arrRead = array(STDIN); $arrWrite = NULL; $arrExcept = NULL; while (stream_select($arrRead, $arrWrite, $arrExcept, 0,0) && in_array(STDIN, $arrRead)) { stream_get_contents(STDIN, 1); $intCount++; } // /\/\/\ // End of protection against copy and paste passwords if($strChar===chr(10)) { break; } if ($intCount===0) { if(ord($strChar)===127) { if(strlen($strObscured)>0) { $strObscured=substr($strObscured,0,strlen($strObscured)-1); echo(chr(27).chr(91)."D"." ".chr(27).chr(91)."D"); } } elseif ($strChar>=' ') { $strObscured.=$strChar; echo($strMaskChar); //echo(ord($strChar)); } } } readline_callback_handler_remove(); return($strObscured); } ?>
quelle
Dies ist die einfachste Lösung für alle Plattformen:
function prompt($message = 'prompt: ', $hidden = false) { if (PHP_SAPI !== 'cli') { return false; } echo $message; $ret = $hidden ? exec( PHP_OS === 'WINNT' || PHP_OS === 'WIN32' ? __DIR__ . '\prompt_win.bat' : 'read -s PW; echo $PW' ) : rtrim(fgets(STDIN), PHP_EOL) ; if ($hidden) { echo PHP_EOL; } return $ret; }
Dann erstellen Sie
prompt_win.bat
im selben Verzeichnis:SetLocal DisableDelayedExpansion Set "Line=" For /F %%# In ('"Prompt;$H & For %%# in (1) Do Rem"') Do ( Set "BS=%%#" ) :loop_start Set "Key=" For /F "delims=" %%# In ('Xcopy /L /W "%~f0" "%~f0" 2^>Nul') Do ( If Not Defined Key ( Set "Key=%%#" ) ) Set "Key=%Key:~-1%" SetLocal EnableDelayedExpansion If Not Defined Key ( Goto :loop_end ) If %BS%==^%Key% ( Set "Key=" If Defined Line ( Set "Line=!Line:~0,-1!" ) ) If Not Defined Line ( EndLocal Set "Line=%Key%" ) Else ( For /F "delims=" %%# In ("!Line!") Do ( EndLocal Set "Line=%%#%Key%" ) ) Goto :loop_start :loop_end Echo;!Line!
quelle
rtrim
Sie können gültige Zeichen entfernen (dh alle Leerzeichen, die die Zeichenfolge beenden), aber Sie können sie weglassen undecho -n
stattdessen verwenden.Ich denke, dass es keinen einfachen Weg gibt, dies zu tun (eigentlich kann ich mir keinen Weg vorstellen), ohne stty -echo zu verwenden. Wenn Sie beabsichtigen, es unter Windows auszuführen, können Sie ein Batch-Skript erstellen, das die nicht verschlüsselten eingegebenen Informationen für Ihr PHP-Skript bereitstellt.
@echo off cls SET /P uname=Enter Username: echo hP1X500P[PZBBBfh#b##fXf-V@`$fPf]f3/f1/5++u5>in.com set /p password=Enter password :<nul for /f “tokens=*” %%i in (’in.com’) do set password=%%i del in.com echo. c:\php\php.exe d:\php\test.php %uname% “%password%” Pause
Beispiel aus http://www.indiangnu.org/2008/php-hide-user-input-using-batch-script-windows/
quelle
Funktioniert auf jedem Windows-System, das Powershell-Unterstützung bietet. (Quelle: http://www.qxs.ch/2013/02/08/php-cli-password-prompts-on-windows-7/ )
<?php // please set the path to your powershell, here it is: C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe $pwd=shell_exec('C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe -Command "$Password=Read-Host -assecurestring \"Please enter your password\" ; $PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)) ; echo $PlainPassword;"'); $pwd=explode("\n", $pwd); $pwd=$pwd[0]; echo "You have entered the following password: $pwd\n";
quelle
Warum nicht eine SSH-Verbindung verwenden? Sie können die Befehle weg abstrahieren, Eingabe / Ausgabe umleiten und die volle Kontrolle haben.
Sie können jemandem eine reine, saubere Shell mit so wenig Rechten wie nötig zur Verfügung stellen und das Passwort einfach zusammen mit SSH2 :: Connect () POSTEN lassen, um die Shell zu öffnen.
Ich habe eine nette Klasse erstellt, um mit der PHP-SSH2-Erweiterung zu arbeiten. Vielleicht hilft sie Ihnen. (und es macht auch sichere Dateiübertragungen)
<?php /** * SSH2 * * @package Pork * @author SchizoDuckie * @version 1.0 * @access public */ class SSH2 { private $host; private $port; private $connection; private $timeout; private $debugMode; private $debugPointer; public $connected; public $error; /** * SSH2::__construct() * * @param mixed $host * @param integer $port * @param integer $timeout * @return */ function __construct($host, $port=22, $timeout=10) { $this->host = $host; $this->port = $port; $this->timeout = 10; $this->error = 'not connected'; $this->connection = false; $this->debugMode = Settings::Load()->->get('Debug', 'Debugmode'); $this->debugPointer = ($this->debugMode) ? fopen('./logs/'.date('Y-m-d--H-i-s').'.log', 'w+') : false; $this->connected = false; } /** * SSH2::connect() * * @param mixed $username * @param mixed $password * @return */ function connect($username, $password) { $this->connection = ssh2_connect($this->host, $this->port); if (!$this->connection) return $this->error("Could not connect to {$this->host}:{$this->port}"); $this->debug("Connected to {$this->host}:{$this->port}"); $authenticated = ssh2_auth_password($this->connection, $username, $password); if(!$authenticated) return $this->error("Could not authenticate: {$username}, check your password"); $this->debug("Authenticated successfully as {$username}"); $this->connected = true; return true; } /** * SSH2::exec() * * @param mixed $command shell command to execute * @param bool $onAvailableFunction a function to handle any available data. * @param bool $blocking blocking or non-blocking mode. This 'hangs' php execution until the command has completed if you set it to true. If you just want to start an import and go on, use this icm onAvailableFunction and false * @return */ function exec($command, $onAvailableFunction=false, $blocking=true) { $output = ''; $stream = ssh2_exec($this->connection, $command); $this->debug("Exec: {$command}"); if($onAvailableFunction !== false) { $lastReceived = time(); $timeout =false; while (!feof($stream) && !$timeout) { $input = fgets($stream, 1024); if(strlen($input) >0) { call_user_func($onAvailableFunction, $input); $this->debug($input); $lastReceived = time(); } else { if(time() - $lastReceived >= $this->timeout) { $timeout = true; $this->error('Connection timed out'); return($this->error); } } } } if($blocking === true && $onAvailableFunction === false) { stream_set_blocking($stream, true); $output = stream_get_contents($stream); $this->debug($output); } fclose($stream); return($output); } /** * SSH2::createDirectory() * * Creates a directory via sftp * * @param string $dirname * @return boolean success * */ function createDirectory($dirname) { $ftpconnection = ssh2_sftp ($this->connection); $dircreated = ssh2_sftp_mkdir($ftpconnection, $dirname, true); if(!$dircreated) { $this->debug("Directory not created: ".$dirname); } return $dircreated; } public function listFiles($dirname) { $input = $this->exec(escapeshellcmd("ls {$dirname}")); return(explode("\n", trim($input))); } public function sendFile($filename, $remotename) { $this->debug("sending {$filename} to {$remotename} "); if(file_exists($filename) && is_readable($filename)) { $result = ssh2_scp_send($this->connection, $filename, $remotename, 0664); } else { $this->debug("Unable to read file : ".$filename); return false; } if(!$result) $this->debug("Failure uploading {$filename} to {$remotename}"); return $result; } public function getFile($remotename, $localfile) { $this->debug("grabbing {$remotename} to {$localfile}"); $result = ssh2_scp_recv($this->connection, $remotename, $localfile); if(!$result) $this->debug("Failure downloading {$remotename} to {$localfile}"); return $result; } /** * SSH2::debug() * * @param mixed $message * @return */ function debug($message) { if($this->debugMode) { fwrite($this->debugPointer, date('Y-m-d H:i:s')." : ".$message."\n"); } } /** * SSH2::error() * * @param mixed $errorMsg * @return */ function error($errorMsg) { $this->error = $errorMsg; $this->debug($errorMsg); return false; } /** * SSH2::__destruct() * * @return */ function __destruct() { if($this->connection){ $this->connection = null; } if($this->debugMode && $this->debugPointer) { fclose($this->debugPointer); } } }
Anwendungsbeispiel:
$settings = Settings::Load()->Get("SecureServer"); $ssh = new SSH2($settings['host']); if( $ssh->connect($settings['username'], $settings['password'])) { echo $ssh->exec("ls -la ".$settings['path'], false, true); flush(); }
quelle
Theoretisch können Sie dies mit stream_set_blocking () tun, aber es sieht so aus, als ob es einige PHP-Fehler gibt, die STDIN verwalten.
Schauen Sie: http://bugs.php.net/bug.php?id=34972 http://bugs.php.net/bug.php?id=36030
Versuchen Sie es selbst:
echo "Enter Password: "; $stdin = fopen('php://stdin','r'); // Trying to disable stream blocking stream_set_blocking($stdin, FALSE) or die ('Failed to disable stdin blocking'); // Trying to set stream timeout to 1sec stream_set_timeout ($stdin, 1) or die ('Failed to enable stdin timeout');
quelle
Die akzeptierte Antwort ist nicht gut genug. Erstens funktioniert die Windows-Lösung unter Windows 7 und höher nicht. Die Lösung für andere Betriebssysteme hängt von dem in Bash und Bash integrierten "Lesen" ab. Es gibt jedoch Systeme, die Bash nicht verwenden (z. B. OpenBSD) und bei denen dies offensichtlich nicht funktioniert.
In diesem Blog habe ich eine Lösung besprochen, die auf fast jedem Unix-basierten Betriebssystem und Windows von 95 bis 8 funktioniert. Die Windows-Lösung verwendet ein externes Programm, das in C auf der obersten Win32-API geschrieben ist. Die Lösung für andere Betriebssysteme verwendet den externen Befehl 'stty'. Ich habe noch kein Unix-basiertes System gesehen, das kein 'stty' hat.
quelle