今天在尝试使用 ssh2 扩展来执行远程上传文件的时候,一直遇到这个错误,Google 了很久,连这个 -28 的错误码都没有搜到,结果自己误打误撞解决了...

示例代码:

class RemoteCommandHandler
{
    private $serverIP, $serverUser, $serverSshPort;

    private $sshConnectSession;

    public function __construct()
    {
        $this->serverIP = 'x.x.x.x';
        $this->serverUser = 'root';
        $this->serverSshPort = '22';
        $rsaPublicKey = '公钥文件路径';
        $rsaPrivateKey = '私钥文件路径';

        $this->sshConnectSession = ssh2_connect($this->serverIP, $this->serverSshPort, ['hostkey'=>'ssh-rsa']);
        if (!$this->sshConnectSession) {
            logger()->error(__METHOD__. ' '.__LINE__. ' ssh2 连接失败');
            throw new RemoteCommandException('服务器连接失败');
        }
        if (!ssh2_auth_pubkey_file($this->sshConnectSession, 'root', $rsaPublicKey, $rsaPrivateKey)) {
            logger()->error(__METHOD__. ' '.__LINE__. ' ssh2 rsa key 验证失败');
            throw new RemoteCommandException('服务器验证失败');
        }
        logger()->info('ssh2 连接成功');
    }

    public function run($command)
    {
        $execStream = ssh2_exec($this->sshConnectSession, $command);
        $stream = ssh2_fetch_stream($execStream, SSH2_STREAM_STDIO);
        stream_set_blocking($stream, true);
        return stream_get_contents($stream);
    }

    public function writeFile($localPath, $remotePath)
    {
        return ssh2_scp_send($this->sshConnectSession, $localPath, $remotePath, '0644');
    }
}

结果在执行 writeFile() 的时候,在 ssh2_scp_send() 会抛出异常:

ssh2_scp_send(): Failure creating remote file: failed to send file (-28)

折腾了快一个小时,确保了各种连接是无障碍的,在本机直接食用scp也是没有问题的。后来我偶然之间想道,mode 是使用八进制数字来控制管理权限的,然而我传入的是一个字符串...

所以我从

ssh2_scp_send($this->sshConnectSession, $localPath, $remotePath, '0644');

改成

ssh2_scp_send($this->sshConnectSession, $localPath, $remotePath, 0644);

就成功了...

同时我收获了一个道理,看文档一定要看仔细,其实 PHP 官方文档就可以解决问题了

# https://www.php.net/manual/zh/function.ssh2-scp-send.php 

ssh2_scp_send ( resource $session , string $local_file , string $remote_file [, int $create_mode = 0644 ] ) : bool

官方说明里已经标明了, $create_mode 是 int ....
蠢哭了 QAQ