Запрос пароля командной строки в PHP

Я пишу инструмент командной строки, чтобы помочь моему веб-приложению. Для подключения к службе требуется пароль. Я хотел бы, чтобы сценарий показывал приглашение пароля, поэтому мне не нужно передавать его в качестве аргумента командной строки.

Это достаточно просто, но я бы хотел, чтобы он не повторял пароль на экране, когда он был напечатан. Как я могу это сделать с PHP?

Бонусные баллы за это делают в чистом PHP (без system('stty') ) и заменяют символы * .

РЕДАКТИРОВАТЬ:

Скрипт будет работать в системе unix (linux или mac). Сценарий написан на PHP, и, скорее всего, останется таким.

Кроме того, для записи, 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"; 

Я бы предпочел, чтобы там не было вызовов system() .

Solutions Collecting From Web of "Запрос пароля командной строки в PHP"

Найдено на сайте.

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

Вы можете использовать мой файл hiddeninput.exe для получения реального скрытого ввода без утечки информации в любом месте экрана.

 <?php echo 'Enter password: '; $password = exec('hiddeninput.exe'); echo PHP_EOL; echo 'Password was: ' . $password . PHP_EOL; 

Если вы удалите последнее эхо, пароль никогда не появится, но вы можете использовать его для проверки obvoiusly.

В зависимости от вашей среды (т. Е. Не в Windows) вы можете использовать библиотеку ncurses (в частности, функцию ncurses_noecho (), чтобы остановить клавиатурное эхо и ncurses_getch () для чтения ввода), чтобы получить пароль, не отображая его на экране.

Я предполагаю, что нет простого способа сделать это (на самом деле я никак не могу придумать) без использования stty -echo. Если вы намереваетесь запустить его на окнах, вы можете создать пакетный скрипт, который предоставит неименованную введенную информацию вашему скрипту php.

 @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 

пример из http://www.indiangnu.org/2008/php-hide-user-input-using-batch-script-windows/

Это самое простое решение для всех платформ:

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

Затем создайте prompt_win.bat в том же каталоге:

 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! 

Почему бы не использовать SSH-соединение? Вы можете абстрагировать команды, перенаправить ввод / вывод и получить полный контроль.

Вы можете предоставить кому-то чистую чистую оболочку с минимальными правами, а также пароль, который будет POST'ed вместе с SSH2 :: Connect (), чтобы открыть оболочку.

Я создал хороший класс для работы с расширением php SSH2, возможно, это поможет вам; (и он также обеспечивает безопасную передачу файлов)

 <?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('Ymd--Hi-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('Ymd 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); } } } 

Пример использования:

 $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(); } 

Принятый ответ недостаточно хорош. Прежде всего, решение Windows не работает в Windows 7 и выше. Решение для других ОС зависит от Bash и bash встроенного «чтения». Однако существуют системы, которые не используют Bash (например, OpenBSD), и это явно не сработает.

В этом блоге я обсуждал решение, которое работает практически с любой ОС на базе Unix и Windows с 95 до 8. В решении Windows используется внешняя программа, написанная на C поверх Win32 API. Решение для других ОС использует внешнюю команду 'stty'. Мне еще предстоит увидеть систему на основе Unix, которая не имеет «stty»,

Работает на каждой системе Windows, которая имеет поддержку powershell. (источник от: 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"; 

Я переформатировал трехлинейное решение JMW, чтобы вы могли просто вырезать и вставить его в существующий PHP-код.

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

Чтобы использовать его:

 $usersPassword=getPassword(); 

Я нахожусь в Powershell V5.0, но путь к каталогу по-прежнему отображается как v1.0, поэтому строка с кавычками в вызове shell_exec должна быть в порядке.

Теоретически вы можете сделать это с помощью stream_set_blocking (), но похоже, что есть некоторые ошибки PHP, управляющие STDIN.

Посмотрите: http://bugs.php.net/bug.php?id=34972 http://bugs.php.net/bug.php?id=36030

Попробуйте сами:

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