PHP+Swoole實(shí)現(xiàn)web版的shell客戶端詳解
本來(lái)是想通過(guò)PHP的proc_open和進(jìn)程進(jìn)行交互,可是中間的坑太多了,不得不轉(zhuǎn)換一下思路,然后想起來(lái)寶塔有網(wǎng)頁(yè)版shell客戶端,然后研究了一下,嘿嘿,發(fā)現(xiàn)能成 。
一、前期準(zhǔn)備
PHP連接ssh是基于第三方拓展庫(kù),PECL/ssh2( libssh2的php擴(kuò)展,允許php程序調(diào)用libssh2中的函數(shù))
然后有一個(gè)現(xiàn)成的、封裝好大部分常用操作的庫(kù)phpseclib
通過(guò)swoole的協(xié)程實(shí)現(xiàn)SSH的讀和寫(xiě)并發(fā)進(jìn)行以及websocket和瀏覽器進(jìn)行通信。
1、安裝ssh2拓展庫(kù)
1.1、Linux安裝
首先要安裝libssh2(libssh2是一個(gè)C 函數(shù)庫(kù),用來(lái)實(shí)現(xiàn)SSH2協(xié)議。)
yum?install?libssh2?libssh2-devel?
然后通過(guò)pcel安裝ssh2拓展 ,找準(zhǔn)版本
pecl install ssh2-1.1.2
當(dāng)然也可以通過(guò)phpize進(jìn)行手動(dòng)安裝。
1.2、window安裝
libssh2好像一般都有,沒(méi)有就下載丟到系統(tǒng)里,主要是安裝ssh2。根據(jù)自己PHP的版本去下載,可以看下自己的php版本,以及是32位的還是64位的,32位的下載x86, 64位的下載x64
php.ini中加入 extension=php_ssh2.dll ,完事。
2、swoole安裝
參考官網(wǎng):https://wiki.swoole.com/#/environment
3、phpseclib
官網(wǎng):https://phpseclib.com,composer安裝即可:
composer?require?phpseclib/phpseclib:~3.0
二、編寫(xiě)代碼
測(cè)試Demo:http://cname.teiao.com:5707/
通過(guò)swoole創(chuàng)建一個(gè)websocket,連接成功時(shí)創(chuàng)建一個(gè)協(xié)程專門讀取ssh返回的內(nèi)容發(fā)送到websocket,客戶端發(fā)送消息時(shí)轉(zhuǎn)發(fā)給shell。
以下是簡(jiǎn)單的功能實(shí)現(xiàn),不可應(yīng)用于生產(chǎn),經(jīng)測(cè)試,實(shí)際使用過(guò)程中某些命令的輸出需要進(jìn)行特殊處理。
1、swoole.php
<?php
include_once 'include/functions.php';
include_once 'vendor/autoload.php';
use Swoole\Http\Request;
use Swoole\Http\Response;
use Swoole\WebSocket\CloseFrame;
use Swoole\Coroutine\Http\Server;
use Swoole\Coroutine;
use function Swoole\Coroutine\go;
use function Swoole\Coroutine\run;
use function Swoole\Coroutine\defer;
use phpseclib3\Net\SSH2;
/*
* 設(shè)置協(xié)程運(yùn)行相關(guān)的參數(shù)
* */
Co::set([
'socket_timeout'=>-1, //tcp超時(shí)
'hook_flags' => SWOOLE_HOOK_ALL //HOOK函數(shù)范圍
]);
/*
* 創(chuàng)建協(xié)程容器
* */
run(function () {
/*
* 第三個(gè)參數(shù) 代表是否開(kāi)啟ssl
* */
$server = new Server('0.0.0.0', 5707, false);
$server->handle('/ws', function (Request $request, Response $ws) {
/*websocket協(xié)議*/
$ws->upgrade();
/*連接ssh*/
$ssh = new SSH2('localhost',22);
/*如果登錄失敗*/
if (!$ssh->login('root', 'Qq461625091@')) {
$ws->close();
return;
}
/*命令輸出內(nèi)容的讀取時(shí)間*/
$ssh->setTimeout(0.1);
/*
* 創(chuàng)建協(xié)程,專門輸出命令行內(nèi)容
* */
$subscribe=function () use($ws,$ssh){
/*
* 保存id,用于取消協(xié)程
* */
$ws->Gid = go(function () use ($ws,$ssh){
/*
* 協(xié)程退出時(shí)清理
* */
defer(function () use ($ssh,$ws) {
/*
* 退出
* */
logs($ws->qq.',已斷開(kāi)鏈接!');
$ssh->disconnect();
});
try {
while (true){
$msg=$ssh->read('username@username:~$');
if(!empty($msg)){
$ws->push($msg);
}
}
} catch (\Throwable $e) {
logs('讀取異常');
}
});
};
/*
* 清理
* */
$quit=function ($log) use ($ws){
logs($log);//記錄退出原因
/*
* 如果協(xié)程已經(jīng)運(yùn)行
* */
if(isset($ws->Gid)){
Coroutine::cancel($ws->Gid); //關(guān)閉協(xié)程
}
$ws->close(); //斷開(kāi)ws
};
/*
* 正常處理邏輯
* */
$subscribe(); //開(kāi)始訂閱
$cmd=[
'ps -ef',
'ping 127.0.0.1',
'ifconfig',
"\x03"
];
while (true) {
$frame = $ws->recv(); //阻塞接收消息
if ($frame === '') {
$quit("斷開(kāi)連接,收到空數(shù)據(jù)!");
break;
} else if ($frame === false) {
$quit(swoole_last_error());
break;
} else {
if ($frame->data == 'close' || get_class($frame) === CloseFrame::class) {
$quit("用戶主動(dòng)關(guān)閉\n");
break;
}
/*
* 如果不在測(cè)試命令,則終止
* */
if(!in_array($frame->data,$cmd)){
continue;
}
$ssh->write($frame->data."\n"); // note the "\n"
}
}
});
/*
* 輸出默認(rèn)測(cè)試模板
* */
$server->handle('/', function (Request $request, Response $response) {
$response->end(getTest());
});
$server->start();
});2、function.php
<?php
/*
* 打印測(cè)試的html模板
* */
function getTest(): string
{
$test = <<<HTML
<!DOCTYPE html>
<html lang="zh-cn" xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="UTF-8"/>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>Web SSH客戶端</title>
<link rel="external nofollow" rel="shortcut icon" type="image/x-icon"/>
<script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.6.0/jquery.min.js" type="application/javascript"></script>
<script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/keyboardjs/2.6.2/keyboard.min.js" type="application/javascript"></script>
<style>
body{
background-color: #000000;
color: #e2e2e2;
padding: 15px;
}
input{
background-color: black;
border: none;
color: white;
outline: none;
font-size: 17px;
}
</style>
</head>
<body>
<h1>Web SSH測(cè)試</h1>
<div>須知:測(cè)試環(huán)境只支持:ps -ef、ping 127.0.0.1、ifconfig,三個(gè)命令。</div>
<div>提示:回車提交、ctrl+c中斷(終端現(xiàn)在連接的是網(wǎng)站的主機(jī))</div>
<br />
<main>
<span id="content"></span>
<input type="text">
</main>
</body>
<script>
window.onload=function (){
let content=$("#content");
let input= $('input');
let wsServer = 'ws://cname.teiao.com:5707/ws';
let websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) {
content.append("Connected to WebSocket server.<br />");
};
websocket.onclose = function (evt) {
content.append("Disconnected.<br />");
};
websocket.onmessage = function (evt) {
content.append(evt.data.replaceAll("\\n",'<br />'));
input.val("");
$(window).scrollTop(document.documentElement.scrollHeight)
};
websocket.onerror = function (evt, e) {
content.append("Error occured: " + evt.data+"<br />");
};
input.focus();
/*
* 自動(dòng)聚焦
* */
$(window).on("click",function (){
input.focus();
})
/*
* 回車提交
* */
keyboardJS.bind('enter', (e) => {
websocket.send(input.val());
});
/*
* ctrl+c
* */
keyboardJS.bind('ctrl > c', (e) => {
websocket.send("\x03");
});
}
</script>
HTML;
return $test;
}
/*
* 記錄日志
* */
function logs(string $log, bool $flag = true): void
{
$time = date("Y-m-d H:i:s", time());
if ($flag) {
echo $time . ',' . $log . "\n";
} else {
file_put_contents('log.txt', $time . ',' . $log . "\n", FILE_APPEND);
}
}3、運(yùn)行
php swoole.php
以上就是PHP+Swoole實(shí)現(xiàn)web版的shell客戶端詳解的詳細(xì)內(nèi)容,更多關(guān)于PHP Swoole shell客戶端的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
php array_map與array_walk比較案例詳解
這篇文章主要介紹了php array_map與array_walk比較案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09
Thinkphp結(jié)合ajaxFileUpload實(shí)現(xiàn)異步圖片傳輸示例
這篇文章主要給大家介紹了利用Thinkphp結(jié)合ajaxFileUpload實(shí)現(xiàn)異步圖片傳輸?shù)姆椒?,文中給出了詳細(xì)的示例代碼,對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-03-03

