81

Web アプリを支援するコマンド ライン ツールを作成しています。サービスに接続するにはパスワードが必要です。スクリプトにパスワード プロンプトを表示させたいので、コマンド ライン引数として渡す必要はありません。

それは簡単ですが、入力時にパスワードを画面にエコーしないようにしたいと思います。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()です。

4

11 に答える 11

42

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;
  }
}
于 2009-11-04T14:41:55.480 に答える
11

環境に応じて(つまり、Windowsではない)、ncursesライブラリ(具体的には、ncurses_noecho()関数を使用してキーボードエコーを停止し、ncurses_getch()を使用して入力を読み取る)を使用して、パスワードを画面に表示せずに取得できます。

于 2008-10-09T17:40:42.707 に答える
9

私のhiddeninput.exeファイルを使用して、画面上のどこにも情報を漏らすことなく、実際の非表示の入力を取得できます。

<?php

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

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

最後のエコーを削除すると、パスワードが表示されることはありませんが、明らかにそれを検証に使用できます。

于 2012-08-25T22:21:47.833 に答える
3

これは、すべてのプラットフォームで最も簡単なソリューションです。

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!
于 2014-09-07T02:18:56.940 に答える
2

stty -echoを使わずにそれを行う簡単な方法はないと思います(実際には私は何も考えられません)。Windowsで実行する場合は、選択されていない型付き情報を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/から抜粋した例

于 2008-10-09T15:28:45.657 に答える
2

PowerShell をサポートするすべての Windows システムで動作します。(出典: 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";
于 2016-09-03T18:19:37.177 に答える
1

受け入れられた答えは十分ではありません。まず、Windows ソリューションは Windows 7 以降では機能しません。他の OS のソリューションは、Bash および bash 組み込みの「読み取り」に依存します。ただし、Bash を使用しないシステム (OpenBSD など) もあり、これが明らかに機能しない場合もあります。

このブログでは、95 から 8 までのほぼすべての Unix ベースの OS と Windows で動作するソリューションについて説明しました。Windows ソリューションは、Win32 API 上で C で記述された外部プログラムを使用します。他の OS のソリューションは、外部コマンド 'stty' を使用します。「stty」を持たない Unix ベースのシステムはまだ見たことがありません。

于 2013-06-21T15:26:35.180 に答える
0

SSH接続を使用してみませんか?コマンドを抽象化し、入力/出力をリダイレクトし、完全に制御できます。

必要なだけの権限を持つ純粋でクリーンなシェルを誰かに提供し、パスワードをSSH2 :: Connect()にPOSTして、シェルを開くことができます。

私はphpSSH2拡張機能を操作するための素晴らしいクラスを作成しました。多分それはあなたを助けるでしょう。(そしてそれはまた安全なファイル転送をします)

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


}

使用例:

$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();    
}
于 2008-10-09T18:03:28.810 に答える
0

理論的には、stream_set_blocking() を使用して実行できますが、STDIN を管理する PHP のバグがいくつかあるようです。

見てください: 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');
于 2008-11-18T13:12:13.153 に答える