生活不只是眼前的苟且,还有诗和远方!

sspanel进阶——修改属于自己的sspanel站点

很多朋友搭建了原版或者魔改版的sspanel,界面以及功能各有千秋,那么,如何搭建自己的魔改sspanel呢?授人以鱼不如授人以渔,这个博文系列将会介绍如何修改出属于自己的sspanel站点。

今天所述实例基于orvice 的sspanel原版,另外向大家推荐使用glzjin大大的魔改版,Git链接:https://github.com/glzjin/ss-panel-v3-mod

sspanelV3目前是基于mvc结构,我所讲述的也是基于V3的修改。mvc大家应该都很了解,分为model( 模型)、view(界面)、controller(控制器)三个模块,model是数据模型,和数据库关联,view是界面,展示我们所看到的直观界面,controller是控制器,完成逻辑判断,并且可以传递动态数据到view中实现界面数据的变更。这里就不再对mvc做过多陈述,不清楚的可以查阅相关资料。

首先,我们来看一下sspanel的目录结构

《sspanel进阶——修改属于自己的sspanel站点》

其中有几个文件夹分别需要我们注意的,第一个是public,我们知道在配置过程中,项目的根目录指向的就是这个文件夹,其次分别是app(controller、model源码目录),resource(资源文件目录)

本期只讲述最基本的view修改方法,控制代码以及数据库等将在以后几期具体讨论

sspanel的view资源文件存放在resource/view目录中,

《sspanel进阶——修改属于自己的sspanel站点》

文件夹以及文件命名很规范,很容易就可以找到对应的页面,打开主页源码index.tpl,这是基于html的网页源码,在开头及结尾处引用了两个文件,header.tpl、footer.tpl,把其中源码加入连贯起来就是一个完整的html网页,当然其中还包含了部分PHP源码

{include file='header.tpl'}
<div class="section no-pad-bot" id="index-banner">
    <div class="container">
        <br><br>
        <h1 class="header center orange-text">{$config["appName"]}</h1>
        <div class="row center">
            <h5 class="header col s12 light">轻松科学上网   保护个人隐私</h5>
            {$homeIndexMsg}
        </div>
        {if $user->isLogin}
            <div class="row center">
                <a href="/user" id="download-button" class="btn-large waves-effect waves-light orange">进入用户中心</a>
            </div>
        {else}
        <div class="row center">
            <a href="/auth/register" id="download-button" class="btn-large waves-effect waves-light orange">立即注册</a>
        </div>
        {/if}
        <br><br>
    </div>
</div>
<div class="container">
    <div class="section">
        <!--   Icon Section   -->
        <div class="row">
            <div class="col s12 m4">
                <div class="icon-block">
                    <!-- To be compatible with some old browsers(especially mobile browsers), use  instead of flash_on. For more information visit the link below.
                    http://google.github.io/material-design-icons/#using-the-icons-in-html
                    -->
                    <h2 class="center light-blue-text"><i class="material-icons"></i></h2>
                    <h5 class="center">Super Fast</h5>
                    <p class="light">
                        Bleeding edge techniques using Asynchronous I/O and Event-driven programming.
                    </p>
                </div>
            </div>
            <div class="col s12 m4">
                <div class="icon-block">
                    <!-- To be compatible with some old browsers(especially mobile browsers), use  instead of group. For more information visit the link below.
                    http://google.github.io/material-design-icons/#using-the-icons-in-html
                    -->
                    <h2 class="center light-blue-text"><i class="material-icons"></i></h2>
                    <h5 class="center">Open Source</h5>
                    <p class="light">
                        Totally free and open source. A worldwide community devoted to deliver bug-free code and long-term support.
                    </p>
                </div>
            </div>
            <div class="col s12 m4">
                <div class="icon-block">
                    <!-- To be compatible with some old browsers(especially mobile browsers), use  instead of settings. For more information visit the link below.
                    http://google.github.io/material-design-icons/#using-the-icons-in-html
                    -->
                    <h2 class="center light-blue-text"><i class="material-icons"></i></h2>
                    <h5 class="center">Easy to work with</h5>
                    <p class="light">
                        Avaliable on multiple platforms, including PC, MAC, Mobile (Android and iOS) and Routers (OpenWRT).
                    </p>
                </div>
            </div>
        </div>
    </div>
    <br><br>
    <div class="section">
    </div>
</div>
{include file='footer.tpl'}

 

header

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0"/>
    <title>{$config["appName"]}</title>
    <!-- CSS fonts.googleapis.com -->
    <link href="//fonts.lug.ustc.edu.cn/icon?family=Material+Icons" rel="stylesheet">
    <link href="/assets/materialize/css/materialize.min.css" type="text/css" rel="stylesheet" media="screen,projection"/>
    <link href="/assets/materialize/css/style.css" type="text/css" rel="stylesheet" media="screen,projection"/>
</head>
<body>
<nav class="light-blue lighten-1" role="navigation">
    <div class="nav-wrapper container"><a id="logo-container" href="/" class="brand-logo">{$config["appName"]}</a>
        <ul class="right hide-on-med-and-down">
            <li><a href="/">首页</a></li>
            <li><a href="https://shadowsocks.org/en/download/clients.html">客户端下载</a></li>
            <li><a href="/code">邀请码</a></li>
            {if $user->isLogin}
                <li><a href="/user">用户中心</a></li>
                <li><a href="/user/logout">退出</a></li>
            {else}
                <li><a href="/auth/login">登录</a></li>
                <li><a href="/auth/register">注册</a></li>
            {/if}
        </ul>
        <ul id="nav-mobile" class="side-nav">
            <li><a href="/">首页</a></li>
            <li><a href="https://shadowsocks.org/en/download/clients.html">客户端下载</a></li>
            <li><a href="/code">邀请码</a></li>
            {if $user->isLogin}
                <li><a href="/user">用户中心</a></li>
                <li><a href="/user/logout">退出</a></li>
            {else}
                <li><a href="/auth/login">登录</a></li>
                <li><a href="/auth/register">注册</a></li>
            {/if}
        </ul>
        <!-- To be compatible with some old browsers(especially mobile browsers), use  instead of menu. For more information visit the link below.
         http://google.github.io/material-design-icons/#using-the-icons-in-html
         -->
        <a href="#" data-activates="nav-mobile" class="button-collapse"><i class="material-icons"></i></a>
    </div>
</nav>

 

在header.tpl中我们可以找到这段代码

<link href="/assets/materialize/css/materialize.min.css" type="text/css" rel="stylesheet" media="screen,projection"/>
    <link href="/assets/materialize/css/style.css" type="text/css" rel="stylesheet" media="screen,projection"/>

 

这里引用了两个css样式文件,需要注意的是,项目的根目录是是public,这里引用的相对路径全是基于public目录,我们可以在public下找到对应的目录以及文件,如果需要增加或者修改css样式那么就可以定位到改目录进行增改,如果需要增加css样式文件,也别忘记在header.tpl中加入新的link引用。在footer文件中,包含了js引用,修改方法同header文件。

这样一来,修改view对于有html基础的人来说很简单,只需要按照html规则修改,就可以修改出自己满意的界面。界面的事还是交给UI美工妹子吧(雾)

回到index. tpl,第五行

<h1 class=”header center orange-text”>{$config[“appName”]}</h1>

{$config[“appName”]},这里是php的语法,作用是获取config对象的appname元素的值,将它显示在html中,config对象是由控制器传递过来,暂时我们只需要明白它的意义即可。

我们知道ssapnelV3是基于mvc架构,页面的访问并不是直接访问到页面文件,而是由controller处理后再返回的html源码。我也提及到,网页的根目录是public,不过关于页面定向的实际处理文件是的app文件夹下的routes.PHP(不同魔改版本位置略有差异,例如glzjin的魔改版本位置是config文件夹下)具体位置可以在public的index.php中找到

<?php
//  PUBLIC_PATH
define('PUBLIC_PATH', __DIR__);
// Bootstrap
require PUBLIC_PATH . '/../bootstrap/app.php';
// Build Slim App
$app = require BASE_PATH . '/app/routes.php';
// Run ButterFly!
$app->run();

 

这里的routes.php是在app目录下,打开这个文件

<?php
use App\Controllers;
use App\Middleware\Admin;
use App\Middleware\Api;
use App\Middleware\Auth;
use App\Middleware\Guest;
use App\Middleware\Mu;
use Slim\App;
use Zeuxisoo\Whoops\Provider\Slim\WhoopsMiddleware;
/***
 * The slim documents: http://www.slimframework.com/docs/objects/router.html
 */
// config
$debug = false;
if (defined("DEBUG")) {
    $debug = true;
}
// Make a Slim App
// $app = new App($c)
$app = new App([
    'settings' => [
        'debug' => $debug,
        'whoops.editor' => 'sublime'
    ]
]);
$app->add(new WhoopsMiddleware);
// Home
$app->get('/', 'App\Controllers\HomeController:index');
$app->get('/code', 'App\Controllers\HomeController:code');
$app->get('/tos', 'App\Controllers\HomeController:tos');
$app->get('/debug', 'App\Controllers\HomeController:debug');
$app->post('/debug', 'App\Controllers\HomeController:postDebug');
//$app->get('/about', 'App\Controllers\HomeController:about');
$app->get('/client', 'App\Controllers\HomeController:client');
$app->get('/nodeList', 'App\Controllers\UserController:nodeList');
// User Center
$app->group('/user', function () {
    $this->get('', 'App\Controllers\UserController:index');
    $this->get('/', 'App\Controllers\UserController:index');
    $this->post('/checkin', 'App\Controllers\UserController:doCheckin');
    $this->get('/node', 'App\Controllers\UserController:node');
    $this->get('/node/{id}', 'App\Controllers\UserController:nodeInfo');
    $this->get('/profile', 'App\Controllers\UserController:profile');
    $this->get('/invite', 'App\Controllers\UserController:invite');
    $this->post('/invite', 'App\Controllers\UserController:doInvite');
    $this->get('/edit', 'App\Controllers\UserController:edit');
    $this->post('/password', 'App\Controllers\UserController:updatePassword');
    $this->post('/sspwd', 'App\Controllers\UserController:updateSsPwd');
    $this->post('/method', 'App\Controllers\UserController:updateMethod');
    $this->get('/sys', 'App\Controllers\UserController:sys');
    $this->get('/trafficlog', 'App\Controllers\UserController:trafficLog');
    $this->get('/kill', 'App\Controllers\UserController:kill');
    $this->post('/kill', 'App\Controllers\UserController:handleKill');
    $this->get('/logout', 'App\Controllers\UserController:logout');
})->add(new Auth());

 

最上层引用了controller的目录,如果自己有新增的目录,也要引用进来,我们可以看到注释 //home、//user Center,其下分别是主页这一块的页面、用户中心这一块的页面,$app->group(‘/user’, function () {起到了一个分组的作用,在这个组里是以/user为根路径,例如www.baidu.com,指向的是home,www.baidu.com/user,指向的就是user下的处理。

这个是我修改后的代码,所以能够看到新增的两行

$app->get(‘/client’, ‘App\Controllers\HomeController:client’);
$app->get(‘/nodeList’, ‘App\Controllers\UserController:nodeList’);

如果在浏览器中访问www.baidu.com/client,那么这个路径就会由App\Controllers\HomeController:client这个方法去处理,HomeController就是页面的控制器,按图索骥找到app\controller下的源码文件

/**
 *  HomeController
 */
class HomeController extends BaseController
{
    public function index()
    {
        $homeIndexMsg = DbConfig::get('home-index');
        return $this->view()->assign('homeIndexMsg', $homeIndexMsg)->display('index.tpl');
    }
    public function code()
    {
        $msg = DbConfig::get('home-code');
        $codes = InviteCode::where('user_id', '=', '0')->take(10)->get();
        return $this->view()->assign('codes', $codes)->assign('msg', $msg)->display('code.tpl');
    }
    public function debug($request, $response, $args)
    {
        $server = [
            "headers" => $request->getHeaders(),
            "content_type" => $request->getContentType()
        ];
        $res = [
            "server_info" => $server,
            "ip" => Http::getClientIP(),
            "version" => Config::get('version'),
            "reg_count" => Check::getIpRegCount(Http::getClientIP()),
        ];
        Logger::debug(json_encode($res));
        return $this->echoJson($response, $res);
    }
    public function tos()
    {
        return $this->view()->display('tos.tpl');
    }
    public function client()
    {
        return $this->view()->display('client.tpl');
    }

 

最后一行可以找到我加入代码引用的client方法,返回了client.tpl这个页面,这里并没有代码的处理,只是简单的返回了一个静态页面,如果按照我的写法,那么我们就新增了一个client页面,通过www.baidu.com/client.tpl可以访问到这个页面(别忘了把百度换成你自己的域名)。可能有人会疑惑,$this->view()->display(‘client.tpl’);我的client.tpl界面在哪里,这里的view对象是在HomeController继承的BaseController中所定义的,上一章我说了view资源文件的位置,具体的view引用和app\Services\View.php有关,作者在其中有相应注释,有兴趣的道友可以去看一下,这里不再讲解。这里也可以新增一个api方法,不返回页面,代码雷同

public function debug($request, $response, $args)
{
    $server = [
        "headers" => $request->getHeaders(),
        "content_type" => $request->getContentType()
    ];
    $res = [
        "server_info" => $server,
        "ip" => Http::getClientIP(),
        "version" => Config::get('version'),
        "reg_count" => Check::getIpRegCount(Http::getClientIP()),
    ];
    Logger::debug(json_encode($res));
    return $this->echoJson($response, $res);
}

 

可以获取请求的参数,处理后通过response返回json或其他格式数据。

上面我们新增了一个静态页面,如果要加一个动态页面那该如何?上段代码中,有个主页的index方法

public function index()
{
    $homeIndexMsg = DbConfig::get('home-index');
    return $this->view()->assign('homeIndexMsg', $homeIndexMsg)->display('index.tpl');
}

 

->assign(‘homeIndexMsg’, $homeIndexMsg)这个方法就是向view传递数据对象,类似于map键值对,键是homeIndexMsg,值是$homeIndexMsg对象,在对应的index.tpl中就可以通过键引用到对象的值

<div class="section no-pad-bot" id="index-banner">
    <div class="container">
        <br><br>
        <h1 class="header center orange-text">{$config["appName"]}</h1>
        <div class="row center">
            <h5 class="header col s12 light">轻松科学上网   保护个人隐私</h5>
            {<span style="color:#ff0000;">$homeIndexMsg</span>}
        </div>
        {if $user->isLogin}
            <div class="row center">
                <a href="/user" id="download-button" class="btn-large waves-effect waves-light orange">进入用户中心</a>
            </div>
        {else}
        <div class="row center">
            <a href="/auth/register" id="download-button" class="btn-large waves-effect waves-light orange">立即注册</a>
        </div>
        {/if}
        <br><br>
    </div>
</div>

 

想必有人会疑惑,我们看到了传入的对象被引用,还有另外两个对象config、user,并没有看见传入,这两个对象是在view中被默认传入的,在所有页面中都可以直接调用,打开app\Services\View.php就可以看到对应的代码,在//add config注释下面几行,将这些配置信息以及个人信息传入

<?php
namespace App\Services;
use Smarty;
class View
{
    public static function getSmarty(){
        $smarty=new smarty(); //实例化smarty
        $smarty->settemplatedir(BASE_PATH.'/resources/views/'.Config::get('theme').'/'); //设置模板文件存放目录
        $smarty->setcompiledir(BASE_PATH.'/storage/framework/smarty/compile/'); //设置生成文件存放目录
        $smarty->setcachedir(BASE_PATH.'/storage/framework/smarty/cache/'); //设置缓存文件存放目录
        // add config
        $smarty->assign('config',Config::getPublicConfig());
        $smarty->assign('user',Auth::getUser());
        $smarty->assign('analyticsCode',DbConfig::get('analytics-code'));
        return $smarty;
    }
}

 

本章讲到这里,下一章会阐述模型的修改以及数据库相关。诸位快行动起来,拆了重建,搞搞大新闻,想必是极好的。

 

本文出自:

http://blog.csdn.net/w2180z/article/details/53405870

http://blog.csdn.net/w2180z/article/details/53579495

点赞
  1. LIFEHACKER说道:

    厉害!要好好学习一下。

    1. 谢谢!大家觉得有帮助就好。

  2. victim说道:

    博主,您能写一下配置邮箱的教程吗?使用阿里云smtp或者mailyun的,谢谢您

    1. 您好,我用的是mailgun,网上教程蛮多的。本站教程:
      https://www.ccino.org/several-scenarios-for-creating-personalized-domain-name-mailbox.html
      您也试试?有问题的话告诉我?

发表评论

电子邮件地址不会被公开。 必填项已用*标注