You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP中使用密钥对实现SFTP身份验证的问题(Laravel环境)

Laravel中使用phpseclib 3.x实现SFTP密钥认证及文件操作

phpseclib 3.x的命名空间和API与旧版本差异较大,以下是适配3.x版本的完整实现代码,支持密钥对认证、列目录、上传/下载文件等核心功能:

1. 核心服务类实现

创建App\Services\SftpService.php,封装SFTP操作:

<?php

namespace App\Services;

use phpseclib3\Net\SFTP;
use phpseclib3\Crypt\PublicKeyLoader;
use RuntimeException;

class SftpService
{
    protected SFTP $sftp;

    /**
     * 建立SFTP连接并完成密钥认证
     * @param string $host SFTP服务器地址
     * @param int $port 端口,默认22
     * @param string $username 用户名
     * @param string $privateKeyPath 本地私钥文件路径
     * @param string|null $privateKeyPassword 私钥密码(无密码则传null)
     * @return bool 认证成功返回true,失败返回false
     */
    public function connect(string $host, int $port = 22, string $username, string $privateKeyPath, ?string $privateKeyPassword = null): bool
    {
        $this->sftp = new SFTP($host, $port);

        // 加载私钥(支持OpenSSH格式,FileZilla使用的密钥无需转换)
        try {
            $privateKey = PublicKeyLoader::load(file_get_contents($privateKeyPath), $privateKeyPassword);
        } catch (\Exception $e) {
            error_log('加载私钥失败: ' . $e->getMessage());
            return false;
        }

        // 执行密钥认证
        if (!$this->sftp->login($username, $privateKey)) {
            error_log('SFTP认证失败: ' . $this->sftp->getLastError());
            return false;
        }

        return true;
    }

    /**
     * 列出指定目录内容
     * @param string $path 目录路径,默认当前目录
     * @return array 目录文件列表,rawlist()可返回包含权限、大小等的详细信息
     */
    public function listDirectory(string $path = '.'): array
    {
        $this->checkConnection();
        return $this->sftp->nlist($path);
        // 如需详细信息,替换为:return $this->sftp->rawlist($path);
    }

    /**
     * 上传本地文件到SFTP服务器
     * @param string $localPath 本地文件路径
     * @param string $remotePath 服务器目标路径
     * @return bool 上传成功返回true
     */
    public function uploadFile(string $localPath, string $remotePath): bool
    {
        $this->checkConnection();
        return $this->sftp->put($remotePath, $localPath, SFTP::SOURCE_LOCAL_FILE);
    }

    /**
     * 从SFTP服务器下载文件到本地
     * @param string $remotePath 服务器文件路径
     * @param string $localPath 本地目标路径
     * @return bool 下载成功返回true
     */
    public function downloadFile(string $remotePath, string $localPath): bool
    {
        $this->checkConnection();
        return $this->sftp->get($remotePath, $localPath, SFTP::SOURCE_LOCAL_FILE);
    }

    /**
     * 断开SFTP连接
     */
    public function disconnect(): void
    {
        if ($this->sftp->isConnected()) {
            $this->sftp->disconnect();
        }
    }

    /**
     * 检查连接状态,未连接则抛出异常
     */
    private function checkConnection(): void
    {
        if (!$this->sftp->isConnected()) {
            throw new RuntimeException('未建立SFTP连接');
        }
    }
}

2. 使用示例(控制器中调用)

<?php

namespace App\Http\Controllers;

use App\Services\SftpService;

class SftpController extends Controller
{
    public function testSftpOperations()
    {
        $sftpService = new SftpService();

        // 从.env读取配置(建议将配置存入.env,避免硬编码)
        $config = [
            'host' => env('SFTP_HOST'),
            'port' => env('SFTP_PORT', 22),
            'username' => env('SFTP_USERNAME'),
            'private_key_path' => storage_path('app/sftp/id_rsa'), // 私钥存放路径示例
            'private_key_password' => env('SFTP_KEY_PASSWORD', null)
        ];

        // 连接认证
        if (!$sftpService->connect(...array_values($config))) {
            return response()->json(['status' => 'error', 'msg' => 'SFTP连接失败'], 500);
        }

        // 1. 列出服务器根目录内容
        $dirList = $sftpService->listDirectory('/');
        dump('目录内容:', $dirList);

        // 2. 上传本地文件示例
        // $uploadSuccess = $sftpService->uploadFile(storage_path('app/test_upload.txt'), '/remote/test_upload.txt');
        // dump('上传状态:', $uploadSuccess);

        // 3. 下载服务器文件示例
        // $downloadSuccess = $sftpService->downloadFile('/remote/test_download.txt', storage_path('app/test_download.txt'));
        // dump('下载状态:', $downloadSuccess);

        // 断开连接
        $sftpService->disconnect();

        return response()->json(['status' => 'success']);
    }
}

3. 关键注意事项

  • 命名空间适配:phpseclib 3.x使用phpseclib3\前缀命名空间,旧版的phpseclib\命名空间已废弃,这是旧代码失效的核心原因。
  • 密钥权限:确保Laravel运行用户(如www-data)能读取私钥文件,密钥文件权限建议设为600,存放目录设为700,避免因权限过高被SFTP服务器拒绝。
  • 调试技巧:连接失败时,可通过$this->sftp->getLastError()获取具体错误信息,排查认证问题。
  • 配置管理:将SFTP配置(主机、用户名、密钥路径等)存入.env文件,通过Laravel的config()或env()函数读取,避免代码硬编码敏感信息。

内容的提问来源于stack exchange,提问作者Datadimension

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 10:42:05