本文目录导读:

在PHP项目中通过SSH远程管理服务器并执行命令,主要有以下几种方法:
使用 PHP SSH2 扩展(推荐)
安装 SSH2 扩展
# Ubuntu/Debian sudo apt-get install php-ssh2 # CentOS/RHEL sudo yum install php-devel php-pear libssh2 libssh2-devel sudo pecl install ssh2 # 启用扩展 echo "extension=ssh2.so" | sudo tee /etc/php/7.4/mods-available/ssh2.ini
基础使用示例
<?php
class SSHManager {
private $connection;
private $host;
private $port;
public function __construct($host, $port = 22) {
$this->host = $host;
$this->port = $port;
}
public function connect($username, $password) {
$this->connection = ssh2_connect($this->host, $this->port);
if (!$this->connection) {
throw new Exception("无法连接到服务器");
}
if (!ssh2_auth_password($this->connection, $username, $password)) {
throw new Exception("认证失败");
}
return true;
}
public function executeCommand($command) {
if (!$this->connection) {
throw new Exception("未建立连接");
}
$stream = ssh2_exec($this->connection, $command);
if (!$stream) {
throw new Exception("命令执行失败");
}
stream_set_blocking($stream, true);
$output = stream_get_contents($stream);
fclose($stream);
return $output;
}
public function disconnect() {
if ($this->connection) {
ssh2_disconnect($this->connection);
$this->connection = null;
}
}
}
// 使用示例
try {
$ssh = new SSHManager('192.168.1.100', 22);
$ssh->connect('root', 'password');
// 执行单个命令
$result = $ssh->executeCommand('ls -la');
echo "命令输出:\n" . $result;
// 执行多个命令
$commands = [
'pwd',
'whoami',
'df -h',
'free -m'
];
foreach ($commands as $cmd) {
echo "执行: $cmd\n";
echo $ssh->executeCommand($cmd) . "\n";
}
$ssh->disconnect();
} catch (Exception $e) {
echo "错误: " . $e->getMessage();
}
?>
使用密钥认证
生成SSH密钥对
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_php ssh-copy-id -i ~/.ssh/id_rsa_php.pub user@remote_server
PHP代码实现
<?php
class SSHKeyAuth extends SSHManager {
private $publicKeyFile;
private $privateKeyFile;
private $passphrase;
public function __construct($host, $port = 22) {
parent::__construct($host, $port);
}
public function setKeyFiles($publicKey, $privateKey, $passphrase = null) {
$this->publicKeyFile = $publicKey;
$this->privateKeyFile = $privateKey;
$this->passphrase = $passphrase;
}
public function connectWithKey($username) {
$this->connection = ssh2_connect($this->host, $this->port);
if (!ssh2_auth_pubkey_file(
$this->connection,
$username,
$this->publicKeyFile,
$this->privateKeyFile,
$this->passphrase
)) {
throw new Exception("密钥认证失败");
}
return true;
}
}
// 使用示例
try {
$ssh = new SSHKeyAuth('192.168.1.100');
$ssh->setKeyFiles(
'/home/user/.ssh/id_rsa_php.pub',
'/home/user/.ssh/id_rsa_php',
'your_passphrase' // 可选,如果密钥没有密码可以设为null
);
$ssh->connectWithKey('remote_user');
// 执行命令
$result = $ssh->executeCommand('uptime');
echo "服务器运行时间:\n" . $result;
$ssh->disconnect();
} catch (Exception $e) {
echo "错误: " . $e->getMessage();
}
?>
使用 phpseclib 库(纯PHP实现)
安装 phpseclib
composer require phpseclib/phpseclib
使用示例
<?php
require 'vendor/autoload.php';
use phpseclib3\Net\SSH2;
class PHPSSHManager {
private $ssh;
public function __construct($host, $port = 22) {
$this->ssh = new SSH2($host, $port);
}
public function connect($username, $password = null, $key = null) {
if ($key) {
// 密钥认证
$auth = $this->ssh->login($username, $key);
} elseif ($password) {
// 密码认证
$auth = $this->ssh->login($username, $password);
} else {
throw new Exception("请提供密码或密钥");
}
if (!$auth) {
throw new Exception("登录失败");
}
return true;
}
public function executeCommand($command) {
return $this->ssh->exec($command);
}
public function executeInteractiveCommand($command, $callback = null) {
if ($callback) {
$this->ssh->exec($command, $callback);
} else {
return $this->ssh->exec($command);
}
}
public function getLastError() {
return $this->ssh->getLastError();
}
public function disconnect() {
$this->ssh->disconnect();
}
}
// 密码认证示例
$ssh = new PHPSSHManager('192.168.1.100');
$ssh->connect('root', 'password');
echo $ssh->executeCommand('ls -la');
// 密钥认证示例
$key = \phpseclib3\Crypt\PublicKeyLoader::load(
file_get_contents('/home/user/.ssh/id_rsa'),
'your_passphrase' // 如果密钥有密码
);
$ssh2 = new PHPSSHManager('192.168.1.100');
$ssh2->connect('remote_user', null, $key);
echo $ssh2->executeCommand('whoami');
// 交互式命令执行
$ssh3 = new PHPSSHManager('192.168.1.100');
$ssh3->connect('root', 'password');
$output = $ssh3->executeInteractiveCommand('tail -f /var/log/syslog', function($data) {
echo $data;
});
?>
最佳实践 - 完整的SSH管理类
<?php
require 'vendor/autoload.php';
use phpseclib3\Net\SSH2;
use phpseclib3\Crypt\RSA;
class SecureSSHManager {
private $ssh;
private $connected = false;
private $error = null;
private $timeout = 30;
public function __construct($host, $port = 22, $timeout = 30) {
$this->ssh = new SSH2($host, $port);
$this->ssh->setTimeout($timeout);
}
public function connectWithPassword($username, $password) {
try {
if (!$this->ssh->login($username, $password)) {
throw new Exception("密码认证失败");
}
$this->connected = true;
return true;
} catch (Exception $e) {
$this->error = $e->getMessage();
return false;
}
}
public function connectWithKey($username, $privateKeyPath, $passphrase = null) {
try {
$key = RSA::load(file_get_contents($privateKeyPath));
if ($passphrase) {
$key = $key->withPassword($passphrase);
}
if (!$this->ssh->login($username, $key)) {
throw new Exception("密钥认证失败");
}
$this->connected = true;
return true;
} catch (Exception $e) {
$this->error = $e->getMessage();
return false;
}
}
public function execute($command) {
if (!$this->connected) {
$this->error = "未连接到服务器";
return false;
}
$output = $this->ssh->exec($command);
if ($output === false) {
$this->error = "命令执行失败";
return false;
}
return $output;
}
public function executeCommands(array $commands, $separator = ' && ') {
return $this->execute(implode($separator, $commands));
}
public function uploadFile($localFile, $remoteFile) {
try {
return $this->ssh->put($remoteFile, $localFile, SSH2::SOURCE_LOCAL_FILE);
} catch (Exception $e) {
$this->error = $e->getMessage();
return false;
}
}
public function downloadFile($remoteFile, $localFile) {
try {
return $this->ssh->get($remoteFile, $localFile);
} catch (Exception $e) {
$this->error = $e->getMessage();
return false;
}
}
public function getError() {
return $this->error;
}
public function isConnected() {
return $this->connected;
}
public function disconnect() {
if ($this->connected) {
$this->ssh->disconnect();
$this->connected = false;
}
}
public function __destruct() {
$this->disconnect();
}
}
// 完整使用示例
$ssh = new SecureSSHManager('192.168.1.100', 22);
// 连接方式1:密码认证
if ($ssh->connectWithPassword('root', 'your_password')) {
echo "连接成功\n";
// 执行单个命令
$result = $ssh->execute('ls -la /var/www');
echo $result;
// 执行多个命令
$commands = [
'cd /var/www',
'git pull origin master',
'composer install',
'php artisan migrate'
];
$result = $ssh->executeCommands($commands);
echo $result;
// 上传文件
$ssh->uploadFile('/local/file.txt', '/remote/file.txt');
// 下载文件
$ssh->downloadFile('/remote/backup.sql', '/local/backup.sql');
$ssh->disconnect();
} elseif ($ssh->connectWithKey('webuser', '/home/user/.ssh/id_rsa', 'passphrase')) {
// 连接方式2:密钥认证
echo "密钥认证连接成功\n";
// ... 执行命令
} else {
echo "连接失败: " . $ssh->getError();
}
?>
安全性建议
配置示例
<?php
// 安全配置
$config = [
'host' => '192.168.1.100',
'port' => 22,
'username' => 'webapp',
'key_file' => '/etc/ssh/keys/webapp_rsa',
'known_hosts' => '/etc/ssh/ssh_known_hosts',
'timeout' => 30,
'allowed_commands' => [
'deploy' => 'cd /var/www && git pull && composer install',
'backup' => 'mysqldump -u root mydb > /backup/db.sql',
'status' => 'systemctl status nginx',
]
];
// 使用白名单命令执行
class SafeSSHExecutor {
private $config;
private $ssh;
public function __construct($config) {
$this->config = $config;
}
public function executeAllowedCommand($commandName) {
if (!isset($this->config['allowed_commands'][$commandName])) {
throw new Exception("不允许的命令: $commandName");
}
$command = $this->config['allowed_commands'][$commandName];
return $this->executeWithTimeout($command);
}
private function executeWithTimeout($command) {
// 设置命令执行超时
$timeout = $this->config['timeout'];
// ... 执行命令
}
}
?>
日志记录
<?php
class LoggingSSHManager extends SecureSSHManager {
private $logFile;
public function __construct($host, $port = 22, $logFile = '/var/log/ssh_commands.log') {
parent::__construct($host, $port);
$this->logFile = $logFile;
}
public function execute($command) {
$result = parent::execute($command);
// 记录日志
$logEntry = sprintf(
"[%s] User: %s | Command: %s | Result length: %d\n",
date('Y-m-d H:i:s'),
$this->getCurrentUser(),
$command,
strlen($result ?? '')
);
file_put_contents($this->logFile, $logEntry, FILE_APPEND);
return $result;
}
}
?>
注意事项
- 安全第一:不建议直接在代码中硬编码密码,使用密钥认证更安全
- 错误处理:始终包含适当的异常处理
- 命令注入:对用户输入进行严格过滤
- 超时设置:避免长时间等待
- 日志记录:记录所有执行的命令用于审计
- 最小权限:使用最低权限的SSH用户
- 连接池:频繁操作时考虑复用连接
选择合适的方案取决于你的具体需求、服务器配置和安全要求,phpseclib 是最兼容的方案,因为它不需要安装额外的扩展。