PHPSECLIB:致命错误:未捕获异常'RuntimeException',消息'连接已被服务器关闭'

时间:2016-03-14 16:37:23

标签: php phpseclib

这是我第一次在这里发帖提问,所以请耐心等待。这个问题让我的智慧结束了。下面详细描述了这个问题。我正在寻找的是运行phpseclib脚本后发生以下错误的潜在原因和可能的补救措施......

  

致命错误:/home/electroline_admin/orders.electrolineelectronics.com/classes/phpseclib/Net/SSH2.php:1075中未捕获的异常'RuntimeException',消息'连接已被服务器关闭'

堆栈追踪:

  

/home/electroline_admin/orders.electrolineelectronics.com/classes/phpseclib/Net/SSH2.php(1877年):   phpseclib \ Net \ SSH2-> _connect()[内部函数]:   phpseclib \ Net \ SSH2-> _login('electroline','Bitter8Steal_Wr ...')

     

/home/electroline_admin/orders.electrolineelectronics.com/classes/phpseclib/Net/SFTP.php(394):   call_user_func_array(Array,Array)

     

/home/electroline_admin/orders.electrolineelectronics.com/classes/class.orders.php(4974):   phpseclib \ Net \ SFTP->登录('electroline','Bitter8Steal_Wr ...')

     

/home/electroline_admin/orders.electrolineelectronics.com/live_orders_test.php(31):   orders-> ftp_in_nd(Array,'1383317685.md5E ...','/ home / electroli ...')

     抛出了

{main}   /home/electroline_admin/orders.electrolineelectronics.com/classes/phpseclib/Net/SSH2.php   在线1075 electroline_admin @ ps80038:〜$ / usr / local / php54 / bin / php   /home/electroline_admin/orders.electrolineelectronics.com/live_orders_test.php

所有关于类似问题的勤奋研究,但似乎没有任何指向有意义的答案。我最初的怀疑是存在超时问题,因为这个脚本正在调用并提取各种数量的大量文件。所以我增加了超时限制,但未能解决问题。

任何见解都将深表感谢。感谢!!!

下面提供详细的代码概述....

导致错误的代码如下......

public function pending_ftp()
{
    $dumped_arr = array('MAM');
    $cust_query = "SELECT DISTINCT `ID` AS ID,`CHUB` AS CH FROM `$this->tbl_cu`";
    $res_cust = $this->query($cust_query);

    if($res_cust[1])
    {
        while($cust_arr = mysql_fetch_array($res_cust[0],MYSQL_ASSOC))
        {
            $cust = $cust_arr['ID'];
            $chub = $cust_arr['CH'];
            if($chub == 'Y') $stg = $this->chub_ftp_settings($cust);
            elseif($cust == 'QBD') $stg = array('URL' => 'edi.esadmin.com','USR' => 'Electroline','PSW' => 'tVd&hP4','PRT' => 21,'DIR' => '/to_Electroline');
            else $stg = false;

            $pend_dir = '/home/electroline_admin/orders.electrolineelectronics.com/pending/'.strtolower($cust);

            if($stg)
            {
                $new_files = $this->ftp_get_filelist($stg); // METHOD CALLING PHPSECLIB CALLABLE

                foreach($new_files as $inx => $file_path)
                {
                    $file_info = pathinfo($file_path);
                    $file = $file_info['basename'];
                    $pend_path = $pend_dir.'/'.$file;
                    $ftp_sts = $this->ftp_in_nd($stg,$file,$pend_path); // METHOD CALLING PHPSECLIB CALLABLE
                }
            }
            elseif(in_array($cust,$dumped_arr))
            {
                $dump_dir = '/home/electroline_admin/orders.electrolineelectronics.com/dump/'.strtolower($cust);
                $dump_files = scandir($dump_dir);
                $not_a_file = array('.','..');

                foreach($dump_files as $inx => $file)
                {
                    if(!in_array($file,$not_a_file))
                    {
                        $dump_path = $dump_dir.'/'.$file;
                        $pend_path = $pend_dir.'/'.$file;

                        if(file_exists($dump_path)) $dump_copy = copy($dump_path,$pend_path);
                    }
                }
            }
        }
    }
}

...包含phpseclib可调用的具体方法如下

public function ftp_in_nd($settings,$remote_file,$local_path)
{
    if(isset($settings))
    {
        $furl = $settings['URL'];
        $fusr = $settings['USR'];
        $fpwd = $settings['PSW'];
        $fprt = is_numeric($settings['PRT']) && $settings['PRT'] > 0 ?  $settings['PRT'] : 21;
        $fdir = strlen($settings['DIR']) > 0 ? $settings['DIR'] : ''; 

        if($fprt == 22)
        {
            $fcon = new \phpseclib\Net\SFTP($furl,$fprt,30); // PHPSECLIB

            if($fcon->login($fusr,$fpwd)) // PHPSECLIB
            {
                $fmsg = "SFTP LOGIN SUCCESS ($fusr): $furl".(is_numeric($fprt) ? " on port $fprt" : '')." on ".date('Y-m-d @ H:i:s',time())."\r\n";
                $fmsg .= "FILE DOWNLOAD ATTEMPT ".date('Y-m-d @ H:i:s',time())."\r\n";

                $fcon->chdir($fdir);

                if($fcon->get($remote_file,$local_path)) // PHPSECLIB
                {
                    $fmsg .= "FILE DOWNLOADED ".date('Y-m-d @ H:i:s',time())."\r\n";

                    if(file_exists($local_path))
                    {
                        $fmsg .= "DOWNLOAD SUCCESSFULLY VERIFIED ".date('Y-m-d @ H:i:s',time())."\r\n";
                        $fstat = "SUCCESS";
                    }
                    else
                    {
                        $fmsg .= "DOWNLOAD NOT VERIFIED ".date('Y-m-d @ H:i:s',time())."\r\n";
                        $fstat = "UNVERIFIED";
                    }

                    goto bottom;
                }
                else
                {
                    $fmsg .= "FILE DOWNLOAD FAIL ".date('Y-m-d @ H:i:s',time())."\r\n";
                    $fstat = "FAIL";    
                    goto bottom;
                }
            }
            else
            {
                $fmsg .= "SFTP LOGIN FAIL ($fusr): file transfer attempt aborted on ".date('Y-m-d @ H:i:s',time())."\r\n";
                $fstat = "FAIL";
                goto bottom;
            }
        }
        else
        {
            if($fcon = ftp_connect($furl,(is_numeric($fprt) ? $fprt : 21)))
            {
                $fmsg = "FTP CONNECT SUCCESS: $furl".(is_numeric($fprt) ? " on port $fprt" : '')." on ".date('Y-m-d @ H:i:s',time())."\r\n";

                if(ftp_login($fcon,$fusr,$fpwd))
                {
                    $fmsg .= "FTP LOGIN SUCCESS ($fusr): $furl".(is_numeric($fprt) ? " on port $fprt" : 21)." on ".date('Y-m-d @ H:i:s',time())."\r\n";
                    $fmsg .= "FILE DOWNLOAD ATTEMPT ".date('Y-m-d @ H:i:s',time())."\r\n";

                    ftp_chdir($fcon,$fdir);

                    if(ftp_get($fcon,$local_path,$remote_file,FTP_BINARY))
                    {
                        $fmsg .= "FILE DOWNLOADED ".date('Y-m-d @ H:i:s',time())."\r\n";

                        if(file_exists($local_path))
                        {
                            $fmsg .= "DOWNLOAD SUCCESSFULLY VERIFIED ".date('Y-m-d @ H:i:s',time())."\r\n";
                            $fstat = "SUCCESS";
                        }
                        else
                        {
                            $fmsg .= "FILE DOWNLOAD NOT VERIFIED ".date('Y-m-d @ H:i:s',time())."\r\n";
                            $fstat = "UNVERIFIED";  
                        }

                        goto bottom;
                    }
                    else
                    {
                        $fmsg .= "FILE DOWNLOAD FAIL ".date('Y-m-d @ H:i:s',time())."\r\n";
                        $fstat = "FAIL";
                        goto bottom;
                    }
                }
                else
                {
                    $fmsg .= "FTP LOGIN FAIL ($fusr): file transfer attempt aborted on ".date('Y-m-d @ H:i:s',time())."\r\n";
                    $fstat = "FAIL";
                    goto bottom;
                }
            }
            else
            {
                $fmsg = "FTP CONNECT FAIL: file transfer attempt aborted on ".date('Y-m-d @ H:i:s',time())."\r\n";
                $fstat = "FAIL";
                goto bottom;
            }
        }
    }
    else
    {
        $fmsg = "FTP SETTINGS NOT PROVIDED: file transfer attempt aborted on ".date('Y-m-d @ H:i:s',time())."\r\n";
        $fstat = "FAIL";
        goto bottom;
    }

    bottom:

    if(!isset($fmsg)) $fmsg = "FTP NOT PROCESSED: process abandoned on ".date('Y-m-d @ H:i:s',time())."; check settings and reprocess\r\n";
    if(!isset($fstat)) $fstat = "FAIL";

    $stat['SID'] = $fstat;
    $stat['MSG'] = $fmsg;

    return $stat;
}

从我自己的行动和情报收集中,当从phpseclib SSH2类调用此方法时,似乎发生了失败的连接......

function _connect()
{
    if ($this->bitmap & self::MASK_CONSTRUCTOR) {
        return false;
    }

    $this->bitmap |= self::MASK_CONSTRUCTOR;

    $this->curTimeout = $this->timeout;

    $this->last_packet = microtime(true);

    if (!is_resource($this->fsock)) {
        $start = microtime(true);
        $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout);
        if (!$this->fsock) {
            $host = $this->host . ':' . $this->port;
            throw new \RuntimeException(rtrim("Cannot connect to $host. Error $errno. $errstr"));
        }
        $elapsed = microtime(true) - $start;

        $this->curTimeout-= $elapsed;

        if ($this->curTimeout <= 0) {
            $this->is_timeout = true;
            return false;
        }
    }

    /* According to the SSH2 specs,

      "The server MAY send other lines of data before sending the version
       string.  Each line SHOULD be terminated by a Carriage Return and Line
       Feed.  Such lines MUST NOT begin with "SSH-", and SHOULD be encoded
       in ISO-10646 UTF-8 [RFC3629] (language is not specified).  Clients
       MUST be able to process such lines." */
    $temp = '';
    $extra = '';
    while (!feof($this->fsock) && !preg_match('#^SSH-(\d\.\d+)#', $temp, $matches)) {
        if (substr($temp, -2) == "\r\n") {
            $extra.= $temp;
            $temp = '';
        }

        if ($this->curTimeout) {
            if ($this->curTimeout < 0) {
                $this->is_timeout = true;
                return false;
            }
            $read = array($this->fsock);
            $write = $except = null;
            $start = microtime(true);
            $sec = floor($this->curTimeout);
            $usec = 1000000 * ($this->curTimeout - $sec);
            // on windows this returns a "Warning: Invalid CRT parameters detected" error
            // the !count() is done as a workaround for <https://bugs.php.net/42682>
            if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
                $this->is_timeout = true;
                return false;
            }
            $elapsed = microtime(true) - $start;
            $this->curTimeout-= $elapsed;
        }

        $temp.= fgets($this->fsock, 255);
    }

    **if (feof($this->fsock)) {
        throw new \RuntimeException('Connection closed by server');
    }  // SCRIPT FAILS HERE!!! **

    $this->identifier = $this->_generate_identifier();

    if (defined('NET_SSH2_LOGGING')) {
        $this->_append_log('<-', $extra . $temp);
        $this->_append_log('->', $this->identifier . "\r\n");
    }

    $this->server_identifier = trim($temp, "\r\n");
    if (strlen($extra)) {
        $this->errors[] = utf8_decode($extra);
    }

    if ($matches[1] != '1.99' && $matches[1] != '2.0') {
        throw new \RuntimeException("Cannot connect to SSH $matches[1] servers");
    }

    fputs($this->fsock, $this->identifier . "\r\n");

    $response = $this->_get_binary_packet();
    if ($response === false) {
        throw new \RuntimeException('Connection closed by server');
    }

    if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
        throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT');
    }

    if (!$this->_key_exchange($response)) {
        return false;
    }

    $this->bitmap|= self::MASK_CONNECTED;

    return true;
}

1 个答案:

答案 0 :(得分:0)

嗯,我能够很好地连接:

<?php
include('Net/SSH2.php');

define('NET_SSH2_LOGGING', 2);

$ssh = new Net_SSH2('orders.electrolineelectronics.com');
$ssh->login('zzz', 'zzz');

echo $ssh->getLog();

我的意思是,我无法成功进行身份验证,但我可以进行身份​​验证尝试。

鉴于此,我的猜测是问题在于试图建立连接的计算机。与环境有关的东西。也许您安装了selinux,默认情况下会阻止fsockopen正常工作:

http://yml.com/fv-b-1-619/selinux--apache-httpd--php-establishing-socket-connections-using-fsockopen---et-al.html

或者您的主机可能orders.electrolineelectronics.com指向其他未安装SSH服务器的IP地址。

可能是任何数量的问题,但事实上,我能够与phpseclib连接得很好,这让我觉得问题是环境问题。特别是因为它在实际设法发送任何数据之前就已经死了(假设你的分析是正确的)。