标题:【PHP小课堂】一起学习PHP中SSH相关扩展的使用

文章目录
    分类:PHP 标签:PHP基础

    一起学习PHP中SSH相关扩展的使用

    对于 PHP 来说,很少有用它来做运维相关管理系统的,不过,这并不代表我们 PHP 就不能远程管理服务器了。其实,也是有直接进行远程操作相关的扩展工具供我们使用的,就像我们今天要学习的这个 SSH 扩展。扩展的安装就是正常的 PHP 安装,使用的是 ssh2 这个扩展包,具体的安装过程就不详细说了,直接来看如何使用吧。

    连接远程 SSH 服务器

    连接过程非常简单,建立连接,然后登录就可以了。

    $conn = ssh2_connect('192.168.56.106');
    var_dump(ssh2_auth_password($conn, 'root', '123456')); // bool(true)

    使用 ssh2_connect() 就可以建立连接并且获得连接句柄。这里我们是本地建立的一台虚拟机,所以直接就使用 root 而且密码也非常简单,大家操作线上服务器时可不能这么任性。而且如果真的需要操作线上真实环境的主机的话,更建议使用密钥的方式来连接,而不是像我们这样直接用户名密码的方式。关于密钥方式也有很多函数可以供大家使用,大家可以自行了解一下。

    执行远程命令

    连接服务器成功后,最主要的就是能够执行各种操作命令,这个也是我们要使用 ssh2 这个扩展的核心。当然,目的也是为了要进行远程服务器的操控管理。我们有两种执行命令的方式。

    单条语句执行

    $stream = ssh2_exec($conn, "ls -l /");
    
    $dio_stream = ssh2_fetch_stream($stream, SSH2_STREAM_STDIO);
    $err_stream = ssh2_fetch_stream($stream, SSH2_STREAM_STDERR);
    
    stream_set_blocking($dio_stream, true);
    stream_set_blocking($err_stream, true);
    
    echo stream_get_contents($dio_stream);
    echo  stream_get_contents($err_stream);
    
    // total 152
    // drwxrwx---    1 root vboxsf 131072 Dec 31  1979 adata_hd330
    // lrwxrwxrwx.   1 root root        7 May 10  2019 bin -> usr/bin
    // dr-xr-xr-x.   6 root root     4096 Jan 29 01:54 boot
    // drwxr-xr-x   20 root root     3080 Mar  4 19:42 dev
    // drwxr-xr-x. 103 root root     8192 Mar  4 19:42 etc
    // drwxr-xr-x.   3 root root       23 Mar  4 20:33 home
    // lrwxrwxrwx.   1 root root        7 May 10  2019 lib -> usr/lib
    // lrwxrwxrwx.   1 root root        9 May 10  2019 lib64 -> usr/lib64
    // drwxr-xr-x.   3 root root       19 Jan 29 01:40 media
    // drwxr-xr-x.   2 root root        6 May 10  2019 mnt
    // drwxr-xr-x.   3 root root       39 Jan 29 02:07 opt
    // dr-xr-xr-x  118 root root        0 Mar  4 19:42 proc
    // dr-xr-x---.  15 root root     4096 Feb 25 04:58 root
    // drwxr-xr-x   32 root root      940 Mar  4 19:43 run
    // lrwxrwxrwx.   1 root root        8 May 10  2019 sbin -> usr/sbin
    // drwxr-xr-x.   2 root root        6 May 10  2019 srv
    // dr-xr-xr-x   13 root root        0 Mar  4 19:41 sys
    // drwxrwxrwt.   5 root root      118 Mar  4 20:36 tmp
    // drwxr-xr-x.  12 root root      144 Mar 16  2020 usr
    // drwxr-xr-x.  21 root root     4096 Mar 16  2020 var
    
    fclose($stream);

    对于单独的一条语句来说,我们可以使用 ssh2_exec() 这个函数来直接执行这条命令。它返回的结果是一个流,所以我们需要通过流的方式来读取返回的内容。在这里,我们就是简单地查看一下根目录下的内容。这块的操作非常简单,不过需要注意的是,如果返回的内容非常多的话,就不要使用 stream_get_contents() 了,它的返回大小是有限制的,我们可以使用 fgets() 这类的文件流相关函数来遍历读取。具体内容大家可以查阅官方文档,其中有不少 Notes 都会讲到这个问题。

    多条语句批量执行

    有时候,我们想一次执行多条命令,这时就可以使用另外一种方式来进行操作。

    $shell = ssh2_shell($conn, 'xterm');
    fwrite($shell, "mkdir /home/shelltest/;".PHP_EOL);
    fwrite($shell, "cd /home;".PHP_EOL);
    fwrite($shell, "ls -l /home;". PHP_EOL);
    sleep(1);
    
    echo stream_get_contents($shell);
    // Activate the web console with: systemctl enable --now cockpit.socket
    
    // Last login: Thu Mar  4 20:36:36 2021 from 192.168.56.102
    // mkdir /home/shelltest/;
    // cd /home;
    // ls -l /home;
    // [root@localhost ~]# mkdir /home/shelltest/;
    // [root@localhost ~]# cd /home;
    // [root@localhost home]# ls -l /home;
    // total 0
    // drwxr-xr-x 2 root root 20 Mar  4 20:36 shelltest
    
    fclose($shell);

    使用 ssh2_shell() 可以看作是打开了一个可以写入的流句柄,然后我们使用 fwrite() 向这个流中写入命令。在这里为什么要 sleep() 一下呢?其实这个流的写入操作并不是同步的,所以如果不加一个暂停的话,可能 PHP 就直接执行过去了,而命令并没有正常地发送完成就中断了。这个是需要注意的地方。同样,我们可以使用 stream_get_contents() 或者其它读取流的方式来获得执行的结果。


    在这段代码中,我们建立了一个目录,然后进入它的上级 home 目录中,最后返回目录里面的内容信息。从打印的结果还能够看出,它会输出整个登录后的信息,就像我们真的打开了一个 ssh shell 工具一样。

    文件传输

    除了命令的操控之外,SSH 中另外一个非常重要的能力就是可以实现 sftp 以及 scp 之类的文件传输的功能,这些功能在 ssh2 扩展中也是支持的。

    sftp 上传下载

    $sftp = ssh2_sftp($conn);
    ssh2_sftp_mkdir($sftp, '/tmp/test/');
    copy('./1.txt', "ssh2.sftp://{$sftp}/tmp/test/11.txt");
    
    $stream = ssh2_exec($conn, "ls -l /tmp/test/");
    
    $dio_stream = ssh2_fetch_stream($stream, SSH2_STREAM_STDIO);
    $err_stream = ssh2_fetch_stream($stream, SSH2_STREAM_STDERR);
    
    stream_set_blocking($dio_stream, true);
    stream_set_blocking($err_stream, true);
    
    echo stream_get_contents($dio_stream);
    echo  stream_get_contents($err_stream);
    
    // total 1
    // -rw-r--r-- 1 root root 73 Mar  4 20:37 11.txt
    
    fclose($stream);
    
    echo file_get_contents("ssh2.sftp://{$sftp}/tmp/test/11.txt"); // 123123123123123123123123123123123123123123123123123123123123123123123123

    首先,我们使用 ssh2_sftp() 函数获取一个 sftp 句柄。然后通过 ssh2_sftp_mkdir() 创建了一个目录。接着,通过普通的 PHP 函数配合 ssh2.sftp 这个伪协议,就可以像操作本地文件一样来操作远程的文件了。是不是非常高大上。


    中间的一段代码是通过 ssh2_exec() 去查看我们上传的文件,可以看到文件和目录都是正常存在的。最后,我们通过 file_get_contents() 并且配合伪协议来读取文件的内容,其实这就相当于从远程服务器下载文件了。


    之前的文章中我们已经简单地学习过一些伪协议相关的内容,所以这里也就不多解释了,但是不得不说,这种形式的操作真的非常方便和直观。不管是 copy() 还是 file_get_contents() 真的就和我们操作本地文件一样的感觉。


    当然,除了上面介绍的 ssh2_sftp() 和 ssh2_sftp_mkdir() 之外,扩展中还有 ssh2_sftp_chmod()、ssh2_sftp_rename()、ssh2_sftp_unlink() 等等的函数,相信从名字大家也能看出它们的作用,这里就不多做解释了,大家可以查阅文档获取相关的资料。

    scp 传输文件

    最后,我们再来看看更为简单的 scp 方式的文件传输。

    ssh2_scp_send($conn, './1.txt', '/home/shelltest/22.txt'); // /home/shelltest/22.txt
    ssh2_scp_recv($conn, '/home/shelltest/22.txt', './222.txt'); // ./222.txt

    虽说 scp 现在用得不多了(没 rsync 快),不过它的使用可真是方便。ssh2_scp_send() 用于发送一个本地文件到远程服务器,ssh2_scp_recv() 用于从远程服务器拉取一个文件,是不是有点简单的过头了。就跟我们平常使用的 copy() 之类的函数一样的感觉。

    总结

    今天我们简单的了解了一下 ssh2 这个扩展的一些简单操作,核心的东西也就是这些了。在官方文档中还有很多其它的函数不过都是和密钥登录相关的内容,在这里也就不多赘述了,有需要的小伙伴自己查阅一下就可以,而且他们的使用都并不复杂。剩下的就是 sftp 和 scp 相关的内容了。总体来说,这个扩展还是比较方便好用的,如果只是简单的小型的运维管理功能,是完全可以满足的,当然,具体业务具体分析,使用什么还是大家自己定夺。


    测试代码:


    https://github.com/zhangyue0503/dev-blog/blob/master/php/2021/03/source/3.%E4%B8%80%E8%B5%B7%E5%AD%A6%E4%B9%A0PHP%E4%B8%ADSSH%E7%9B%B8%E5%85%B3%E6%89%A9%E5%B1%95%E7%9A%84%E4%BD%BF%E7%94%A8.php


    参考文档:


    https://www.php.net/manual/zh/book.ssh2.php

    视频链接

    微信文章地址:https://mp.weixin.qq.com/s/kTdph8t7PTt1iuUIIZSrqg

    搜索
    关注