laravel+ Linux 修改ssh连接终端的展示信息代码示例记录 
                                                    
                        
                    
                    
  
                    
                    使用场景
对Linux设备进行集中管理的时候,标明平台信息,防止多个部署的管理平台操作到同一个设备,用此信息表明设备的所属
思路
ssh到服务器,判断设备是否有含有本平台的信息,从而判断此设备能否使用,如果含有信息或者文件为空,均为无人认领机器,可以对其操作
如果不含本平台信息则不允许对其操作.
实现原理
追加修改linux设备的 /etc/profile 文件,来展示需要显示的内容
拓展
可以搭配 chattr 等指令 来保护文件不被修改、删除
环境
- laravel8.5
- php8.0
- 拓展包 :查看代码引用
实操服务代码
autotest_supervise_example:
*************************************************************
*                     请您立即退出本服务器 *
*                                                           *
*  本服务器受自动化测试程序监管,所有操作将被监控和记录。 *
*  未经授权的访问和更改是被禁止的,自动化结果可能变化。 *
*  请遵守相关规定,感谢您的合作。 *
*  如有疑问,请联系系统管理员:test@test.com         *
*************************************************************服务代码:
use Exception;
use File;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Storage;
use phpseclib3\Crypt\PublicKeyLoader;
use phpseclib3\Net\SFTP;
use phpseclib3\Net\SSH2;
    public function addSupervise($box)
    {
        if(env('DEBUG')){
            return [
                'status' => TRUE,
                'message' => "监管已成功移除。"
  ];
        }
        $userName = $box->ssh_name;
        $appUrl = env('APP_URL'); // 获取当前平台的 APP_URL  try {
            $this->insertTextArrayToFile( [
                " ",
                "自动化测试程序:        " . env('APP_NAME') ,
                "自动化测试程序地址:     " . env('APP_URL') ,
                "自动化测试程序版本:     " . env('VERSION') ,
            ]);
            // 创建 SSH 客户端实例
  $ssh = new SSH2($box['ssh_ip'], $box['ssh_port']);
            $key = Storage::get('id_rsa');
            // 使用 PublicKeyLoader 加载私钥
  $rsa = PublicKeyLoader::load($key);
            if (!$ssh->login($userName, $rsa)) {
                return [
                    'message' => "SSH 登录失败",
                    'code' => "-1",
                    'status' => FALSE
  ];
            }
            // 检查远程文件是否存在并读取内容
  $remoteFilePath = '/usr/local/disk/autotest_supervise';
            $checkCommand = "if [ -f {$remoteFilePath} ]; then cat {$remoteFilePath}; else echo 'FILE_NOT_EXIST'; fi";
            $remoteContent = $ssh->exec($checkCommand);
            if (trim($remoteContent) === 'FILE_NOT_EXIST') {
                // 文件不存在,可以继续添加监管
  } else {
                // 文件存在,检查是否包含当前平台的 APP_URL  if (strpos($remoteContent, $appUrl) === FALSE) {
                    return [
                        'message' => "此设备已经被其他平台添加至监管,请前往其他平台解除监管后添加",
                        'code' => "-4",
                        'status' => FALSE
  ];
                }
                // 如果包含当前 APP_URL,可以选择覆盖或追加,根据需求调整
  }
            // 创建 SFTP 实例进行文件上传
  $sftp = new SFTP($box['ssh_ip'], $box['ssh_port']);
            if (!$sftp->login($userName, $rsa)) {
                return [
                    'message' => "SFTP 登录失败",
                    'code' => "-1",
                    'status' => FALSE
  ];
            }
            // 本地文件路径
  $localFilePath = Storage::path('public/autotest_supervise');
            // 远程服务器上的文件路径
  $remoteFilePath = '/usr/local/disk/autotest_supervise';
            // 将文件上传到远程服务器
  if (!$sftp->put($remoteFilePath, $localFilePath, SFTP::SOURCE_LOCAL_FILE)) {
                return [
                    'message' => "SFTP 传输失败, 需要确认权限及 /usr/local/disk 存在",
                    'code' => "-2",
                    'status' => FALSE
  ];
            }
            $sftp->disconnect();
            // 追加内容到 /etc/profile  if ($userName == 'root') {
                $command = 'sudo sh -c \'cat >> /etc/profile << "EOF"
if [ -f /usr/local/disk/autotest_supervise ]; then
 cat /usr/local/disk/autotest_supervisefi
EOF\'';
                $ssh->exec(str_replace("\r\n", "\n", $command));
            } else {
                // 切换到 sudo 用户并执行命令
  $ssh->write("sudo su\n");
                $ssh->read('密码:');
                $ssh->write("nle\n"); // 这里假设密码为 'nle', 请根据实际情况修改
  $ssh->setTimeout(1);
                $ssh->read();
                $ssh->write('[ "$(stat -c "%U:%G" /usr/local/disk)" != "nle:nle" ] && sudo chown -R nle:nle /usr/local/disk' . "\n");
                $ssh->setTimeout(2);
                $ssh->read();
                $ssh->setTimeout(1);
                $command = 'sudo sh -c \'cat >> /etc/profile << "EOF"
if [ -f /usr/local/disk/autotest_supervise ]; then
 cat /usr/local/disk/autotest_supervisefi
EOF\'' . "\n";
                $ssh->write(str_replace("\r\n", "\n", $command));
                $ssh->read();
            }
            // 关闭 SSH 连接
  $ssh->disconnect();
            return [
                'status' => TRUE
  ];
        } catch (Exception $e) {
            return [
                'status' => FALSE,
                'line' => $e->getLine(),
                'message' => $e->getMessage(),
            ];
        }
    }
    public function insertTextArrayToFile(array $textArray)
    {
        // 1. 读取文件内容
  $content = Storage::get('public/autotest_supervise_example');
        // 2. 统一换行符为 \n,避免因换行符不同导致的问题
  $content = str_replace(["\r\n", "\r"], "\n", $content);
        // 3. 拆分为行数组
  $lines = explode("\n", $content);
        // 4. 找到底部边框行的位置
  $borderLine = str_repeat('*', 61);
        $bottomBorderIndex = null;
        foreach (array_reverse($lines, true) as $index => $lineContent) {
            if (trim($lineContent) === $borderLine) {
                $bottomBorderIndex = $index;
                break;
            }
        }
        if ($bottomBorderIndex === null) {
            // 未找到底部边框,抛出异常或根据需要处理
  throw new Exception('底部边框行未找到,无法插入文本。');
        }
        // 5. 定义颜色代码
  $colors = [
            'red' => "\033[31m",    // 红色
  'reset' => "\033[0m",   // 重置颜色
  ];
        // 6. 准备要插入的行数组,并添加颜色
  $insertLines = [];
        foreach ($textArray as $key => $text) {
            // 检查是否是需要着色的行,这里假设第一行需要红色
  if ($key === 0|| $key === 1||$key === 2||$key === 3) {
                $colorStart = $colors['red'];
                $colorEnd = $colors['reset'];
            } else {
                $colorStart = '';
                $colorEnd = '';
            }
            // 生成新行内容,确保总可见宽度为59个字符(61 - 2个 '*')
  $lineContent = " {$text}"; // 两个空格开头
  $visibleWidth = mb_strwidth($lineContent, 'UTF-8');
            // 计算需要填充的空格数量
  $paddingLength = 59 - $visibleWidth;
            $padding = str_repeat(' ', max(0, $paddingLength));
            // 填充空格后,确保总可见宽度一致
  $lineContentPadded = $lineContent . $padding;
            // 应用颜色转义码,仅包裹内容部分,不包括填充
  $coloredLineContent = $colorStart . $lineContent . $colorEnd . $padding;
            // 构建完整的行,以 '*' 开始和结束
  $line = "*" . $coloredLineContent . "*";
            $insertLines[] = $line;
        }
        // 7. 在底部边框行之前插入新行数组
  array_splice($lines, $bottomBorderIndex, 0, $insertLines);
        // 8. 重组内容并写回文件
  $newContent = implode("\n", $lines);
        Storage::put('public/autotest_supervise', $newContent);
    }
    public function destroySupervise($box)
    {
        if(env('DEBUG')){
            return [
                'status' => TRUE,
                'message' => "监管已成功移除。"
  ];
        }
        $userName = $box->ssh_name;
        $appUrl = env('APP_URL'); // 获取当前平台的 APP_URL
  try {
            // 创建 SSH 客户端实例
  $ssh = new SSH2($box['ssh_ip'], $box['ssh_port']);
            $key = Storage::get('id_rsa');
            // 使用 PublicKeyLoader 加载私钥
  $rsa = PublicKeyLoader::load($key);
            if (!$ssh->login($userName, $rsa)) {
                return [
                    'message' => "SSH 登录失败",
                    'code' => "-1",
                    'status' => FALSE
  ];
            }
            // 检查远程文件是否存在并读取内容
  $remoteFilePath = '/usr/local/disk/autotest_supervise';
            $checkCommand = "if [ -f {$remoteFilePath} ]; then cat {$remoteFilePath}; else echo 'FILE_NOT_EXIST'; fi";
            $remoteContent = $ssh->exec($checkCommand);
            $remoteContent = trim($remoteContent);
            if ($remoteContent === 'FILE_NOT_EXIST') {
                // 文件不存在,说明没有添加过监管,可以返回成功或提示无监管
  return [
                    'message' => "该设备未被监管或已被移除。",
                    'code' => "0",
                    'status' => TRUE
  ];
            } else {
                // 文件存在,检查内容是否为空或包含当前平台的 APP_URL  if ($remoteContent !== '' && strpos($remoteContent, $appUrl) === FALSE) {
                    return [
                        'message' => "此设备已经被其他平台添加至监管,请前往其他平台解除监管后再进行操作。",
                        'code' => "-4",
                        'status' => FALSE
  ];
                }
                // 如果内容为空或包含当前 APP_URL,可以继续执行移除操作
  }
            // 创建 SFTP 实例进行文件删除
  $sftp = new SFTP($box['ssh_ip'], $box['ssh_port']);
            if (!$sftp->login($userName, $rsa)) {
                return [
                    'message' => "SFTP 登录失败",
                    'code' => "-1",
                    'status' => FALSE
  ];
            }
            // 删除远程 supervise 文件
  if (!$sftp->delete($remoteFilePath)) {
                return [
                    'message' => "SFTP 删除文件失败,需要确认权限及文件存在",
                    'code' => "-2",
                    'status' => FALSE
  ];
            }
            $sftp->disconnect();
            // 移除 /etc/profile 中的相关内容
  if ($userName == 'root') {
                $command = 'sudo sed -i \'/^if \[ -f \/usr\/local\/disk\/autotest_supervise \]; then$/,/^fi$/d\' /etc/profile';
                $ssh->exec($command);
            } else {
                // 切换到 sudo 用户并执行命令
  $ssh->write("sudo su\n");
                $ssh->read('密码:');
                $ssh->write("nle\n"); // 请根据实际情况修改密码
  $ssh->setTimeout(2);
                $ssh->read();
                $command = 'sudo sed -i \'/^if \[ -f \/usr\/local\/disk\/autotest_supervise \]; then$/,/^fi$/d\' /etc/profile' . "\n";
                $ssh->write($command);
                $ssh->read();
            }
            // 关闭 SSH 连接
  $ssh->disconnect();
            return [
                'status' => TRUE,
                'message' => "监管已成功移除。"
  ];
        } catch (Exception $e) {
            return [
                'status' => FALSE,
                'line' => $e->getLine(),
                'message' => $e->getMessage(),
            ];
        }
    }

本作品采用《CC 协议》,转载必须注明作者和本文链接
 
           chowjiawei 的个人博客
 chowjiawei 的个人博客
         
             
             
             
                     
                     
           
           关于 LearnKu
                关于 LearnKu
               
                     
                     
                     粤公网安备 44030502004330号
 粤公网安备 44030502004330号 
 
推荐文章: