【问题标题】:Sending input to the blocking stream of PHP ssh将输入发送到 PHP ssh 的阻塞流
【发布时间】:2013-07-02 09:50:44
【问题描述】:

我的情况与以下问题类似 SSH2 change a user password

唯一的区别是我的操作是“scp”,我想通过 PHP 发送 ssh 命令以使用 scp 命令将文件发送到远程机器(我知道 php 本身有方法来实现这一点,但由于某种原因,我跳过那个方法)。

Code is as follows



//run specified cmd with stream reading and writing
    function runCMDAdvance($cmd){
        if (strpos($cmd,'scp') !== false) {
                        //reply machine when ask for password in file transfer
            $confirmPass = $this->password."\n".$this->password."\n";
            if (!($stream = ssh2_exec($this->conn, $cmd )))
            {
                echo "fail: unable to execute command\n";
                fclose($stream);
                return ERROR_SSH_EXEC_COMM;
            }

            fwrite($stream,$confirmPass); //>>Actually I want to pass the password information by writing to the stream, but turn out that it does not work
            stream_set_blocking($stream, true);
        }
    }

当我尝试在流集阻塞后写入密码信息时,php执行代码会卡住。 (我猜原因可能是远程机器在等待密码信息,但是 php 不能给它们,所以它一直在等待并阻塞 php 运行线程。)

我已经阅读了上述问题,但似乎无法找到实现这一目标的正确方向,对此有什么想法吗??

再次感谢大家的帮助!

参考neubert的回答,使用phpseclib还是不行...

//$cmd is $cmd =  'scp '.$scpPath.' root@'.$ip.':/root';
function runCMDAdvance($cmd, $tVal){

        if (strstr($cmd,"scp")!==FALSE){
            if((include('Net/SSH2.php')) && (include('Net/SCP.php'))){
                //set ssh timeout value
                $this->setTimeoutVar($tVal);

                $ssh = new Net_SSH2($this->host);
                if (!$ssh->login($this->username, $this->password)){
                    echo "Bad Login";
                    return false;
                }
                $ssh->write($cmd."\n");
                $ssh->read(' password:');
                $ssh->write($this->password."\n");
            }
        }
        else{
            echo "Wrong command used, please check your code";
            return false;
        }
    }

我处理SSH读写流的解决方案

//run any specified cmd using ssh
    //parameter:
    //cmd>>running command
    //tVal>>command run timeout
    //return:terminal stdout
    function runCMDAdvance($sshIP, $cmd, $tVal,$tarIP){
        $ssh = new Net_SSH2($sshIP);
        if (!$ssh->login($this->username, $this->password)){
            echo "Bad Login";
            return false;
        }
        //set timeout for running ssh command, should be done after the ssh object has been initialized
        $ssh->setTimeout($tVal);

        //scp action detected
        if (strstr($cmd,"scp")!==FALSE){
            //if this is the first time to do the ssh, connect with "yes" for answering
            if ($ssh->write($cmd)){
                //store the output of the text message given by the router
                $ssh_stdout = $ssh->read();
                //echo $ssh_stdout."|||";
                if (strstr($ssh_stdout,'trusted ')!==FALSE){
                    $ssh->write("y\n");
                    //and ask password
                    $ssh->read(' :password');
                }
                //deal with known host situation
                elseif (strstr($ssh_stdout,'ssh-keygen ')!==FALSE){
                    $ssh->write('ssh-keygen -f '.'/root/.ssh/known_hosts -R '.$tarIP."\n");
                    $ssh->write($cmd);
                    $ssh->read(' :password');
                    $ssh->write($this->password."\n");
                    return true;
                }
                //deal with still connecting situation
                elseif (strstr($ssh_stdout,'Are you sure you want to continue connecting')!==FALSE){
                    $ssh->write("yes\n");
                    $ssh->read(' :password');
                    $ssh->write($this->password."\n");
                    return true;
                }
                $ssh->write($this->password."\n");
                $returnRead = $ssh->read();
                $ssh->disconnect();
                return true;
            }//end of inner inner if
        }//end of scp if (deal with scp)
        else{//if not scp action,just normal action,simply execute the command
            //exec will not return anything if the command is not run successfully
            $res = $ssh->exec($cmd);
            $ssh->disconnect();
            return $res;
        }
    }

【问题讨论】:

    标签: php ssh stream blocking


    【解决方案1】:

    以下是使用phpseclib, a pure PHP SSH2 implementation 的方法:

    <?php
    include('Net/SSH2.php');
    
    define('NET_SSH2_LOGGING', 3);
    
    $ssh = new Net_SSH2('www.website1.com');
    $ssh->login('username', 'password');
    
    $ssh->write("ssh username@www.website2.com\n");
    $ssh->read(' password:');
    $ssh->write("password\n");
    
    $ssh->setTimeout(0.5);
    echo $ssh->read();
    

    【讨论】:

    • 感谢方法,不过我试过了,还是像以前一样挂掉我的脚本,不知道是哪一部分出错了……
    • 我已更新我的代码以添加 decine('NET_SSH2_LOGGING', 3)。这将输出来回发送的原始未加密的 SSH 数据包。如果你能发布那将是很棒的。谢谢!
    • 嗨neubert,抱歉回复晚了,我终于弄明白了,这是我的程序错误,与代码无关,我现在可以使用phpseclib成功进行读写流,我会的本周晚些时候发布工作代码,感谢大家的大力帮助,尤其是 neubert!
    【解决方案2】:

    scp(以及ssh)不期望密码,而是来自标准输入,而是来自控制台(如tty),这是一件好事。将密码存储在任何地方(例如某些 PHP 代码)会损害 ssh 的目的。

    相反,您应该创建一个 RSA 身份验证密钥。 Here is a simple how-to.

    完成后,如下更改命令行:

    scp -i /path/to/your/rsa.private.key
    

    确保将此私钥存储在“安全”位置。它必须可以从您的 PHP 脚本访问,但不能从其他脚本访问。特别是不要让它从 URL 访问。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-25
      • 2011-12-23
      • 1970-01-01
      • 2013-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-17
      相关资源
      最近更新 更多