2008-10-09 15 views
66

Ich schreibe ein Befehlszeilentool, um meine Webanwendung zu unterstützen. Es benötigt ein Passwort, um sich mit dem Dienst zu verbinden. Ich möchte, dass das Skript eine Kennworteingabeaufforderung anzeigt, sodass ich es nicht als Befehlszeilenargument übergeben muss.Eingabeaufforderung für Befehlszeile in PHP

Das ist einfach genug, aber ich möchte es nicht das Passwort auf dem Bildschirm, wie es getippt ist. Wie kann ich das mit PHP machen?

Bonuspunkte für reines PHP (system('stty')) und Ersetzen der Zeichen durch *.

EDIT:

Das Skript auf einem Unix-artiges System läuft (Linux oder Mac). Das Skript ist in PHP geschrieben und wird wahrscheinlich so bleiben.

Auch für die Aufzeichnung, die stty Art und Weise, es zu tun ist:

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, nicht die system() Anrufe in dort haben.

+0

Auf welches Betriebssystem wird das Befehlszeilenskript ausgeführt? Wird das Befehlszeilenskript in PHP oder in der Batch-Skriptsprache des Betriebssystems geschrieben? –

Antwort

37

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; 
    } 
} 
+2

Funktioniert nicht auf Windows 7. Nach verschiedenen Online-Foren, wird nicht auf etwas anderes als Windows XP und funktionieren 2003 Server. – Tgr

+0

Siehe meine Antwort unten (oder gehen Sie direkt zu https://github.com/Seldaek/hidden-input) für eine Lösung, die von XP bis zu 7, 32/64bit und keine hässliche Aufforderung funktioniert. – Seldaek

+0

http://www.qxs.ch/2013/02/08/php-cli-password-prompts-on-windows-7/ – JMW

2

Ich denke, dass es keine einfache Möglichkeit gibt, es zu tun (eigentlich kann ich mir keinen Weg vorstellen), ohne stty -echo zu verwenden. Wenn Sie beabsichtigen, es unter Windows auszuführen, könnten Sie ein Batch-Skript erstellen, das Ihrem PHP-Skript die unechotierten, typisierten Informationen liefert.

@echo off 
cls 
SET /P uname=Enter Username: 
echo hP1X500P[PZBBBfh#b##[email protected]`$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/

+0

netter Trick, um eine Text-only-COM-Datei zu erstellen (sieht ein bisschen aus wie der EICAR-Anti-Virus-Test ;-)) Leider funktioniert das nicht unter 64-Bit-Windows ... (nicht mehr 16-Bit-COM-Unterstützung ... und Erstellen einer EXE-Datei auf diese Weise ... viel Glück!) – Ale

9

Je nach Umgebung (dh nicht unter Windows), können Sie die ncurses-Bibliothek verwenden (genauer gesagt, die ncurses_noecho() Funktionstastatur Echo und ncurses_getch() zu lesen, um den Eingang zu stoppen) um das Passwort zu erhalten, ohne es auf dem Bildschirm anzuzeigen.

1

Warum nicht eine SSH-Verbindung verwenden? Sie können die Befehle abstrahieren, Eingabe/Ausgabe umleiten und volle Kontrolle haben.

Sie können jemandem mit einer reinen, sauberen Shell mit so wenig Rechten wie nötig zur Verfügung stellen, und lassen Sie das Passwort nur mit SSH2 :: Connect() POST'ed, um die Shell zu öffnen.

Ich schuf eine nette Klasse, um mit der php SSH2 Erweiterung zu arbeiten, vielleicht hilft es Ihnen; (und tut es 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();  
} 
+0

Ich bekomme Fehler: PHP Schwerwiegender Fehler: Klasse "Einstellungen" nicht in /home/tester/tools/SSH/conn_ssh3.php in Zeile 2 gefunden, nannte ich die ssh2 Klasse als Settings.php, und auch versucht, die Einstellungen ändern :: Load() zu SSH2 :: Load() – kamal

-1

theorically können Sie es tun stream_set_blocking(), sieht aber wie es einige Bugs STDIN Verwaltung PHP sind.

Look: http://bugs.php.net/bug.php?id=34972 http://bugs.php.net/bug.php?id=36030

selbst ausprobieren:

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');
11

Sie können meine hiddeninput.exe Datei verwenden versteckten Eingang zu erhalten, ohne die Informationen irgendwo auf dem Bildschirm undicht.

Wenn Sie das letzte Echo entfernen, sollte das Passwort nie angezeigt werden, aber Sie können es für die Validierung verwenden.

+1

Funktioniert aus offensichtlichen Gründen nicht auf meiner Linux-Box. –

1

Die akzeptierte Antwort ist nicht gut genug. Vor allem funktioniert die Windows-Lösung nicht unter Windows 7 und höher. Die Lösung für andere Betriebssysteme hängt von Bash und Bash 'Read' ab. Es gibt jedoch Systeme, die Bash nicht benutzen (zB OpenBSD) und wo dies offensichtlich nicht funktioniert.

In diesem blog Ich habe Lösung diskutiert, die fast funktioniert auf jedem Unix-basierten Betriebssystem und Windows von 95 bis 8. Die Windows-Lösung externe Programm verwendet auf Win32-API in C geschrieben. Die Lösung für andere Betriebssysteme verwendet den externen Befehl 'stty'. Ich habe noch ein Unix-basiertes System, um zu sehen, die nicht über ‚stty‘

+1

Ich denke, es ist besser, wenn Sie hier eine prägnante Version Ihres Beitrags bereitstellen (möglicherweise nur mit Beispielen für jeden Ansatz), denn ein einfacher Verweis ist gegen die ursprüngliche Idee von SE-Websites. – user907860

+0

Gibt es eine generische Bibliothek, die die Möglichkeit bietet, den Benutzer zur Eingabe von Passwörtern, normalem Klartext und Menüoptionen auf der ganzen Plattform aufzufordern? – CMCDragonkai

+0

@CMCDragonkai Nein, gibt es nicht. Diese Funktion ist in PHP nicht implementiert und kann daher nicht nur mit PHP ausgeführt werden. Es gibt eine PHP-Erweiterung von Ncurses, aber es funktioniert nicht unter Windows. –

2

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 prompt_win.bat im gleichen Verzeichnis erstellen:

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! 
+0

'rtrim' konnte gültige Zeichen (d. H. Alle Leerzeichen, die die Zeichenfolge beenden) strippen, aber Sie können es weglassen und stattdessen' echo -n' verwenden. – Synexis

1

Funktioniert auf jedem Windows-System, das Powershell unterstützt. (Quelle aus: 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"; 
0

Ich habe JMW ‚s 3 line Lösung erneut formatiert, so dass Sie nur schneiden kann und es in Ihre bestehende PHP-Code einfügen.

function getPassword() 
{ 
    $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]; 
    return $pwd; 
} 

es zu benutzen:

$usersPassword=getPassword(); 

Ich bin auf Powershell V5.0 aber der Verzeichnispfad zeigt nach wie vor als v1.0 so die Zeichenfolge in Anführungszeichen in dem shell_exec Aufruf OK sein sollte.

Verwandte Themen