ssh2_connect

(PECL ssh2 >= 0.9.0)

ssh2_connect连接到 SSH 服务器

说明

ssh2_connect(
    字符串 $host,
    整数 $port = 22,
    数组 $methods = ?,
    数组 $callbacks = ?
): 资源|false

建立与远程 SSH 服务器的连接。

连接后,客户端应使用 ssh2_fingerprint() 验证服务器的主机密钥,然后使用密码或公钥进行身份验证。

参数

host

port

methods

methods 可以是关联数组,最多包含四个参数,如下所述。

methods 可以是关联数组,包含以下任何或所有参数。
索引 含义 支持的值*
kex 要通告的密钥交换方法列表,以逗号分隔,按优先级排序。 diffie-hellman-group1-sha1diffie-hellman-group14-sha1diffie-hellman-group-exchange-sha1
hostkey 要通告的主机密钥方法列表,以逗号分隔,按优先级排序。 ssh-rsassh-dss
client_to_server 关联数组,包含从客户端到服务器发送的消息的加密、压缩和消息认证码 (MAC) 方法首选项。  
server_to_client 关联数组,包含从服务器到客户端发送的消息的加密、压缩和消息认证码 (MAC) 方法首选项。  

* - 支持的值取决于底层库支持的方法。有关更多信息,请参阅 » libssh2 文档。

client_to_serverserver_to_client 可以是关联数组,包含以下任何或所有参数。
索引 含义 支持的值*
crypt 要通告的加密方法列表,以逗号分隔,按优先级排序。 [email protected]aes256-cbcaes192-cbcaes128-cbc3des-cbcblowfish-cbccast128-cbcarcfournone**
comp 要通告的压缩方法列表,以逗号分隔,按优先级排序。 zlibnone
mac 要通告的 MAC 方法列表,以逗号分隔,按优先级排序。 hmac-sha1hmac-sha1-96hmac-ripemd160[email protected]none**

注意: 加密和 MAC 方法 "none"

出于安全原因,除非在构建时使用相应的 ./configure 选项明确启用,否则底层 » libssh2 库将禁用 none。有关更多信息,请参阅底层库的文档。

callbacks

callbacks 可以是关联数组,包含以下任何或所有参数。

回调参数
索引 含义 原型
ignore 接收 SSH2_MSG_IGNORE 包时调用的函数名称 void ignore_cb($message)
debug 接收 SSH2_MSG_DEBUG 包时调用的函数名称 void debug_cb($message, $language, $always_display)
macerror 接收包但消息认证码失败时调用的函数名称。如果回调返回 true,则将忽略不匹配,否则将终止连接。 bool macerror_cb($packet)
disconnect 接收 SSH2_MSG_DISCONNECT 包时调用的函数名称 void disconnect_cb($reason, $message, $language)

返回值

成功时返回资源,错误时返回 false

示例

示例 #1 ssh2_connect() 示例

打开连接,强制在发送数据包时使用 3des-cbc,在接收数据包时使用任何强度的 aes 密码,在两个方向上都不进行压缩,并使用 Group1 密钥交换。

<?php
/* 如果服务器终止连接,通知用户 */
function my_ssh_disconnect($reason, $message, $language) {
printf("服务器以原因代码 [%d] 和消息断开连接: %s\n",
$reason, $message);
}

$methods = array(
'kex' => 'diffie-hellman-group1-sha1',
'client_to_server' => array(
'crypt' => '3des-cbc',
'comp' => 'none'),
'server_to_client' => array(
'crypt' => 'aes256-cbc,aes192-cbc,aes128-cbc',
'comp' => 'none'));

$callbacks = array('disconnect' => 'my_ssh_disconnect');

$connection = ssh2_connect('shell.example.com', 22, $methods, $callbacks);
if (!
$connection) die('连接失败');
?>

参见

添加注释

用户贡献的注释 8 个注释

Steve Kamerman
13 年前
由于缺少完整的示例,以下是一个简单的 SSH2 类,用于连接到服务器、使用公钥身份验证进行身份验证、验证服务器的指纹、发出命令并读取其 STDOUT,以及正确断开连接。注意:您可能需要确保您的命令生成输出,以便可以提取响应。有些人建议在提取响应之前不会执行命令。
<?php
class NiceSSH {
// SSH 主机
private $ssh_host = 'myserver.example.com';
// SSH 端口
private $ssh_port = 22;
// SSH 服务器指纹
private $ssh_server_fp = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
// SSH 用户名
private $ssh_auth_user = 'username';
// SSH 公钥文件
private $ssh_auth_pub = '/home/username/.ssh/id_rsa.pub';
// SSH 私钥文件
private $ssh_auth_priv = '/home/username/.ssh/id_rsa';
// SSH 私钥密码(null == 无密码)
private $ssh_auth_pass;
// SSH 连接
private $connection;

public function
connect() {
if (!(
$this->connection = ssh2_connect($this->ssh_host, $this->ssh_port))) {
throw new
Exception('无法连接到服务器');
}
$fingerprint = ssh2_fingerprint($this->connection, SSH2_FINGERPRINT_MD5 | SSH2_FINGERPRINT_HEX);
if (
strcmp($this->ssh_server_fp, $fingerprint) !== 0) {
throw new
Exception('无法验证服务器身份!');
}
if (!
ssh2_auth_pubkey_file($this->connection, $this->ssh_auth_user, $this->ssh_auth_pub, $this->ssh_auth_priv, $this->ssh_auth_pass)) {
throw new
Exception('服务器拒绝认证');
}
}
public function
exec($cmd) {
if (!(
$stream = ssh2_exec($this->connection, $cmd))) {
throw new
Exception('SSH 命令执行失败');
}
stream_set_blocking($stream, true);
$data = "";
while (
$buf = fread($stream, 4096)) {
$data .= $buf;
}
fclose($stream);
return
$data;
}
public function
disconnect() {
$this->exec('echo "EXITING" && exit;');
$this->connection = null;
}
public function
__destruct() {
$this->disconnect();
}
}
?>

[EDIT BY danbrown AT php DOT net: Contains two bugfixes suggested by 'AlainC' in user note #109185 (removed) on 26-JUN-2012.]
thessoro at gmail dot com
9 years ago
在提供特定主机密钥顺序时要小心。

<?php
ssh2_connect
('IP', 'port', array('hostkey'=>'ssh-rsa, ssh-dss'));
?>

仅当服务器的公钥是 RSA 时才有效,而不是像预期的那样也支持 DSA。这是因为 "ssh-dss" 前面的空格造成的。

所以类似的代码

<?php
ssh2_connect
('IP', 'port', array('hostkey'=>'ssh-rsa,ssh-dss'));
?>

将有效。HOSTKEY 方法使用您编写的完全内容进行覆盖,因此不允许空格。

这花了我一些时间,你可以节省下来;)
christophermjgray at gmail dot com
6 years ago
此页面已过时。由于 Logjam (https://weakdh.org/logjam.html),kex 部分中的密钥交换方法中的任何 SHA-1 都应该被丢弃。如果您继续使用它们,连接将导致以下警告
"Warning: ssh2_connect(): Error starting up SSH connection(-5): Unable to exchange encryption keys in ..."

以下是一个有效的示例。此外,通过完全删除 'hex' 部分,libssl (https://libssh2.org/) 将回退到发现用于身份验证的最强密码。

<?php

if (!function_exists("ssh2_connect")) die("function ssh2_connect doesn't exist");

function
ssh2_debug($message, $language, $always_display) {
printf("%s %s %s\n",$message,$language,$always_display);
}

/* Notify the user if the server terminates the connection */
function my_ssh_disconnect($reason, $message, $language) {
printf("Server disconnected with reason code [%d] and message: %s\n", $reason, $message);
}

$methods = array(
'hostkey'=>'ssh-rsa,ssh-dss',
// 'kex' => 'diffie-hellman-group-exchange-sha256',
'client_to_server' => array(
'crypt' => 'aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-cbc,blowfish-cbc',
'comp' => 'none'),
'server_to_client' => array(
'crypt' => 'aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-cbc,blowfish-cbc',
'comp' => 'none'));

$callbacks = array('disconnect' => 'my_ssh_disconnect');

foreach (array(
'192.168.1.1') as $host) {
$connection = ssh2_connect($host, 22, $methods, $callbacks);
if (!
$connection) die("Connection failed:");

ssh2_auth_password($connection, 'user', 'my_password') or die("Unable to authenticate");
$stream = ssh2_exec($connection, 'free -m');
stream_set_blocking($stream, true);
$stream_out = ssh2_fetch_stream($stream, SSH2_STREAM_STDIO);
echo
stream_get_contents($stream_out);
}

?>
jrdbrndt at gmail dot com
4 years ago
尝试在加密方法列表中包含 "aes256-cbc" 会导致错误。此处的文档可能已过时,您可能需要在 libssh2.org 上检查 libssh2 文档以找到更准确的接受值列表。
Trev White
11 years ago
您好!
如果您在运行 ssh2 会话时遇到问题,并且在执行 stream_get_contents 时无限期等待,可能是因为远程系统已运行命令,现在处于 # 提示符下,正在等待下一个命令。我在 HP MSA 盒子上遇到了这个问题,以下代码可以解决这个问题。

假设您已使用您的身份验证方法连接,并且 $ssh 包含句柄。

<?php
$command
= "检查磁盘";
// 打开一个足够大的窗口以防止换行
$stream = ssh2_shell ($ssh, 'xterm', null, 200, 200, SSH2_TERM_UNIT_CHARS);

// 连接到错误流
$errorStream = ssh2_fetch_stream($stream, SSH2_STREAM_STDERR);

// 阻塞流,以便我们等待它们完成
stream_set_blocking ($stream, true);
stream_set_blocking($errorStream, true);

// 将命令发送到终端
fwrite ($stream, $command . PHP_EOL );

// 等待终端有机会接受并开始处理命令,毕竟这是一个慢速存储设备
sleep(2);

// 重要步骤!在等待流之前,向终端发送退出命令以关闭连接
fwrite ($stream, "exit" . PHP_EOL );
sleep (2);

// 打印输出
echo stream_get_contents($stream);
$errortext=stream_get_contents($errorStream);

if (
strlen($errortext) > 0) {
// 错误数据
echo "错误数据: $errortext";
exit (
1);
}

// 正常情况
exit (0);

?>

您不能使用 ssh2_exec 方法(至少我不能),因为在执行第一个命令时,流会被阻塞,然后您就无法运行退出命令,而终端似乎使用了一个会话。

希望这对某些人有所帮助。
suri dot suribala dot com
19 年前
在 Sara 的帮助下,我创建了以下 SS2 类,它非常灵活。如果有人改进它,请随时告诉我。

<?php

// ssh 协议
// 注意:一旦使用 openShell 方法,cmdExec 就不起作用

class ssh2 {

private
$host = '主机';
private
$user = '用户';
private
$port = '22';
private
$password = '密码';
private
$con = null;
private
$shell_type = 'xterm';
private
$shell = null;
private
$log = '';

function
__construct($host='', $port='' ) {

if(
$host!='' ) $this->host = $host;
if(
$port!='' ) $this->port = $port;

$this->con = ssh2_connect($this->host, $this->port);
if( !
$this->con ) {
$this->log .= "连接失败!";
}

}

function
authPassword( $user = '', $password = '' ) {

if(
$user!='' ) $this->user = $user;
if(
$password!='' ) $this->password = $password;

if( !
ssh2_auth_password( $this->con, $this->user, $this->password ) ) {
$this->log .= "授权失败!";
}

}

function
openShell( $shell_type = '' ) {

if (
$shell_type != '' ) $this->shell_type = $shell_type;
$this->shell = ssh2_shell( $this->con, $this->shell_type );
if( !
$this->shell ) $this->log .= " Shell 连接失败!";

}

function
writeShell( $command = '' ) {

fwrite($this->shell, $command."\n");

}

function
cmdExec( ) {

$argc = func_num_args();
$argv = func_get_args();

$cmd = '';
for(
$i=0; $i<$argc ; $i++) {
if(
$i != ($argc-1) ) {
$cmd .= $argv[$i]." && ";
}else{
$cmd .= $argv[$i];
}
}
echo
$cmd;

$stream = ssh2_exec( $this->con, $cmd );
stream_set_blocking( $stream, true );
return
fread( $stream, 4096 );

}

function
getLog() {

return
$this->log;

}

}

?>
devoldemar
11 个月前
当您需要检查远程服务器的真实性时,使用 'hostkey' 选项是有意义的,例如通过 ssh2_fingerprint 函数。为此,您需要指定一个按优先级降序排序的可能算法列表。支持的值还包括 'ssh-ed25519'、'ecdsa-sha2-nistp256'、'ecdsa-sha2-nistp384' 和 'ecdsa-sha2-nistp521'。
例如
<?php
$ssh
= ssh2_connect('192.168.3.1', 22, ['hostkey' => 'ssh-ed25519,ssh-rsa']);
$md5 = ssh2_fingerprint($ssh); // 返回 ED25519 主机密钥的 MD5 哈希值,或者如果不存在先前类型的密钥,则返回 RSA 密钥的 MD5 哈希值
?>

注意,如果远程服务器没有相应类型的密钥,连接将失败
<?php
$ssh
= ssh2_connect('192.168.3.1', 22, ['hostkey' => 'ssh-dss']);
PHP Warning: ssh2_connect(): 启动 SSH 连接时出错(-5): 无法在 php shell 代码的第 1 行交换加密密钥
PHP Warning
: ssh2_connect(): 无法连接到 192.168.3.1 在 php shell 代码的第 1 行
?>
rainerkrauss at googlemail dot com
10 年前
警告!如果您打开一个 ssh 连接并执行打开另一个 ssh 连接的外部程序,可能会导致非常奇怪的行为。

我使用了 sftp 连接获取文件列表,并使用 "exec" 命令通过外部 sftp 下载文件。lftp 下载了全是零的文件,没有任何提示信息,psftp 大多数情况下会退出并返回错误代码 11,但有时它也能正常工作,这可能取决于 PHP 垃圾回收和关闭未使用连接的速度。

由于没有关闭连接的函数,你需要确保销毁所有引用(unset)来关闭连接。
To Top