Command Line Password Prompt in PHP

后端 未结 10 1459
北海茫月
北海茫月 2020-11-30 21:48

I\'m writing a command line tool to help my web app. It needs a password to connect to the service. I\'d like the script to show a password prompt so I don\'t have to pass i

相关标签:
10条回答
  • 2020-11-30 22:08

    I guess that there is no simple way of doing it (actually I can't think of any way) without using stty -echo. If you intent running it on windows, you could create a batch script that would provide the unechoed typed info to your php script.

    @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
    

    example taken from http://www.indiangnu.org/2008/php-hide-user-input-using-batch-script-windows/

    0 讨论(0)
  • 2020-11-30 22:08

    Why not use an SSH connection? You can abstract the commands away, redirect input/output and have full control.

    You can provide someone with a pure clean shell with as little rights as neccesary, and let the password just be POST'ed along with to SSH2::Connect() to open the shell.

    I created a nice class to work with the php SSH2 extension, maybe it helps you; (and it also does secure file transfers)

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

    Usage example:

    $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 讨论(0)
  • 2020-11-30 22:08

    The accepted answer is not good enough. First of all, the Windows solution doesn't work on Windows 7 and above. The solution for other OSs depends on Bash and bash built-in 'read'. However, there are systems which does not use Bash (eg. OpenBSD) and where this obviously won't work.

    In this blog I've discussed solution which works on almost any Unix based OS and Windows from 95 to 8. The Windows solution uses external program written in C on top Win32 API. The solution for other OSs uses external command 'stty'. I have yet to see a Unix based system which does not have 'stty'

    0 讨论(0)
  • 2020-11-30 22:09

    This is the easiest solution for all platforms:

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

    Then create prompt_win.bat in the same directory:

    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 讨论(0)
  • 2020-11-30 22:12

    You can use my hiddeninput.exe file to get real hidden input without leaking the information anywhere on screen.

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

    If you remove the last echo, the password should never show up, but you can use that for validation obvoiusly.

    0 讨论(0)
  • 2020-11-30 22:20

    Depending on your environment (i.e., not on Windows), you can use the ncurses library (specifically, the ncurses_noecho() function to stop keyboard echo and ncurses_getch() to read the input) to get the password without displaying it on screen.

    0 讨论(0)
提交回复
热议问题