PHP项目SSH远程管理如何PHP调用执行命令

wen PHP项目 27

本文目录导读:

PHP项目SSH远程管理如何PHP调用执行命令

  1. 使用 PHP SSH2 扩展(推荐)
  2. 使用密钥认证
  3. 使用 phpseclib 库(纯PHP实现)
  4. 最佳实践 - 完整的SSH管理类
  5. 安全性建议
  6. 日志记录
  7. 注意事项

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

注意事项

  1. 安全第一:不建议直接在代码中硬编码密码,使用密钥认证更安全
  2. 错误处理:始终包含适当的异常处理
  3. 命令注入:对用户输入进行严格过滤
  4. 超时设置:避免长时间等待
  5. 日志记录:记录所有执行的命令用于审计
  6. 最小权限:使用最低权限的SSH用户
  7. 连接池:频繁操作时考虑复用连接

选择合适的方案取决于你的具体需求、服务器配置和安全要求,phpseclib 是最兼容的方案,因为它不需要安装额外的扩展。

抱歉,评论功能暂时关闭!