2008-10-09 16 views
66

Estoy escribiendo una herramienta de línea de comandos para ayudar a mi aplicación web. Necesita una contraseña para conectarse al servicio. Me gustaría que el script muestre un mensaje de contraseña para que no tenga que pasarlo como un argumento de línea de comando.Solicitud de contraseña de la línea de comando en PHP

Eso es bastante fácil, pero me gustaría que no repita la contraseña de la pantalla a medida que se escribe. ¿Cómo puedo hacer esto con PHP?

Puntos extra por hacerlo en PHP puro (no system('stty')) y reemplazar los caracteres por *.

EDIT:

El script se ejecutará en un sistema Unix (Linux o Mac). La secuencia de comandos está escrita en PHP, y probablemente seguirá así.

Además, para el registro, la forma de hacerlo es stty:

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"; 

preferiría no tener las llamadas en system() allí.

+0

¿En qué sistema operativo se ejecutará el script de línea de comando? ¿El script de línea de comando se escribirá en PHP o en el lenguaje de scripts por lotes del sistema operativo? –

Respuesta

37

encontrado en sitepoint.

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

No funciona en Windows 7. De acuerdo con varios foros en línea, no funcionará en nada más que Windows XP y 2003 servidor. – Tgr

+0

Consulte mi respuesta a continuación (o vaya a https://github.com/Seldaek/hidden-input directamente) para obtener una solución que funcione desde XP hasta 7, 32/64 bits, y no aparezca ningún mensaje desagradable. – Seldaek

+0

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

2

Supongo que no hay una forma sencilla de hacerlo (en realidad no puedo pensar de ninguna manera) sin usar st-echo. Si intenta ejecutarlo en Windows, puede crear un script por lotes que proporcione la información tipeada no repuesta a su script php.

@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 

ejemplo tomado de http://www.indiangnu.org/2008/php-hide-user-input-using-batch-script-windows/

+0

buen truco para crear un archivo COM de solo texto (se parece un poco a la prueba antivirus EICAR ;-)) desafortunadamente esto no funcionará en Windows de 64 bits ... (no más soporte COM de 16 bits ... y creando un archivo EXE de esta manera ... ¡buena suerte!) – Ale

9

función de su entorno (es decir, no en Windows), puede utilizar la biblioteca ncurses (en concreto, la función ncurses_noecho() para detener el eco de teclado y ncurses_getch() para leer la entrada) para obtener la contraseña sin mostrarla en la pantalla.

1

¿Por qué no utilizar una conexión SSH? Puede abstraer los comandos, redirigir la entrada/salida y tener control total.

Puede proporcionarle a alguien una shell pura y limpia con los mínimos derechos necesarios, y deje que la contraseña se envíe por POST junto con SSH2 :: Connect() para abrir el shell.

He creado una buena clase para trabajar con la extensión php SSH2, quizás te ayude; (y que también hace las transferencias de archivos seguras) ejemplo

<?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); 
     } 
    }  


} 

Uso:

$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

recibo un error: PHP Error fatal: Clase 'Configuración' no encontrada en /home/tester/tools/SSH/conn_ssh3.php en la línea 2, he llamado ssh2 clase como Settings.php, y también trató de cambiar la configuración :: Load() a SSH2 :: Load() – kamal

-1

Teóricamente puede hacerlo utilizando stream_set_blocking(), pero parece que hay algunos errores de PHP que gestionan STDIN.

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

Pruebe usted mismo:

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

Usted puede usar mi archivo hiddeninput.exe para conseguir la entrada escondida real sin fugas la información en cualquier lugar de la pantalla.

<?php 

echo 'Enter password: '; 
$password = exec('hiddeninput.exe'); 
echo PHP_EOL; 

echo 'Password was: ' . $password . PHP_EOL; 

Si elimina el último eco, la contraseña nunca debe aparecer, pero se puede utilizar para la validación de que muy movido.

+1

No funciona en mi linux box por razones obvias. –

1

La respuesta aceptada no es suficiente. En primer lugar, la solución de Windows no funciona en Windows 7 y superior. La solución para otros sistemas operativos depende de Bash y bash built-in 'read'. Sin embargo, hay sistemas que no usan Bash (por ejemplo, OpenBSD) y donde obviamente esto no funcionará.

En esta blog he discutido la solución que funciona en casi cualquier sistema operativo basado en Unix y Windows de 95 a 8. La solución de Windows utiliza un programa externo escrito en C en la API Win32 superior. La solución para otros sistemas operativos utiliza el comando externo 'stty'. Todavía tengo que ver un sistema basado en Unix que no tiene 'stty'

+1

Creo que será mejor si proporciona una versión concisa de su publicación aquí (puede ser con solo ejemplos para cada enfoque), porque simplemente publicar un enlace va en contra de la idea inicial de los sitios de SE. – user907860

+0

¿Existe una biblioteca genérica que ofrezca la posibilidad de solicitar al usuario contraseñas, texto plano normal y opciones de menú en todas las plataformas? – CMCDragonkai

+0

@CMCDragonkai No, no hay. Dicha característica no está implementada en PHP, por lo que no se puede hacer utilizando solo PHP. Hay una extensión PHP de ncurses, pero no funciona en Windows. –

2

Esta es la solución más fácil para todas las plataformas:

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

A continuación, cree prompt_win.bat en el mismo directorio:

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' podría eliminar caracteres válidos (es decir, cualquier espacio en blanco que termine la cadena), pero puede omitirlo y usar' echo -n' en su lugar. – Synexis

1

Funciona en todos los sistemas de Windows, que tiene soporte de powershell. (fuente de: 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

He JMW solución de 3 line 's re-formateado por lo que sólo puede cortar y pegar en su código PHP existente.

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

Para usarlo:

$usersPassword=getPassword(); 

Estoy en Powershell V5.0, pero la ruta del directorio se muestra como sigue v1.0 por lo que la cadena entre comillas en la llamada shell_exec debería estar bien.

Cuestiones relacionadas