Initial commit

This commit is contained in:
2020-01-18 05:51:45 +08:00
Unverified
commit e0da205b34
1758 changed files with 550610 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
<?php
$page_title = "404 Not found";
?>
<section class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1><?php echo $page_title; ?></h1>
</div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item">
<a href="?">主页</a>
</li>
<li class="breadcrumb-item active"><?php echo $page_title; ?></li>
</ol>
</div>
</div>
</div>
</section>
<section class="content">
<div class="error-page">
<h2 class="headline text-warning">404</h2>
<div class="error-content">
<br>
<h3><i class="fas fa-exclamation-triangle text-warning"></i> <b>Not found</b></h3>
<p>抱歉,我们无法找到您所请求的页面或文件,您可以尝试 <a href="?page=panel&module=home">返回首页</a> 或返回上一页。</p>
</div>
</div>
</section>
+303
View File
@@ -0,0 +1,303 @@
<?php
namespace SakuraPanel;
use SakuraPanel;
global $_config;
$page_title = "创建隧道";
$rs = Database::querySingleLine("users", Array("username" => $_SESSION['user']));
if(!$rs) {
exit("<script>location='?page=login';</script>");
}
$nm = new SakuraPanel\NodeManager();
$pm = new SakuraPanel\ProxyManager();
$un = $nm->getUserNode($rs['group']);
$proxies_max = $rs['proxies'] == "-1" ? "无限制" : $rs['proxies'];
if(isset($_GET['portrules'])) {
ob_clean();
SakuraPanel\Utils::checkCsrf();
echo "<p>映射的端口最小为 <code>{$_config['proxies']['min']}</code>,最大为 <code>{$_config['proxies']['max']}</code>。</p>";
if(!empty($_config['proxies']['protect'])) {
echo "<p>以下为系统保留的端口范围,不可使用:</p>";
echo "<ul>";
foreach($_config['proxies']['protect'] as $key => $value) {
echo "<li><code>{$key}</code> - <code>{$value}</code></li>";
}
echo "</ul>";
echo "<span>您最多可以使用 {$proxies_max} 个端口</span>";
}
exit;
}
if(isset($_GET['randomport'])) {
ob_clean();
SakuraPanel\Utils::checkCsrf();
echo $pm->getRandomPort();
exit;
}
?>
<style type="text/css">
.fix-text p {
margin-bottom: 4px;
}
.pdesc {
margin-left: 8px;
}
.sub-heading {
width: calc(100% - 16px);
height: 0!important;
border-top: 1px solid #e9f1f1!important;
text-align: center!important;
margin-top: 32px!important;
margin-bottom: 40px!important;
margin-left: 7px;
}
.sub-heading span {
display: inline-block;
position: relative;
padding: 0 17px;
top: -11px;
font-size: 16px;
color: #058;
background-color: #fff;
}
</style>
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark"><?php echo $page_title; ?>&nbsp;&nbsp;<small class="text-muted text-xs">创建一个新的内网穿透隧道</small></h1></div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item">
<a href="?">主页</a></li>
<li class="breadcrumb-item active"><?php echo $page_title; ?></li></ol>
</div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="col-lg-8">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">创建映射隧道</h3>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-sm-12">
<p><b>选择服务器</b> <small class="pdesc">选择您要使用的 Frp 服务器</small></p>
<p><select class="form-control" id="node">
<?php
foreach($un as $server) {
echo "<option value='{$server[0]}'>{$server[1]} - {$server[2]} ({$server[3]})</option>";
}
?>
</select></p>
</div>
<div class="sub-heading">
<span>基础设置</span>
</div>
<div class="col-sm-6">
<p><b>隧道名称</b><small class="pdesc">3-15 个字符,中英文和数字以及下划线组成</small></p>
<p><input type="text" class="form-control" id="proxy_name" placeholder="MyProxy" /></p>
</div>
<div class="col-sm-6">
<p><b>隧道类型</b> <small class="pdesc">每种隧道类型的区别请看右侧介绍</small></p>
<p><select class="form-control" id="proxy_type">
<option value="tcp">TCP 隧道</option>
<option value="udp">UDP 隧道</option>
<option value="http">HTTP 隧道</option>
<option value="https">HTTPS 隧道</option>
<option value="stcp">STCP 隧道</option>
<option value="xtcp">XTCP 隧道</option>
</select></p>
</div>
<div class="col-sm-6">
<p><b>本地地址</b> <small class="pdesc">要转发到的本机 IP,默认 127.0.0.1 即可</small></p>
<p><input type="text" class="form-control" id="local_ip" placeholder="127.0.0.1" /></p>
</div>
<div class="col-sm-6">
<p><b>本地端口</b> <small class="pdesc">本地服务的运行端口,例如网站是 80 端口</small></p>
<p><input type="text" class="form-control" id="local_port" placeholder="80" /></p>
</div>
<div class="col-sm-6">
<p><b>远程端口</b> <small class="pdesc">给访客连接时使用的外部端口 (<a href="javascript:loadPortRules();">查看规则</a>)</small></p>
<p><input type="text" class="form-control" id="remote_port" placeholder="1234" /></p>
</div>
<div class="col-sm-6">
<p><b>绑定域名</b> <small class="pdesc">仅限 HTTP 和 HTTPS 类型的隧道</small></p>
<p><input type="text" class="form-control" id="domain" placeholder="example.com" /></p>
</div>
<div class="sub-heading">
<span>高级设置</span>
</div>
<div class="col-sm-12">
<p><b>提示:</b>以下设置均为选填,仅供有需要的用户使用,一般留空即可。</p>
</div>
<div class="col-sm-6">
<p><b>加密传输</b> <small class="pdesc">使用加密来保护传输的数据</small></p>
<p><select class="form-control" id="use_encryption">
<option value="true">启用</option>
<option value="false">关闭</option>
</select></p>
</div>
<div class="col-sm-6">
<p><b>压缩数据</b> <small class="pdesc">压缩数据来节省宽带和流量使用</small></p>
<p><select class="form-control" id="use_compression">
<option value="true">启用</option>
<option value="false">关闭</option>
</select></p>
</div>
<div class="col-sm-6">
<p><b>URL 路由</b> <small class="pdesc">指定要转发的 URL 路由,仅限 HTTP 隧道</small></p>
<p><input type="text" class="form-control" id="locations" placeholder="/" /></p>
</div>
<div class="col-sm-6">
<p><b>Host 重写</b> <small class="pdesc">重写请求头部的 Host 字段,仅限 HTTP 隧道</small></p>
<p><input type="text" class="form-control" id="host_header_rewrite" placeholder="frp.example.com" /></p>
</div>
<div class="col-sm-6">
<p><b>请求来源</b> <small class="pdesc">给后端区分请求来源用,仅限 HTTP 隧道</small></p>
<p><input type="text" class="form-control" id="header_X-From-Where" placeholder="frp_node_1" /></p>
</div>
<div class="col-sm-6">
<p><b>访问密码</b> <small class="pdesc">Frpc 以访客模式连接时的密码,仅限 XTCP/STCP</small></p>
<p><input type="text" class="form-control" id="sk" placeholder="1234567890" /></p>
</div>
</div>
</div>
<div class="card-footer">
<button type="button" class="btn btn-default" onclick="randomPort()">随机端口</button>
<button type="button" class="btn btn-primary float-right" onclick="addProxy()">完成创建</button>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">隧道类型介绍</h3>
</div>
</div>
<div class="card-body fix-text">
<p><b>提示:</b>XTCP 映射成功率并不高,具体取决于 NAT 设备的复杂度。</p>
<p><b>TCP 映射</b></p>
<p>基础的 TCP 映射,适用于大多数服务,例如远程桌面、SSH、Minecraft、泰拉瑞亚等</p>
<p><b>UDP 映射</b></p>
<p>基础的 UDP 映射,适用于域名解析、部分基于 UDP 协议的游戏等</p>
<p><b>HTTP 映射</b></p>
<p>搭建网站专用映射,并通过 80 端口访问。</p>
<p><b>HTTPS 映射</b></p>
<p>带有 SSL 加密的网站映射,通过 443 端口访问,服务器需要支持 SSL。</p>
<p><b>XTCP 映射</b></p>
<p>客户端之间点对点 (P2P) 连接协议,流量不经过服务器,适合大流量传输的场景,需要两台设备之间都运行一个客户端。</p>
<p><b>STCP 映射</b></p>
<p>安全交换 TCP 连接协议,基于 TCP,访问此服务的用户也需要运行一个客户端,才能建立连接,流量由服务器转发。</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="modal-default" style="display: none;" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="msg-title"></h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span></button>
</div>
<div class="modal-body" id="msg-body"></div>
<div class="modal-footer justify-content-between">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" data-dismiss="modal">确定</button></div>
</div>
</div>
</div>
<script type="text/javascript">
var csrf_token = "<?php echo $_SESSION['token']; ?>";
function alertMessage(title, body) {
$("#msg-title").html(title);
$("#msg-body").html(body);
$("#modal-default").modal('toggle');
}
function addProxy() {
var node = $("#node").val();
var proxy_name = $("#proxy_name").val();
var proxy_type = $("#proxy_type").val();
var local_ip = $("#local_ip").val();
var local_port = $("#local_port").val();
var remote_port = $("#remote_port").val();
var domain = $("#domain").val();
var use_encryption = $("#use_encryption").val();
var use_compression = $("#use_compression").val();
var locations = $("#locations").val();
var host_header_rewrite = $("#host_header_rewrite").val();
var header_X_From_Where = $("#header_X-From-Where").val();
var sk = $("#sk").val();
var htmlobj = $.ajax({
type: 'POST',
url: "?page=panel&module=addproxy&action=addproxy&csrf=" + csrf_token,
data: {
node : node,
proxy_name : proxy_name,
proxy_type : proxy_type,
local_ip : local_ip,
local_port : local_port,
remote_port : remote_port,
domain : domain,
use_encryption : use_encryption,
use_compression : use_compression,
locations : locations,
host_header_rewrite: host_header_rewrite,
header_X_From_Where: header_X_From_Where,
sk : sk
},
async:true,
error: function() {
return;
},
success: function() {
alertMessage("提示信息", htmlobj.responseText);
return;
}
});
}
function loadPortRules() {
var htmlobj = $.ajax({
type: 'GET',
url: "?page=panel&module=addproxy&portrules&csrf=" + csrf_token,
async:true,
error: function() {
return;
},
success: function() {
alertMessage("端口规则", htmlobj.responseText);
return;
}
});
}
function randomPort() {
var htmlobj = $.ajax({
type: 'GET',
url: "?page=panel&module=addproxy&randomport&csrf=" + csrf_token,
async:true,
error: function() {
alertMessage("发生错误", htmlobj.responseText);
return;
},
success: function() {
$("#remote_port").val(htmlobj.responseText);
return;
}
});
}
</script>
+130
View File
@@ -0,0 +1,130 @@
<?php
namespace SakuraPanel;
use SakuraPanel;
$pm = new SakuraPanel\ProxyManager();
$page_title = "配置文件";
$rs = Database::querySingleLine("users", Array("username" => $_SESSION['user']));
if(!$rs) {
exit("<script>location='?page=login';</script>");
}
$sel_server = isset($_GET['server']) && preg_match("/^[0-9]+$/", $_GET['server']) ? Intval($_GET['server']) : 0;
if($sel_server <= 0) {
$sel_server = 1;
}
$ss = Database::toArray(Database::search("nodes", Array("group" => "{$rs['group']};", "status" => "200")));
?>
<style type="text/css">
.fix-text p {
margin-bottom: 4px;
}
.sub-heading {
width: calc(100% - 16px);
height: 0!important;
border-top: 1px solid #e9f1f1!important;
text-align: center!important;
margin-top: 32px!important;
margin-bottom: 40px!important;
margin-left: 7px;
}
.sub-heading span {
display: inline-block;
position: relative;
padding: 0 17px;
top: -11px;
font-size: 16px;
color: #058;
background-color: #fff;
}
</style>
<link href="assets/configuration/prettify.css" rel="stylesheet">
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark"><?php echo $page_title; ?>&nbsp;&nbsp;<small class="text-muted text-xs">获取用于客户端的配置文件</small></h1></div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item">
<a href="?">主页</a></li>
<li class="breadcrumb-item active"><?php echo $page_title; ?></li></ol>
</div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="col-lg-8">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">配置文件获取</h3>
</div>
</div>
<div class="card-body">
<p><b>选择服务器</b></p>
<p><select class="form-control" id="server" <?php echo count($ss) == 0 ? "disabled" : ""; ?>>
<?php
foreach($ss as $si) {
$selected = $sel_server == $si[0] ? "selected" : "";
echo "<option value='{$si[0]}' {$selected}>{$si[1]} ({$si[3]})</option>";
}
if(count($ss) == 0) {
echo "<option>没有可用的服务器</option>";
}
?>
</select></p>
<p><b>配置文件内容</b></p>
<pre class="prettyprint linenums"><?php echo count($ss) !== 0 ? $pm->getUserProxiesConfig($_SESSION['user'], $sel_server) : "当前所有服务器都不可用,请联系管理员。"; ?></pre>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">配置文件说明</h3>
</div>
</div>
<div class="card-body">
<p>每次创建完映射或删除了映射之后配置文件都会发生变化,请在变更后及时更新您的配置文件。</p>
<p class='text-danger'>请勿泄露配置文件中 user 字段的内容,否则他人可以登录您的账号,截图注意打码。</p>
<p>不过,如果真的泄露了,可以通过修改密码来解决,User 字段的内容也会随之更新。</p>
<div class="sub-heading">
<span>配置安装方法</span>
</div>
<p><ol>
<li>将左侧的内容复制。</li>
<li>在客户端的同级目录创建一个文本文档,命名为 frpc.ini 。</li>
<li>使用 Notepad++ 等专业的文本编辑器打开它</li>
<li>将复制的内容粘贴到里面并保存。</li>
</ol></p>
<div class="sub-heading">
<span>客户端启动方法</span>
</div>
<p><ol>
<li>按照上面的方法储存好你的配置文件。</li>
<li>在客户端的目录里按住 Shift + 鼠标右键。</li>
<li>点击 “在此处打开命令提示符” 或 “在此处打开 PowerShell”。</li>
<li>输入命令 <code>frpc.exe -c frpc.ini</code> 并按下回车启动。</li>
<li>保持命令提示符窗口打开,不要关闭它,否则映射会中断。</li>
</ol></p>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="assets/configuration/prettify.js"></script>
<script type="text/javascript">
prettyPrint();
window.onload = function() {
$('#server').change(function() {
location = "/?page=panel&module=configuration&server=" + $(this).children('option:selected').val();
});
}
</script>
+158
View File
@@ -0,0 +1,158 @@
<?php
namespace SakuraPanel;
use SakuraPanel;
$page_title = "软件下载";
$rs = Database::querySingleLine("users", Array("username" => $_SESSION['user']));
if(!$rs) {
exit("<script>location='?page=login';</script>");
}
?>
<style type="text/css">
.fix-text p {
margin-bottom: 4px;
}
.system-img {
height: 32px;
}
.download tr td {
vertical-align: middle;
}
</style>
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark"><?php echo $page_title; ?>&nbsp;&nbsp;<small class="text-muted text-xs">下载各种版本的 Frp 客户端</small></h1></div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item">
<a href="?">主页</a></li>
<li class="breadcrumb-item active"><?php echo $page_title; ?></li></ol>
</div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">客户端下载</h3>
</div>
</div>
<div class="card-body p-0 table-responsive">
<table class="download table table-striped table-valign-middle">
<thead>
<tr>
<th style="width: 32px;"></th>
<th nowrap>系统类型</th>
<th nowrap>系统架构</th>
<th nowrap>下载地址</th>
<th nowrap>下载文件</th>
</tr>
</thead>
<tbody>
<tr>
<td><img src="assets/download/windows.png" class="system-img"></td>
<td nowrap>Windows</td>
<td nowrap>i386</td>
<td nowrap><code>https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_windows_386.zip</code></td>
<td nowrap><a href="https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_windows_386.zip" target="_blank"><button class="btn btn-sm btn-success">点击下载</button></a></td>
</tr>
<tr>
<td><img src="assets/download/windows.png" class="system-img"></td>
<td nowrap>Windows</td>
<td nowrap>amd64</td>
<td nowrap><code>https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_windows_amd64.zip</code></td>
<td nowrap><a href="https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_windows_amd64.zip" target="_blank"><button class="btn btn-sm btn-success">点击下载</button></a></td>
</tr>
<tr>
<td><img src="assets/download/linux.png" class="system-img"></td>
<td nowrap>Linux</td>
<td nowrap>i386</td>
<td nowrap><code>https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_386.tar.gz</code></td>
<td nowrap><a href="https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_386.tar.gz" target="_blank"><button class="btn btn-sm btn-success">点击下载</button></a></td>
</tr>
<tr>
<td><img src="assets/download/linux.png" class="system-img"></td>
<td nowrap>Linux</td>
<td nowrap>amd64</td>
<td nowrap><code>https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_amd64.tar.gz</code></td>
<td nowrap><a href="https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_amd64.tar.gz" target="_blank"><button class="btn btn-sm btn-success">点击下载</button></a></td>
</tr>
<tr>
<td><img src="assets/download/linux.png" class="system-img"></td>
<td nowrap>Linux</td>
<td nowrap>arm</td>
<td nowrap><code>https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_arm.tar.gz</code></td>
<td nowrap><a href="https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_arm.tar.gz" target="_blank"><button class="btn btn-sm btn-success">点击下载</button></a></td>
</tr>
<tr>
<td><img src="assets/download/linux.png" class="system-img"></td>
<td nowrap>Linux</td>
<td nowrap>aarch64</td>
<td nowrap><code>https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_arm64.tar.gz</code></td>
<td nowrap><a href="https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_arm64.tar.gz" target="_blank"><button class="btn btn-sm btn-success">点击下载</button></a></td>
</tr>
<tr>
<td><img src="assets/download/linux.png" class="system-img"></td>
<td nowrap>Linux</td>
<td nowrap>Mips</td>
<td nowrap><code>https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_mips.tar.gz</code></td>
<td nowrap><a href="https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_mips.tar.gz" target="_blank"><button class="btn btn-sm btn-success">点击下载</button></a></td>
</tr>
<tr>
<td><img src="assets/download/linux.png" class="system-img"></td>
<td nowrap>Linux</td>
<td nowrap>Mips64</td>
<td nowrap><code>https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_mips64.tar.gz</code></td>
<td nowrap><a href="https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_mips64.tar.gz" target="_blank"><button class="btn btn-sm btn-success">点击下载</button></a></td>
</tr>
<tr>
<td><img src="assets/download/linux.png" class="system-img"></td>
<td nowrap>Linux</td>
<td nowrap>Mipsle</td>
<td nowrap><code>https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_mipsle.tar.gz</code></td>
<td nowrap><a href="https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_mipsle.tar.gz" target="_blank"><button class="btn btn-sm btn-success">点击下载</button></a></td>
</tr>
<tr>
<td><img src="assets/download/linux.png" class="system-img"></td>
<td nowrap>Linux</td>
<td nowrap>Mips64le</td>
<td nowrap><code>https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_mips64le.tar.gz</code></td>
<td nowrap><a href="https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_mips64le.tar.gz" target="_blank"><button class="btn btn-sm btn-success">点击下载</button></a></td>
</tr>
<tr>
<td><img src="assets/download/freebsd.png" class="system-img"></td>
<td nowrap>FreeBSD</td>
<td nowrap>i386</td>
<td nowrap><code>https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_freebsd_386.tar.gz</code></td>
<td nowrap><a href="https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_freebsd_386.tar.gz" target="_blank"><button class="btn btn-sm btn-success">点击下载</button></a></td>
</tr>
<tr>
<td><img src="assets/download/freebsd.png" class="system-img"></td>
<td nowrap>FreeBSD</td>
<td nowrap>amd64</td>
<td nowrap><code>https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_freebsd_amd64.tar.gz</code></td>
<td nowrap><a href="https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_freebsd_amd64.tar.gz" target="_blank"><button class="btn btn-sm btn-success">点击下载</button></a></td>
</tr>
<tr>
<td><img src="assets/download/macos.png" class="system-img"></td>
<td nowrap>MacOS</td>
<td nowrap>amd64</td>
<td nowrap><code>https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_darwin_amd64.tar.gz</code></td>
<td nowrap><a href="https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_darwin_amd64.tar.gz" target="_blank"><button class="btn btn-sm btn-success">点击下载</button></a></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
+110
View File
@@ -0,0 +1,110 @@
<?php
namespace SakuraPanel;
use SakuraPanel;
include(ROOT . "/core/Parsedown.php");
$markdown = new Parsedown();
$markdown->setSafeMode(true);
$markdown->setBreaksEnabled(true);
$markdown->setUrlsLinked(true);
$page_title = "管理面板";
$rs = Database::querySingleLine("users", Array("username" => $_SESSION['user']));
if(!$rs) {
exit("<script>location='?page=login';</script>");
}
$um = new SakuraPanel\UserManager();
$ls = $um->getLimit($_SESSION['user']);
$inbound = round($ls['inbound'] / 1024 * 8);
$outbound = round($ls['outbound'] / 1024 * 8);
$speed_limit = "{$inbound}Mbps 上行 / {$outbound}Mbps 下行";
$traffic = $rs['traffic'] - round($um->getTodayTraffic($_SESSION['user']) / 1024 / 1024);
if($traffic < 0) {
$traffic = 0;
}
?>
<style type="text/css">
.fix-text p {
margin-bottom: 4px;
}
</style>
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark"><?php echo $page_title; ?>&nbsp;&nbsp;<small class="text-muted text-xs">欢迎来到 Frp 管理面板</small></h1></div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item">
<a href="?">主页</a></li>
<li class="breadcrumb-item active"><?php echo $page_title; ?></li></ol>
</div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="col-lg-4">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">用户信息</h3>
</div>
</div>
<div class="card-body">
<h3 class='text-primary'><?php echo htmlspecialchars($_SESSION['user']); ?></h3>
<table style="width: 100%;font-size: 15px;margin-bottom: 16px;">
<tr>
<td style="width: 30%;"><b>注册邮箱</b></td>
<td><?php echo htmlspecialchars($_SESSION['mail']); ?></td>
</tr>
<tr>
<td style="width: 30%;"><b>注册时间</b></td>
<td><?php echo date("Y-m-d", $rs['regtime']); ?></td>
</tr>
<tr>
<td style="width: 30%;"><b>剩余流量</b></td>
<td><?php echo htmlspecialchars(round($traffic / 1024, 2)); ?> GB</td>
</tr>
<tr>
<td style="width: 30%;"><b>隧道数量</b></td>
<td><?php echo htmlspecialchars($rs['proxies']); ?> 条</td>
</tr>
<tr>
<td style="width: 30%;"><b>宽带速率</b></td>
<td><?php echo htmlspecialchars($speed_limit); ?></td>
</tr>
</table>
<span>您可以通过每日签到获取免费流量</span>
</div>
</div>
</div>
<div class="col-lg-8">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">站点公告</h3>
</div>
</div>
<div class="card-body fix-text">
<?php echo $markdown->text(Settings::get("broadcast", "暂时没有公告信息")); ?>
</div>
</div>
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">使用帮助</h3>
</div>
</div>
<div class="card-body fix-text">
<?php echo $markdown->text(Settings::get("helpinfo", "暂时没有帮助信息")); ?>
</div>
</div>
</div>
</div>
</div>
</div>
+259
View File
@@ -0,0 +1,259 @@
<?php
namespace SakuraPanel;
use SakuraPanel;
$page_title = "服务器节点";
$um = new SakuraPanel\NodeManager();
$rs = Database::querySingleLine("users", Array("username" => $_SESSION['user']));
if(!$rs || $rs['group'] !== "admin") {
exit("<script>location='?page=panel';</script>");
}
if(isset($_GET['getinfo']) && preg_match("/^[0-9]{1,10}$/", $_GET['getinfo'])) {
SakuraPanel\Utils::checkCsrf();
$rs = Database::querySingleLine("nodes", Array("id" => $_GET['getinfo']));
if($rs) {
ob_clean();
exit(json_encode($rs));
} else {
ob_clean();
Header("HTTP/1.1 403");
exit("未找到用户");
}
}
?>
<style type="text/css">
.fix-text p {
margin-bottom: 4px;
}
.sub-heading {
width: calc(100% - 16px);
height: 0!important;
border-top: 1px solid #e9f1f1!important;
text-align: center!important;
margin-top: 32px!important;
margin-bottom: 40px!important;
margin-left: 7px;
}
.sub-heading span {
display: inline-block;
position: relative;
padding: 0 17px;
top: -11px;
font-size: 16px;
color: #058;
background-color: #fff;
}
.page-num {
margin-right: 8px;
margin-bottom: 8px;
margin-top: 8px;
}
</style>
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark"><?php echo $page_title; ?>&nbsp;&nbsp;<small class="text-muted text-xs">管理本站点的服务器节点</small></h1></div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item">
<a href="?">主页</a></li>
<li class="breadcrumb-item active"><?php echo $page_title; ?></li></ol>
</div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="col-lg-8">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">服务器节点</h3>
</div>
</div>
<div class="card-body p-0 table-responsive">
<table class="table table-striped table-valign-middle" style="width: 100%;font-size: 15px;">
<tr>
<th class='text-center' nowrap>ID</th>
<th class='text-center' nowrap>名称</th>
<th class='text-center' nowrap>主机名</th>
<th class='text-center' nowrap>IP</th>
<th class='text-center' nowrap>端口</th>
<th class='text-center' nowrap>状态</th>
<th class='text-center' nowrap>操作</th>
</tr>
<?php
$rs = Database::toArray(Database::query("users", "SELECT * FROM `nodes`", true));
$i = 0;
foreach($rs as $node) {
$i++;
$statuss = Array(200 => "正常", 403 => "禁用", 500 => "离线", 401 => "隐藏");
$status = $statuss[Intval($node[10])] ?? "未知";
echo "<tr>
<td class='text-center' nowrap>{$node[0]}</td>
<td class='text-center' nowrap>{$node[1]}</td>
<td class='text-center' nowrap>{$node[3]}</td>
<td class='text-center' nowrap>{$node[4]}</td>
<td class='text-center' nowrap>{$node[5]}</td>
<td class='text-center' nowrap>{$status}</td>
<td class='text-center' nowrap><a href='javascript:edit({$node[0]})'>[编辑]</a> <a href='javascript:deletenode({$node[0]})'>[删除]</a></td>
";
}
?>
</table>
<?php
if($i == 0) {
echo "<p class='text-center'>没有找到符合条件的结果</p>";
}
?>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">添加或修改节点信息</h3>
</div>
</div>
<div class="card-body">
<p id="statusmsg">点击左侧节点列表的编辑按钮来编辑节点信息</p>
<div class="sub-heading">
<span>节点设置</span>
</div>
<p><b>节点名称</b>&nbsp;&nbsp;<small>会显示在隧道列表和创建隧道界面</small></p>
<p><input type="text" class="form-control" id="node_name"></input></p>
<p><b>节点简介</b>&nbsp;&nbsp;<small>用一句简单的话来介绍这个节点</small></p>
<p><input type="text" class="form-control" id="node_description"></input></p>
<p><b>主机名称</b>&nbsp;&nbsp;<small>这里可以是一个域名或者 IP 地址</small></p>
<p><input type="text" class="form-control" id="node_hostname"></input></p>
<p><b>IP 地址</b>&nbsp;&nbsp;<small>服务器的 IP 地址,请不要输入域名</small></p>
<p><input type="text" class="form-control" id="node_ip"></input></p>
<p><b>节点端口</b>&nbsp;&nbsp;<small>节点的 Frps 服务器运行端口</small></p>
<p><input type="number" class="form-control" id="node_port"></input></p>
<p><b>管理端口</b>&nbsp;&nbsp;<small>Frps 管理 API 的端口,用于系统接口</small></p>
<p><input type="number" class="form-control" id="node_adminport"></input></p>
<p><b>管理密码</b>&nbsp;&nbsp;<small>Frps 管理 API 的端口,用于系统接口</small></p>
<p><input type="text" class="form-control" id="node_adminpass"></input></p>
<p><b>Token</b>&nbsp;&nbsp;<small>用于 Frpc 客户端连接用的 Token</small></p>
<p><input type="text" class="form-control" id="node_token"></input></p>
<div class="sub-heading">
<span>其他设置</span>
</div>
<p><b>用户组</b>&nbsp;&nbsp;<small>允许的用户组,用 ; 隔开每个组名</small></p>
<p><input type="text" class="form-control" id="node_group"></input></p>
<p><b>节点状态</b>&nbsp;&nbsp;<small>切换节点的状态</small></p>
<select class="form-control" id="node_status">
<option value="200">正常</option>
<option value="401">隐藏</option>
<option value="403">禁用</option>
<option value="500">离线</option>
</select>
</div>
<div class="card-footer">
<button class="btn btn-primary float-sm-right" onclick="save()">保存设置</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var csrf_token = "<?php echo $_SESSION['token']; ?>";
var nodeid = undefined;
function search() {
window.location = window.location.href + '&search=' + encodeURIComponent($(searchdata).val());
}
function edit(id) {
var htmlobj = $.ajax({
type: 'GET',
url: "?page=panel&module=nodes&getinfo=" + id + "&csrf=" + csrf_token,
async:true,
error: function() {
alert("错误:" + htmlobj.responseText);
return;
},
success: function() {
try {
var json = JSON.parse(htmlobj.responseText);
nodeid = id;
$("#node_name").val(json.name);
$("#node_description").val(json.description);
$("#node_hostname").val(json.hostname);
$("#node_ip").val(json.ip);
$("#node_port").val(json.port);
$("#node_adminport").val(json.admin_port);
$("#node_adminpass").val(json.admin_pass);
$("#node_token").val(json.token);
$("#node_group").val(json.group);
$("#node_status").val(json.status);
$("#statusmsg").html("正在编辑节点 " + json.name + " 的设置");
} catch(e) {
alert("错误:无法解析服务器返回的数据");
}
return;
}
});
}
function deletenode(id) {
if(!confirm("你确定要删除这个节点吗?此操作不可恢复!\n\n该节点下所有的隧道也会被删除!")) {
return;
}
var htmlobj = $.ajax({
type: 'POST',
url: "?action=deletenode&page=panel&module=nodes&csrf=" + csrf_token,
async:true,
data: {
id: id
},
error: function() {
alert("错误:" + htmlobj.responseText);
return;
},
success: function() {
alert(htmlobj.responseText);
window.location.reload();
return;
}
});
}
function save() {
var url = "?action=updatenode&page=panel&module=nodes";
if(nodeid == undefined) {
nodeid = null;
url = "?action=addnode&page=panel&module=nodes";
}
var htmlobj = $.ajax({
type: 'POST',
url: url + "&csrf=" + csrf_token,
async:true,
data: {
id: nodeid,
name: $("#node_name").val(),
description: $("#node_description").val(),
hostname: $("#node_hostname").val(),
ip: $("#node_ip").val(),
port: $("#node_port").val(),
admin_port: $("#node_adminport").val(),
admin_pass: $("#node_adminpass").val(),
token: $("#node_token").val(),
group: $("#node_group").val(),
status: $("#node_status").val()
},
error: function() {
alert("错误:" + htmlobj.responseText);
return;
},
success: function() {
alert(htmlobj.responseText);
window.location.reload();
return;
}
});
}
</script>
+159
View File
@@ -0,0 +1,159 @@
<?php
namespace SakuraPanel;
use SakuraPanel;
$pm = new SakuraPanel\ProxyManager();
$page_title = "用户信息";
$rs = Database::querySingleLine("users", Array("username" => $_SESSION['user']));
if(!$rs) {
exit("<script>location='?page=login';</script>");
}
$um = new SakuraPanel\UserManager();
$ls = $um->getLimit($_SESSION['user']);
$inbound = round($ls['inbound'] / 1024 * 8);
$outbound = round($ls['outbound'] / 1024 * 8);
$speed_limit = "{$inbound}Mbps 上行 / {$outbound}Mbps 下行";
$signinfo = Database::querySingleLine("sign", Array("username" => $_SESSION['user']));
?>
<style type="text/css">
.fix-text p {
margin-bottom: 4px;
}
.sub-heading {
width: calc(100% - 16px);
height: 0!important;
border-top: 1px solid #e9f1f1!important;
text-align: center!important;
margin-top: 32px!important;
margin-bottom: 40px!important;
margin-left: 7px;
}
.sub-heading span {
display: inline-block;
position: relative;
padding: 0 17px;
top: -11px;
font-size: 16px;
color: #058;
background-color: #fff;
}
</style>
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark"><?php echo $page_title; ?>&nbsp;&nbsp;<small class="text-muted text-xs">查看您的个人信息</small></h1></div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item">
<a href="?">主页</a></li>
<li class="breadcrumb-item active"><?php echo $page_title; ?></li></ol>
</div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="col-lg-6">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">账号信息</h3>
</div>
</div>
<div class="card-body p-0 table-responsive">
<h3 class='text-primary' style='padding: 16px;padding-left: 24px;'><?php echo htmlspecialchars($_SESSION['user']); ?></h3>
<table class="download table table-striped table-valign-middle" style="width: 100%;font-size: 15px;">
<tr>
<td style="width: 30%;"><b>用户 ID</b></td>
<td><?php echo $rs['id']; ?></td>
</tr>
<tr>
<td style="width: 30%;"><b>注册邮箱</b></td>
<td><?php echo htmlspecialchars($_SESSION['mail']); ?></td>
</tr>
<tr>
<td style="width: 30%;"><b>注册时间</b></td>
<td><?php echo date("Y-m-d", $rs['regtime']); ?></td>
</tr>
<tr>
<td style="width: 30%;"><b>用户组别</b></td>
<td><?php echo htmlspecialchars($rs['group']); ?></td>
</tr>
</table>
</div>
</div>
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">修改密码</h3>
</div>
</div>
<form method="post" action="?page=panel&module=profile&action=updatepass&csrf=<?php echo $_SESSION['token']; ?>">
<div class="card-body">
<p><b>请输入旧密码</b></p>
<p><input type="password" class="form-control" name="oldpass"></p>
<p><b>请输入新密码</b></p>
<p><input type="password" class="form-control" name="newpass"></p>
<p><b>请再输入一次</b></p>
<p><input type="password" class="form-control" name="newpass1"></p>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-primary float-right">确认修改</button>
</div>
</form>
</div>
</div>
<div class="col-lg-6">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">映射信息</h3>
</div>
</div>
<div class="card-body p-0 table-responsive">
<p style='padding: 16px;padding-left: 24px;padding-bottom: 8px;'>关于您的内网穿透使用情况</p>
<table class="download table table-striped table-valign-middle" style="width: 100%;font-size: 15px;">
<tr>
<td style="width: 30%;"><b>剩余流量</b></td>
<td><?php echo htmlspecialchars(round($rs['traffic'] / 1024, 2)); ?> GB</td>
</tr>
<tr>
<td style="width: 30%;"><b>今日已用</b></td>
<td><?php echo htmlspecialchars(round($um->getTodayTraffic($_SESSION['user']) / 1024 / 1024 / 1024, 2)); ?> GB</td>
</tr>
<tr>
<td style="width: 30%;"><b>隧道数量</b></td>
<td><?php echo htmlspecialchars($rs['proxies']); ?> 条</td>
</tr>
<tr>
<td style="width: 30%;"><b>宽带速度</b></td>
<td><?php echo htmlspecialchars($speed_limit); ?></td>
</tr>
<tr>
<td style="width: 30%;"><b>创建隧道</b></td>
<td><?php echo htmlspecialchars($pm->getUserProxies($_SESSION['user'])); ?> 条</td>
</tr>
<tr>
<td style="width: 30%;"><b>总计签到</b></td>
<td><?php echo htmlspecialchars($signinfo['totalsign']); ?> 天</td>
</tr>
<tr>
<td style="width: 30%;"><b>获得流量</b></td>
<td><?php echo htmlspecialchars($signinfo['totaltraffic']); ?> GB</td>
</tr>
<tr>
<td style="width: 30%;"><b>上次签到</b></td>
<td><?php echo date("Y-m-d H:i:s", $signinfo['signdate']); ?></td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
+361
View File
@@ -0,0 +1,361 @@
<?php
namespace SakuraPanel;
use SakuraPanel;
include(ROOT . "/core/Parsedown.php");
$markdown = new Parsedown();
$markdown->setSafeMode(true);
$markdown->setBreaksEnabled(true);
$markdown->setUrlsLinked(true);
$page_title = "隧道列表";
$rs = Database::querySingleLine("users", Array("username" => $_SESSION['user']));
$pm = new SakuraPanel\ProxyManager();
$nm = new SakuraPanel\NodeManager();
$um = new SakuraPanel\UserManager();
if(!$rs) {
exit("<script>location='?page=login';</script>");
}
if(isset($_GET['getproxyinfo']) && preg_match("/^[0-9]{1,10}$/", $_GET['getproxyinfo'])) {
ob_clean();
SakuraPanel\Utils::checkCsrf();
$rs = $pm->getProxyInfo($_GET['getproxyinfo']);
if($rs) {
if(isset($rs['username']) && $rs['username'] == $_SESSION['user']) {
$ns = $nm->getNodeInfo($rs['node']);
$domain = "";
$domains = json_decode($rs['domain'], true);
if($domains && !empty($domains)) {
for($i = 0;$i < count($domains);$i++) {
$domain .= $domains[$i];
if($i < count($domains) - 1) { $domain .= ", "; }
}
}
?>
<style type="text/css">
.proxyinfo tr th {
width: 30%;
text-align: right;
padding-right: 16px;
}
</style>
<table class="proxyinfo" style="width: 100%;font-size: 15px;">
<tr>
<th>服务器</th>
<td><?php echo "{$ns['name']} ({$ns['hostname']})"; ?></td>
</tr>
<tr>
<th>隧道 ID</th>
<td><?php echo $rs['id']; ?></td>
</tr>
<tr>
<th>隧道类型</th>
<td><?php echo strtoupper($rs['proxy_type']); ?> 映射</td>
</tr>
<tr>
<th>本地地址</th>
<td><?php echo $rs['local_ip'] == "" ? "127.0.0.1" : $rs['local_ip']; ?></td>
</tr>
<tr>
<th>本地端口</th>
<td><?php echo $rs['local_port'] == "" ? "80" : $rs['local_port']; ?></td>
</tr>
<tr>
<th>远程端口</th>
<td><?php echo $rs['remote_port'] == "" ? "无" : $rs['remote_port']; ?></td>
</tr>
<tr>
<th>连接加密</th>
<td><?php echo $rs['use_encryption'] == "true" ? "启用" : "禁用"; ?></td>
</tr>
<tr>
<th>数据压缩</th>
<td><?php echo $rs['use_compression'] == "true" ? "启用" : "禁用"; ?></td>
</tr>
<tr>
<th>绑定域名</th>
<td><?php echo $domain == "" ? "无" : $domain; ?></td>
</tr>
<tr>
<th>URI 绑定</th>
<td><?php echo $rs['locations'] == "" ? "无" : $rs['locations']; ?></td>
</tr>
<tr>
<th>Host 重写</th>
<td><?php echo $rs['host_header_rewrite'] == "" ? "无" : $rs['host_header_rewrite']; ?></td>
</tr>
<tr>
<th>连接密码</th>
<td><?php echo $rs['sk'] == "" ? "无" : $rs['sk']; ?></td>
</tr>
<tr>
<th>X-From-Where</th>
<td><?php echo $rs['header_X-From-Where'] == "" ? "无" : $rs['header_X-From-Where']; ?></td>
</tr>
<tr>
<th>状态</th>
<td><?php echo $rs['status'] == "0" ? "启用" : "禁用"; ?></td>
</tr>
</table>
<?php
exit;
} else {
exit("拒绝访问");
}
} else {
exit("未找到该隧道");
}
}
if(isset($_GET['toggle']) && preg_match("/^[0-9]{1,10}$/", $_GET['toggle'])) {
ob_clean();
SakuraPanel\Utils::checkCsrf();
$rs = $pm->getProxyInfo($_GET['toggle']);
if($rs) {
if(isset($rs['username']) && $rs['username'] == $_SESSION['user']) {
if($rs['status'] == '2') {
exit("你的流量已经用完,无法开启隧道,充值或签到获取流量后即可恢复");
} elseif($rs['status'] == '3') {
exit("此隧道已经被管理员封禁,无法恢复");
} else {
$newStatus = $rs['status'] == "0" ? "1" : "0";
Database::update("proxies", Array("status" => $newStatus), Array("id" => $_GET['toggle']));
$nm->closeClient($rs['node'], $um->getUserToken($_SESSION['user']));
exit("隧道状态更新成功");
}
} else {
exit("拒绝访问");
}
} else {
exit("未找到该隧道");
}
}
if(isset($_GET['delete']) && preg_match("/^[0-9]{1,10}$/", $_GET['delete'])) {
ob_clean();
SakuraPanel\Utils::checkCsrf();
$rs = $pm->getProxyInfo($_GET['delete']);
if($rs) {
if(isset($rs['username']) && $rs['username'] == $_SESSION['user']) {
if($rs['status'] == '3') {
exit("此隧道已经被管理员封禁,无法删除");
} else {
Database::delete("proxies", Array("id" => $rs['id']));
$nm->closeClient($rs['node'], $um->getUserToken($_SESSION['user']));
exit("隧道删除成功,请刷新页面");
}
} else {
exit("拒绝访问");
}
} else {
exit("未找到该隧道");
}
}
$use_proxies = $pm->getUserProxies($_SESSION['user']);
$max_proxies = Intval($um->getInfoByUser($_SESSION['user'])['proxies']);
?>
<style type="text/css">
.fix-text p {
margin-bottom: 4px;
}
</style>
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark"><?php echo $page_title; ?>&nbsp;&nbsp;<small class="text-muted text-xs">管理您的内网穿透隧道</small></h1></div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item">
<a href="?">主页</a></li>
<li class="breadcrumb-item active"><?php echo $page_title; ?></li></ol>
</div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="col-lg-8">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">映射隧道列表</h3>
</div>
</div>
<div class="card-body table-responsive">
<p><i class="fas fa-info-circle"></i>&nbsp;&nbsp;您已添加 <code><?php echo $use_proxies; ?></code> 条隧道,还可以添加 <code><?php echo $max_proxies == -1 ? "无限制" : ($max_proxies - $use_proxies); ?></code> 条隧道。</p>
<table class="table table-striped table-valign-middle">
<thead>
<tr>
<th>ID</th>
<th nowrap>隧道名称</th>
<th nowrap>隧道类型</th>
<th nowrap>绑定域名 / 远程端口</th>
<th nowrap>服务器节点</th>
<th nowrap>操作</th>
<th nowrap>启用隧道</th>
</tr>
</thead>
<tbody>
<?php
$ps = Database::query("proxies", Array("username" => $_SESSION['user']));
$ps = Database::toArray($ps);
foreach($ps as $pi) {
$domOrPort = "";
$domains = json_decode($pi[8], true);
if($domains && !empty($domains)) {
for($i = 0;$i < count($domains);$i++) {
$domOrPort .= $domains[$i];
if($i < count($domains) - 1) { $domOrPort .= ", "; }
}
} elseif(!empty($pi[11])) {
$domOrPort = $pi[11];
}
$nodeName = $nm->getNodeInfo($pi[16])['name'];
$enable = $pi[14] == "0" ? "checked" : "";
$enable = $pi[14] == "2" || $pi[14] == "3" ? "disabled" : $enable;
echo "<tr>
<td>{$pi[0]}</td>
<td>{$pi[2]}</td>
<td>{$pi[3]}</td>
<td>{$domOrPort}</td>
<td>{$nodeName}</td>
<td nowrap><a href='javascript:deleteProxy({$pi[0]});'>删除</a> | <a href='javascript:getProxyInfo({$pi[0]});'>详细信息</a></td>
<td><div class='custom-control custom-switch'>
<input type='checkbox' class='custom-control-input' {$enable} id='switchProxy_{$pi[0]}' onclick='toggleProxy({$pi[0]});'>
<label class='custom-control-label' for='switchProxy_{$pi[0]}'></label>
</div></td>
</tr>";
}
?>
</tbody>
</table>
<?php
if(empty($ps)) {
echo "<div class='text-center' style='margin-top: 16px;'>您还没有创建任何隧道</div>";
}
?>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">隧道类型介绍</h3>
</div>
</div>
<div class="card-body fix-text">
<p><b>提示:</b>XTCP 映射成功率并不高,具体取决于 NAT 设备的复杂度。</p>
<p><b>TCP 映射</b></p>
<p>基础的 TCP 映射,适用于大多数服务,例如远程桌面、SSH、Minecraft、泰拉瑞亚等</p>
<p><b>UDP 映射</b></p>
<p>基础的 UDP 映射,适用于域名解析、部分基于 UDP 协议的游戏等</p>
<p><b>HTTP 映射</b></p>
<p>搭建网站专用映射,并通过 80 端口访问。</p>
<p><b>HTTPS 映射</b></p>
<p>带有 SSL 加密的网站映射,通过 443 端口访问,服务器需要支持 SSL。</p>
<p><b>XTCP 映射</b></p>
<p>客户端之间点对点 (P2P) 连接协议,流量不经过服务器,适合大流量传输的场景,需要两台设备之间都运行一个客户端。</p>
<p><b>STCP 映射</b></p>
<p>安全交换 TCP 连接协议,基于 TCP,访问此服务的用户也需要运行一个客户端,才能建立连接,流量由服务器转发。</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="modal-default" style="display: none;" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="msg-title"></h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span></button>
</div>
<div class="modal-body" id="msg-body"></div>
<div class="modal-footer justify-content-between">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" data-dismiss="modal">确定</button></div>
</div>
</div>
</div>
<div class="modal fade" id="deleteconfirm" style="display: none;" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">删除确认</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span></button>
</div>
<div class="modal-body">您确定要删除此隧道吗?删除之后将不能恢复!</div>
<div class="modal-footer justify-content-between">
<button type="button" class="btn btn-default" data-dismiss="modal" onclick="tempdelete = ''">关闭</button>
<button type="button" class="btn btn-primary" data-dismiss="modal" onclick="confirmDeleteProxy()">确定</button></div>
</div>
</div>
</div>
<script type="text/javascript">
var tempdelete = "";
var csrf_token = "<?php echo $_SESSION['token']; ?>";
function alertMessage(title, body) {
$("#msg-title").html(title);
$("#msg-body").html(body);
$("#modal-default").modal('toggle');
}
function getProxyInfo(id) {
var htmlobj = $.ajax({
type: 'GET',
url: "?page=panel&module=proxies&getproxyinfo=" + id + "&csrf=" + csrf_token,
async:true,
error: function() {
return;
},
success: function() {
alertMessage("映射信息", htmlobj.responseText);
return;
}
});
}
function toggleProxy(id) {
var htmlobj = $.ajax({
type: 'GET',
url: "?page=panel&module=proxies&toggle=" + id + "&csrf=" + csrf_token,
async:true,
error: function() {
return;
},
success: function() {
alertMessage("提示信息", htmlobj.responseText);
return;
}
});
}
function deleteProxy(id) {
// 随便这样吧
tempdelete = "" + id;
$("#deleteconfirm").modal('toggle');
}
function confirmDeleteProxy() {
if(tempdelete != "") {
var htmlobj = $.ajax({
type: 'GET',
url: "?page=panel&module=proxies&delete=" + tempdelete + "&csrf=" + csrf_token,
async:true,
error: function() {
return;
},
success: function() {
tempdelete = "";
alertMessage("提示信息", htmlobj.responseText);
return;
}
});
}
}
</script>
+230
View File
@@ -0,0 +1,230 @@
<?php
namespace SakuraPanel;
use SakuraPanel;
$page_title = "站点设置";
$um = new SakuraPanel\UserManager();
$nm = new SakuraPanel\NodeManager();
$pm = new SakuraPanel\ProxyManager();
$rs = Database::querySingleLine("users", Array("username" => $_SESSION['user']));
if(!$rs || $rs['group'] !== "admin") {
exit("<script>location='?page=panel';</script>");
}
$broadcast = SakuraPanel\Settings::get("broadcast");
$helpinfo = SakuraPanel\Settings::get("helpinfo");
?>
<style type="text/css">
.fix-text p {
margin-bottom: 4px;
}
.infotable th {
width: 30%;
}
#broadcast, #helpinfo {
width: 100%;
height: 256px;
max-width: 100%;
min-width: 100%;
min-height: 256px;
}
</style>
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark"><?php echo $page_title; ?>&nbsp;&nbsp;<small class="text-muted text-xs">更改网站的相关设置</small></h1></div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item">
<a href="?">主页</a></li>
<li class="breadcrumb-item active"><?php echo $page_title; ?></li></ol>
</div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="col-lg-8">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">编辑公告</h3>
</div>
</div>
<div class="card-body">
<p style="margin-top: -16px;">在此处填写公告内容,支持 Markdown 语法。</p>
<textarea class="form-control" id="broadcast"><?php echo $broadcast; ?></textarea>
</div>
<div class="card-footer">
<button type="button" class="btn btn-default" onclick="preview(broadcast.value)">预览更改</button>
<button type="button" class="btn btn-primary float-right" onclick="saveBroadcast()">保存修改</button>
</div>
</div>
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">编辑帮助</h3>
</div>
</div>
<div class="card-body">
<p style="margin-top: -16px;">在此处填写帮助内容,让用户更好的了解如何使用,支持 Markdown 语法。</p>
<textarea class="form-control" id="helpinfo"><?php echo $helpinfo; ?></textarea>
</div>
<div class="card-footer">
<button type="button" class="btn btn-default" onclick="preview(helpinfo.value)">预览更改</button>
<button type="button" class="btn btn-primary float-right" onclick="saveHelpInfo()">保存修改</button>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">站点信息</h3>
</div>
</div>
<div class="card-body fix-text table-responsive p-0">
<table class="table table-striped table-valign-middle infotable" style="width: 100%;font-size: 15px;margin-top: 0px;margin-bottom: 0px;">
<tr>
<th>版本</th>
<td><?php echo SakuraPanel\Utils::PANEL_VERSION; ?></td>
</tr>
<tr>
<th>服务器程序</th>
<td><?php echo $_SERVER['SERVER_SOFTWARE']; ?></td>
</tr>
<tr>
<th>运行模式</th>
<td><?php echo php_sapi_name(); ?></td>
</tr>
<tr>
<th>授权类型</th>
<td>免费版 (仅限非商业使用)</td>
</tr>
<tr>
<th>注册用户数</th>
<td><?php echo $um->getTotalUsers(); ?></td>
</tr>
<tr>
<th>服务器节点数</th>
<td><?php echo $nm->getTotalNodes(); ?></td>
</tr>
<tr>
<th>映射隧道数</th>
<td><?php echo $pm->getTotalProxies(); ?></td>
</tr>
<tr>
<th>更新检查</th>
<td id="updateinfo">正在检查更新...</td>
</tr>
</table>
<p style="padding: 12px;">&copy; 2019-<?php echo date("Y"); ?> SakuraPanel</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="modal-default" style="display: none;" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="msg-title"></h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span></button>
</div>
<div class="modal-body" id="msg-body"></div>
<div class="modal-footer justify-content-between">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" data-dismiss="modal">确定</button></div>
</div>
</div>
</div>
<script type="text/javascript">
var csrf_token = "<?php echo $_SESSION['token']; ?>";
function alertMessage(title, body) {
$("#msg-title").html(title);
$("#msg-body").html(body);
$("#modal-default").modal('toggle');
}
function saveBroadcast() {
var htmlobj = $.ajax({
type: 'POST',
url: "?action=updatebroadcast&page=panel&module=settings&csrf=" + csrf_token,
async:true,
data: {
data: $("#broadcast").val()
},
error: function() {
alert("错误:" + htmlobj.responseText);
return;
},
success: function() {
alert(htmlobj.responseText);
return;
}
});
}
function saveHelpInfo() {
var htmlobj = $.ajax({
type: 'POST',
url: "?action=updatehelpinfo&page=panel&module=settings&csrf=" + csrf_token,
async:true,
data: {
data: $("#helpinfo").val()
},
error: function() {
alert("错误:" + htmlobj.responseText);
return;
},
success: function() {
alert(htmlobj.responseText);
return;
}
});
}
function preview(data) {
var htmlobj = $.ajax({
type: 'POST',
url: "?action=preview&page=panel&module=settings&csrf=" + csrf_token,
async:true,
data: {
data: data
},
error: function() {
alertMessage("发生错误", htmlobj.responseText);
return;
},
success: function() {
alertMessage("预览更改", htmlobj.responseText);
return;
}
});
}
function checkUpdate() {
$("#updateinfo").html("正在检查更新...");
var htmlobj = $.ajax({
type: 'GET',
url: "https://cdn.zerodream.net/panel/update.php?s=SakuraPanel&version=<?php echo urlencode(SakuraPanel\Utils::PANEL_VERSION); ?>",
async:true,
error: function() {
$("#updateinfo").html("检查更新出错:" + htmlobj.responseText);
return;
},
success: function() {
try {
var json = JSON.parse(htmlobj.responseText);
$("#updateinfo").html("最新版本:" + json.version + "<br>更新内容:" + json.message);
} catch(e) {
}
return;
}
});
}
window.onload = checkUpdate;
</script>
+232
View File
@@ -0,0 +1,232 @@
<?php
namespace SakuraPanel;
use SakuraPanel;
include(ROOT . "/core/Parsedown.php");
global $_config;
$markdown = new Parsedown();
$markdown->setSafeMode(true);
$markdown->setBreaksEnabled(true);
$markdown->setUrlsLinked(true);
$page_title = "每日签到";
$rs = Database::querySingleLine("users", Array("username" => $_SESSION['user']));
$pm = new SakuraPanel\ProxyManager();
$nm = new SakuraPanel\NodeManager();
$um = new SakuraPanel\UserManager();
if(!$rs) {
exit("<script>location='?page=login';</script>");
}
$user_traffic = $rs['traffic'] - ($um->getTodayTraffic($_SESSION['user']) / 1024 / 1024);
if(isset($_GET['sign'])) {
ob_clean();
SakuraPanel\Utils::checkCsrf();
// 欢迎来到喜闻乐见的欧皇与非酋抽流量
if(!$_config['sign']['enable']) {
exit("本站暂未开启签到功能~");
}
// 欧皇判定范围
$good_rand = round($_config['sign']['max'] * 0.7);
// 非酋判定范围
$bad_rand = round($_config['sign']['max'] * 0.2);
// 随机流量
$rand = mt_rand($_config['sign']['min'], $_config['sign']['max']);
$rs = Database::querySingleLine("sign", Array("username" => $_SESSION['user']));
if($rs) {
if(isset($rs['signdate'])) {
if(round(time() / 86400) >= (round($rs['signdate'] / 86400) + 1)) {
$totaltraffic = $rs['totaltraffic'] == "" ? "0" : $rs['totaltraffic'];
$totalsign = $rs['totalsign'] == "" ? "0" : $rs['totalsign'];
Database::update("sign", Array("signdate" => time(), "totaltraffic" => $totaltraffic + $rand, "totalsign" => $totalsign + 1), Array("username" => $_SESSION['user']));
Database::update("users", Array("traffic" => $user_traffic + ($rand * 1024)), Array("username" => $_SESSION['user']));
Database::update("proxies", Array("status" => "0"), Array("username" => $_SESSION['user'], "status" => "2"));
$randtext = "今天运气不错,";
if($rand >= $good_rand) {
$randtext = "今天欧皇手气,共";
} elseif($rand <= $bad_rand) {
$randtext = "今天是非酋,只";
}
exit("签到成功,{$randtext}获得了 {$rand}GB 流量,目前您的剩余流量为 " . round(($user_traffic + ($rand * 1024)) / 1024, 2) . "GB。");
} else {
exit("您今天已经签到过了,请明天再来");
}
} else {
Database::insert("sign", Array("id" => null, "username" => $_SESSION['user'], "signdate" => time(), "totaltraffic" => $rand, "totalsign" => 1));
Database::update("users", Array("traffic" => $user_traffic + ($rand * 1024)), Array("username" => $_SESSION['user']));
Database::update("proxies", Array("status" => "0"), Array("username" => $_SESSION['user'], "status" => "2"));
exit("签到成功,这是你第一次签到,获得了 {$rand}GB 流量。");
}
} else {
Database::insert("sign", Array("id" => null, "username" => $_SESSION['user'], "signdate" => time(), "totaltraffic" => $rand, "totalsign" => 1));
Database::update("users", Array("traffic" => $user_traffic + ($rand * 1024)), Array("username" => $_SESSION['user']));
Database::update("proxies", Array("status" => "0"), Array("username" => $_SESSION['user'], "status" => "2"));
exit("签到成功,这是你第一次签到,获得了 {$rand}GB 流量。");
}
}
$signed = false;
$ss = Database::querySingleLine("sign", Array("username" => $_SESSION['user']));
if($ss) {
if(isset($ss['signdate']) && round(time() / 86400) < (round($ss['signdate'] / 86400) + 1)) {
$signed = true;
}
}
?>
<style type="text/css">
.fix-text p {
margin-bottom: 4px;
}
.info-icon {
margin-bottom: 16px;
}
.sub-heading {
width: 100%;
height: 0!important;
border-top: 1px solid #e9f1f1!important;
text-align: center!important;
margin-top: 32px!important;
margin-bottom: 40px!important;
}
.sub-heading span {
display: inline-block;
position: relative;
padding: 0 17px;
top: -11px;
font-size: 16px;
color: #058;
background-color: #fff;
}
</style>
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark"><?php echo $page_title; ?>&nbsp;&nbsp;<small class="text-muted text-xs">签到以获取免费的流量</small></h1></div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item">
<a href="?">主页</a></li>
<li class="breadcrumb-item active"><?php echo $page_title; ?></li></ol>
</div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="col-lg-7">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">每日签到</h3>
</div>
</div>
<div class="card-body table-responsive">
<div class="row">
<div class="col-sm-9">
<?php
if($signed) {
?>
<h3 class="text-success">您今天已经签到过了噢</h3>
<p>继续保持签到就可以获得更多的流量</p>
<?php
} else {
?>
<h3 class="text-warning">您今天还没有签到哦</h3>
<p>立即签到就可以获得免费的流量,可用于内网穿透使用</p>
<?php
}
?>
</div>
<div class="col-sm-3 text-center" style="padding-top: 16px;">
<button class="btn btn-primary" onclick="sign()" <?php echo $signed ? "disabled" : ""; ?>>立即签到</button>
</div>
</div>
<div class="sub-heading">
<span>统计信息</span>
</div>
<div class="row">
<div class="col-sm-4 text-center">
<h1 class='info-icon'><i class='fas fa-calendar-check'></i></h1>
<p>总计已签到 <?php echo $ss['totalsign'] == "" ? "0" : $ss['totalsign'];?> 天</p>
</div>
<div class="col-sm-4 text-center">
<h1 class='info-icon'><i class='fas fa-rocket'></i></h1>
<p>共获得流量 <?php echo $ss['totaltraffic'] == "" ? "0" : $ss['totaltraffic'];?> GB</p>
</div>
<div class="col-sm-4 text-center">
<h1 class='info-icon'><i class='fas fa-clock'></i></h1>
<p>上次签到于 <?php echo $ss['signdate'] == "" ? "从未签到" : date("Y-m-d", $ss['signdate']);?></p>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-5">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">签到说明</h3>
</div>
</div>
<div class="card-body fix-text">
<p>欢迎使用签到系统,通过每天登录签到您可以获得免费的流量,可以用于抵消使用内网穿透产生的流量费用。</p>
<div class="sub-heading">
<span>签到配置</span>
</div>
<p>当前站点的签到系统启用状态:<?php echo $_config['sign']['enable'] ? "<span class='text-success'>已启用</span>" : "<span class='text-danger'>已禁用</span>"; ?>。</p>
<p>通过签到可以随机获得 <?php echo $_config['sign']['min']; ?> ~ <?php echo $_config['sign']['max']; ?> GB 流量。</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="modal-default" style="display: none;" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="msg-title"></h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span></button>
</div>
<div class="modal-body" id="msg-body"></div>
<div class="modal-footer justify-content-between">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" data-dismiss="modal" onclick="window.location.reload()">确定</button></div>
</div>
</div>
</div>
<script type="text/javascript">
var csrf_token = "<?php echo $_SESSION['token']; ?>";
function alertMessage(title, body) {
$("#msg-title").html(title);
$("#msg-body").html(body);
$("#modal-default").modal('toggle');
}
function sign() {
var htmlobj = $.ajax({
type: 'GET',
url: "?page=panel&module=sign&sign&csrf=" + csrf_token,
async:true,
error: function() {
return;
},
success: function() {
alertMessage("提示信息", htmlobj.responseText);
return;
}
});
}
</script>
+249
View File
@@ -0,0 +1,249 @@
<?php
namespace SakuraPanel;
use SakuraPanel;
$page_title = "流量统计";
$um = new SakuraPanel\UserManager();
$rs = Database::querySingleLine("users", Array("username" => $_SESSION['user']));
if(!$rs || $rs['group'] !== "admin") {
exit("<script>location='?page=panel';</script>");
}
if(isset($_GET['getinfo']) && preg_match("/^[0-9]{1,10}$/", $_GET['getinfo'])) {
ob_clean();
SakuraPanel\Utils::checkCsrf();
$nm = new SakuraPanel\NodeManager();
$rs = $nm->getNodeInfo($_GET['getinfo']);
if(is_array($rs)) {
$hs = SakuraPanel\Utils::http("http://admin:{$rs['admin_pass']}@{$rs['ip']}:{$rs['admin_port']}/api/serverinfo");
if(isset($hs['status']) && $hs['status'] == 200) {
$js = json_decode($hs['body'], true);
$tf_in = SakuraPanel\Utils::getFormatTraffic($js['total_traffic_in']);
$tf_out = SakuraPanel\Utils::getFormatTraffic($js['total_traffic_out']);
echo <<<EOF
<h4>{$rs['name']} <small>节点信息</small></h4>
<hr>
<table style="width: 100%;" class="sinfotable">
<tr><th>服务端版本</th><td>{$js['version']}</td></tr>
<tr><th>监听端口</th><td>{$js['bind_port']}</td></tr>
<tr><th>UDP 监听端口</th><td>{$js['bind_udp_port']}</td></tr>
<tr><th>HTTP 监听端口</th><td>{$js['vhost_http_port']}</td></tr>
<tr><th>HTTPS 监听端口</th><td>{$js['vhost_https_port']}</td></tr>
<tr><th>总共入网流量</th><td>{$tf_in}</td></tr>
<tr><th>总共入网流量</th><td>{$tf_out}</td></tr>
<tr><th>连接数量</th><td>{$js['cur_conns']}</td></tr>
<tr><th>客户端数量</th><td>{$js['client_counts']}</td></tr>
</table>
EOF;
exit;
} else {
Header("HTTP/1.1 404 Not Found");
exit("无法连接至服务器,错误代码:{$hs['status']}");
}
} else {
exit("未找到该隧道");
}
}
if(isset($_GET['gettraffic']) && preg_match("/^[0-9]{1,10}$/", $_GET['gettraffic']) && in_array($_GET['type'], ["tcp", "udp", "http", "https", "stcp"])) {
ob_clean();
SakuraPanel\Utils::checkCsrf();
$um = new SakuraPanel\UserManager();
$nm = new SakuraPanel\NodeManager();
$rs = $nm->getNodeInfo($_GET['gettraffic']);
$tokens = $um->getTokensToUsers();
if(is_array($rs)) {
$hs = SakuraPanel\Utils::http("http://admin:{$rs['admin_pass']}@{$rs['ip']}:{$rs['admin_port']}/api/proxy/{$_GET['type']}");
if(isset($hs['status']) && $hs['status'] == 200) {
$js = json_decode($hs['body'], true);
echo '<table class="table table-striped table-valign-middle" style="width: 100%;font-size: 15px;margin-top: 12px;margin-bottom: 0px;">';
echo '<tr><th>隧道名称</th><th>所属用户</th><th>连接数量</th><th>今日流量 (↓/↑)</th><th>当前状态</th></tr>';
foreach($js['proxies'] as $proxy) {
$name = explode(".", $proxy['name']);
if(count($name) !== 2) continue;
echo "<tr>";
echo "<td>{$name[1]}</td>";
echo "<td>{$tokens[$name[0]]}</td>";
echo "<td>{$proxy['cur_conns']}</td>";
$tf_in = SakuraPanel\Utils::getFormatTraffic($proxy['today_traffic_in']);
$tf_out = SakuraPanel\Utils::getFormatTraffic($proxy['today_traffic_out']);
echo "<td>{$tf_in} / {$tf_out}</td>";
echo "<td>{$proxy['status']}</td>";
echo "</tr>";
}
echo "</table>";
exit;
} else {
Header("HTTP/1.1 404 Not Found");
exit("无法连接至服务器,错误代码:{$hs['status']}");
}
} else {
exit("未找到该隧道");
}
}
?>
<style type="text/css">
.fix-text p {
margin-bottom: 4px;
}
.sinfotable th {
width: 40%;
}
</style>
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark"><?php echo $page_title; ?>&nbsp;&nbsp;<small class="text-muted text-xs">查看服务器的流量统计信息</small></h1></div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item">
<a href="?">主页</a></li>
<li class="breadcrumb-item active"><?php echo $page_title; ?></li></ol>
</div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="col-lg-8">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">服务器节点</h3>
</div>
</div>
<div class="card-body p-0 table-responsive">
<table class="table table-striped table-valign-middle" style="width: 100%;font-size: 15px;">
<tr>
<th class='text-center' nowrap>ID</th>
<th class='text-center' nowrap>名称</th>
<th class='text-center' nowrap>主机名</th>
<th class='text-center' nowrap>IP</th>
<th class='text-center' nowrap>端口</th>
<th class='text-center' nowrap>状态</th>
<th class='text-center' nowrap>操作</th>
</tr>
<?php
$rs = Database::toArray(Database::query("users", "SELECT * FROM `nodes`", true));
$i = 0;
foreach($rs as $node) {
$i++;
$statuss = Array(200 => "正常", 403 => "禁用", 500 => "离线", 401 => "隐藏");
$status = $statuss[Intval($node[10])] ?? "未知";
echo "<tr>
<td class='text-center' nowrap>{$node[0]}</td>
<td class='text-center' nowrap>{$node[1]}</td>
<td class='text-center' nowrap>{$node[3]}</td>
<td class='text-center' nowrap>{$node[4]}</td>
<td class='text-center' nowrap>{$node[5]}</td>
<td class='text-center' nowrap>{$status}</td>
<td class='text-center' nowrap><a href='javascript:selectserver({$node[0]})'>[选择]</a></td>
";
}
?>
</table>
<?php
if($i == 0) {
echo "<p class='text-center'>没有找到符合条件的结果</p>";
}
?>
</div>
</div>
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">查看流量排行</h3>
</div>
</div>
<div class="card-body fix-text">
<p>先点击上面选择一个服务器,然后再点击此处进行查询。</p>
<p>流量实时查询需要一定时间,请勿频繁点击按钮,否则容易导致服务器卡死。</p>
<span>选择映射类型:</span>&nbsp;&nbsp;
<button class="btn btn-default" onclick="gettraffic('tcp')">TCP</button>&nbsp;&nbsp;
<button class="btn btn-default" onclick="gettraffic('udp')">UDP</button>&nbsp;&nbsp;
<button class="btn btn-default" onclick="gettraffic('http')">HTTP</button>&nbsp;&nbsp;
<button class="btn btn-default" onclick="gettraffic('https')">HTTPS</button>&nbsp;&nbsp;
<button class="btn btn-default" onclick="gettraffic('stcp')">STCP</button>&nbsp;&nbsp;
<div id="trafficlist" class="table-responsive">
<!-- placeholder -->
</div>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">服务器信息</h3>
</div>
</div>
<div class="card-body fix-text" id="serverinfo">
<p>请选择一个服务器,然后这里会显示信息</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="modal-default" style="display: none;" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="msg-title"></h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span></button>
</div>
<div class="modal-body" id="msg-body"></div>
<div class="modal-footer justify-content-between">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" data-dismiss="modal">确定</button></div>
</div>
</div>
</div>
<script type="text/javascript">
var csrf_token = "<?php echo $_SESSION['token']; ?>";
var nodeid = undefined;
function search() {
window.location = window.location.href + '&search=' + encodeURIComponent($(searchdata).val());
}
function selectserver(id) {
$("#serverinfo").html("正在查询...");
var htmlobj = $.ajax({
type: 'GET',
url: "?page=panel&module=traffic&getinfo=" + id + "&csrf=" + csrf_token,
async:true,
error: function() {
alert("错误:" + htmlobj.responseText);
return;
},
success: function() {
nodeid = id;
$("#serverinfo").html(htmlobj.responseText);
return;
}
});
}
function gettraffic(type) {
if(nodeid == undefined) {
alert("请先选择一个服务器后再查询流量");
return;
}
$("#trafficlist").html("正在查询...");
var htmlobj = $.ajax({
type: 'GET',
url: "?page=panel&module=traffic&gettraffic=" + nodeid + "&type=" + type + "&csrf=" + csrf_token,
async:true,
error: function() {
alert("错误:" + htmlobj.responseText);
return;
},
success: function() {
$("#trafficlist").html(htmlobj.responseText);
return;
}
});
}
</script>
+281
View File
@@ -0,0 +1,281 @@
<?php
namespace SakuraPanel;
use SakuraPanel;
$page_title = "用户列表";
$um = new SakuraPanel\UserManager();
$rs = Database::querySingleLine("users", Array("username" => $_SESSION['user']));
if(!$rs || $rs['group'] !== "admin") {
exit("<script>location='?page=panel';</script>");
}
if(isset($_GET['getinfo']) && preg_match("/^[0-9]{1,10}$/", $_GET['getinfo'])) {
SakuraPanel\Utils::checkCsrf();
$rs = Database::querySingleLine("users", Array("id" => $_GET['getinfo']));
if($rs) {
$lm = $um->getLimit($rs['username']);
$inbound = $lm['type'] == 1 ? $lm['inbound'] : "";
$outbound = $lm['type'] == 1 ? $lm['outbound'] : "";
ob_clean();
exit(json_encode(Array(
"id" => $rs['id'],
"username" => $rs['username'],
"traffic" => $rs['traffic'],
"proxies" => $rs['proxies'],
"inbound" => $inbound,
"outbound" => $outbound,
"group" => $rs['group'],
"status" => $rs['status']
)));
} else {
ob_clean();
Header("HTTP/1.1 403");
exit("未找到用户");
}
}
?>
<style type="text/css">
.fix-text p {
margin-bottom: 4px;
}
.sub-heading {
width: calc(100% - 16px);
height: 0!important;
border-top: 1px solid #e9f1f1!important;
text-align: center!important;
margin-top: 32px!important;
margin-bottom: 40px!important;
margin-left: 7px;
}
.sub-heading span {
display: inline-block;
position: relative;
padding: 0 17px;
top: -11px;
font-size: 16px;
color: #058;
background-color: #fff;
}
.page-num {
margin-right: 8px;
margin-bottom: 8px;
margin-top: 8px;
}
</style>
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark"><?php echo $page_title; ?>&nbsp;&nbsp;<small class="text-muted text-xs">管理本站点的用户</small></h1></div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item">
<a href="?">主页</a></li>
<li class="breadcrumb-item active"><?php echo $page_title; ?></li></ol>
</div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="col-lg-8">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">用户列表</h3>
</div>
</div>
<div class="card-body p-0 table-responsive">
<table class="table table-striped table-valign-middle" style="width: 100%;font-size: 15px;">
<tr>
<th class='text-center' nowrap>ID</th>
<th class='text-center' nowrap>用户名</th>
<th class='text-center' nowrap>邮箱</th>
<th class='text-center' nowrap>流量</th>
<th class='text-center' nowrap>隧道</th>
<th class='text-center' nowrap>用户组</th>
<th class='text-center' nowrap>注册时间</th>
<th class='text-center' nowrap>状态</th>
<th class='text-center' nowrap>操作</th>
</tr>
<?php
$spage = isset($_GET['p']) && preg_match("/^[0-9]{1,9}$/", $_GET['p']) && Intval($_GET['p']) > 0 ? (Intval($_GET['p'])) : 1;
$_GET['search'] = isset($_GET['search']) ? Database::escape($_GET['search']) : "";
$_GET['p'] = isset($_GET['p']) && preg_match("/^[0-9]{1,9}$/", $_GET['p']) && Intval($_GET['p']) > 0 ? (Intval($_GET['p']) - 1) * 10 : "";
$mainSQL = "SELECT * FROM `users` ";
$mainSQL .= (isset($_GET['search']) && !empty($_GET['search'])) ? "WHERE POSITION('{$_GET['search']}' IN `username`) OR POSITION('{$_GET['search']}' IN `email`) " : "";
$mainSQL .= (isset($_GET['p']) && !empty($_GET['p'])) ? "LIMIT {$_GET['p']},11" : "LIMIT 0,11";
$rs = Database::toArray(Database::query("users", $mainSQL, true));
$i = 0;
foreach($rs as $user) {
$i++;
if($i > 10) break;
$traffic = round($user[4] / 1024, 2) . "GB";
$regtime = date("Y-m-d", $user[7]);
$statuss = Array(0 => "正常", 1 => "已封号");
$status = $statuss[$user[8]] ?? "未知";
echo "<tr>
<td class='text-center' nowrap>{$user[0]}</td>
<td class='text-center' nowrap>{$user[1]}</td>
<td class='text-center' nowrap>{$user[3]}</td>
<td class='text-center' nowrap>{$traffic}</td>
<td class='text-center' nowrap>{$user[5]}</td>
<td class='text-center' nowrap>{$user[6]}</td>
<td class='text-center' nowrap>{$regtime}</td>
<td class='text-center' nowrap>{$status}</td>
<td class='text-center' nowrap><a href='javascript:edit({$user[0]})'>[编辑]</a></td>
";
}
?>
</table>
<?php
if($i == 0) {
echo "<p class='text-center'>没有找到符合条件的结果</p>";
}
?>
<div class="text-right page-num">
<span>当前在第 <?php echo $spage; ?> 页&nbsp;&nbsp;</span>
<?php
$search = isset($_GET['search']) ? "&search=" . urlencode($_GET['search']) : "";
$fpage = $spage - 1;
$npage = $spage + 1;
if($i > 10) {
if(isset($_GET['p']) && Intval($_GET['p']) > 1) {
echo "<a href='?page=panel&module=userlist{$search}'><button class='btn btn-default'><i class='fa fa-home'></i></button></a>&nbsp;&nbsp;";
echo "<a href='?page=panel&module=userlist{$search}&p={$fpage}'><button class='btn btn-default'><i class='fa fa-angle-left'></i></button></a>&nbsp;&nbsp;";
}
echo "<a href='?page=panel&module=userlist{$search}&p={$npage}'><button class='btn btn-default'><i class='fa fa-angle-right'></i></button></a>";
} else {
if(isset($_GET['p']) && Intval($_GET['p']) > 1) {
echo "<a href='?page=panel&module=userlist{$search}'><button class='btn btn-default'><i class='fa fa-home'></i></button></a>&nbsp;&nbsp;";
echo "<a href='?page=panel&module=userlist{$search}&p={$fpage}'><button class='btn btn-default'><i class='fa fa-angle-left'></i></button></a>";
}
}
?></div>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card">
<div class="card-header border-0">
<div class="d-flex justify-content-between">
<h3 class="card-title">修改用户信息</h3>
</div>
</div>
<div class="card-body">
<p id="statusmsg">点击左侧用户列表的编辑按钮来编辑用户信息</p>
<div class="sub-heading">
<span>搜索用户</span>
</div>
<p>可输入用户名、邮箱来进行搜索</p>
<div class="input-group">
<input type="text" class="form-control" id="searchdata">
<span class="input-group-append">
<button type="button" class="btn btn-info" onclick="search()"><i class="fas fa-search"></i></button>
</span>
</div>
<div class="sub-heading">
<span>映射设置</span>
</div>
<p>此部分设置如果留空将会使用用户组的设置进行覆盖。例如您需要将某个用户设置为 VIP,同时更新该用户的限速、流量等信息至 VIP 的设置,请先清空此部分输入框内容。</p>
<p><b>流量设置</b>&nbsp;&nbsp;<small>单位 MB,修改后即时生效。</small></p>
<p><input type="number" class="form-control" id="traffic"></input></p>
<p><b>隧道数量</b>&nbsp;&nbsp;<small>用户最多可以添加的隧道数量</small></p>
<p><input type="number" class="form-control" id="proxies"></input></p>
<p><b>最大上传</b>&nbsp;&nbsp;<small>单位 KB/s,留空则继承组设定</small></p>
<p><input type="number" class="form-control" id="inbound"></input></p>
<p><b>最大下行</b>&nbsp;&nbsp;<small>单位 KB/s,留空则继承组设定</small></p>
<p><input type="number" class="form-control" id="outbound"></input></p>
<div class="sub-heading">
<span>权限设置</span>
</div>
<p><b>用户组</b>&nbsp;&nbsp;<small>选择需要将用户分配到的用户组</small></p>
<p><select class="form-control" id="group">
<?php
$gs = Database::toArray(Database::query("groups", "SELECT * FROM `groups`", true));
foreach($gs as $gi) {
echo "<option value='{$gi[1]}'>{$gi[2]}</option>";
}
?>
<option value="admin">管理员</option>
</select></p>
<p><b>用户状态</b>&nbsp;&nbsp;<small>切换用户的状态</small></p>
<select class="form-control" id="status">
<option value="0">正常</option>
<option value="1">封号</option>
</select>
</div>
<div class="card-footer">
<button class="btn btn-primary float-sm-right" onclick="save()">保存设置</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var csrf_token = "<?php echo $_SESSION['token']; ?>";
var userid = "";
function search() {
window.location = window.location.href + '&search=' + encodeURIComponent($(searchdata).val());
}
function edit(id) {
var htmlobj = $.ajax({
type: 'GET',
url: "?page=panel&module=userlist&getinfo=" + id + "&csrf=" + csrf_token,
async:true,
error: function() {
alert("错误:" + htmlobj.responseText);
return;
},
success: function() {
try {
var json = JSON.parse(htmlobj.responseText);
userid = json.id;
$("#traffic").val(json.traffic);
$("#proxies").val(json.proxies);
$("#inbound").val(json.inbound);
$("#outbound").val(json.outbound);
$("#group").val(json.group);
$("#status").val(json.status);
$("#statusmsg").html("正在编辑用户 " + json.username + " 的设置");
} catch(e) {
alert("错误:无法解析服务器返回的数据");
}
return;
}
});
}
function save() {
if(userid == "") {
alert("您未编辑任何用户信息。");
return;
}
var htmlobj = $.ajax({
type: 'POST',
url: "?action=updateuser&page=panel&module=userlist&csrf=" + csrf_token,
async:true,
data: {
id: userid,
traffic: $("#traffic").val(),
proxies: $("#proxies").val(),
inbound: $("#inbound").val(),
outbound: $("#outbound").val(),
group: $("#group").val(),
status: $("#status").val()
},
error: function() {
alert("错误:" + htmlobj.responseText);
return;
},
success: function() {
alert(htmlobj.responseText);
window.location.reload();
return;
}
});
}
</script>