tryer 发布的文章

DophinPHP(海豚PHP)是一个基于ThinkPHP5.0.24开发的一套开源PHP快速开发框架,DophinPHP秉承极简、极速、极致的开发理念,为开发集成了基于数据-角色的权限管理机制,集成多种灵活快速构建工具,可方便快速扩展的模块、插件、钩子、数据包。统一了模块、插件、钩子、数据包之间的版本和依赖关系,进一步降低了代码和数据的冗余,以方便开发者快速构建自己的应用。

表单,表单构建器

使用DophinPHP(海豚PHP)自主开发的ZBuilder类,您可以轻松的应对复杂多变的表单、数据列表。数据列表集成类似EXCEL的快速筛选、排序、模糊搜索、AJAX编辑等功能,表单页集成常用的文本、下拉框、单选、多选、关键词、编辑器、文件上传、图片上传、图片裁切等控件,除此之外,您还可以灵活的扩展自己的控件,以便在自己的项目中重复使用。ZBuilder让您更加专注业务逻辑。

快速开发流程:建立数据库 > 新建控制器、模型、验证器 > 构建器快速生成表单、数据列表 > 添加业务逻辑
不需要在构建界面、通用代码等细节中浪费时间,快速实现系统功能,爽。

扩展html,js

构建器中可以定义扩展HTML,JS,相互配合可以实现丰富的页面交互功能,补充构建器复杂业务需求。

  1. 扩展js 实现动态添加表单元素
  2. 搜索区域的下拉联动

搜索区域

重设$map条件,有时候搜索区域的字段并不是实际的字段,需要做一些判断处理,并将搜索区域传过来的字段注销,以免影响查询
unset($map['']);

用户关联所属村居

多级用户 权限控制

 //村居只显示自己的信息
        if(session('user_auth.role') == 3){
            $map["v_id"] = session('user_auth.v_id');
        }

自动添加、自动编辑

追求极简的开发是DolphinPHP的核心思想之一,为了节省开发者的宝贵时间,我们为大家准备了一个神奇的方法,可以让开发者无需编写add方法也能实现创建表单和写入数据。
对于一些简单的数据,没有复杂的处理逻辑只是简单的crud,可以用自动添加、自动编辑功能快速实现,神奇!

select2的技巧

全选,联动,动态追加,提交判断

$(function(){

    //全局变量
    var count=1;
    var mselect = $("#members").select2();
    var btn = "<a id='allmember' class='btn btn-default'>选中全体人员</a>";

    $("#members").after(btn);

    $("#allmember").click(function() {
        mselect.val(allmember).trigger("change");
        mselect.change();
        //设置参会人员,重置选项
        resetSelect();
    });

    //改变参会人员选项
    $("#members").on("change",function () {
        //alert(mselect.val());
        //改变所有的下拉选项 事件处理
        resetSelect();
    });

    $("#members").change(function () {
        resetSelect();
    });

    //动态添加表决事项
    $("#additem").click(function() {
        //alert(count);
        count++;
        $(this).parent().parent().before(getHtml(count));
        //初始化选项
        $("#agreed" + count).append($("#agreed1").find("*").clone(true));
        //设置表决人员
        $("#agreed" + count).select2().val($("#agreed1").select2().val());
        resetSelect();
    });
    
    
    function resetSelect() {
       for (var i=1; i<=count;i++){
           $("#agreed" + i).select2().val(mselect.val());
       }
    }
    

    //追加表单
    function getHtml(ii) {
        var html = "";

        html += "  <div class=\"form-group col-lg-12 col-md-12 col-sm-12 col-xs-12 \" id=\"form_group_content" + ii +  "\">\n" +
            "    <label class=\"col-xs-12\" for=\"content" + ii + "\">表决事项内容" + ii + "</label>\n" +
            "    <div class=\"col-xs-12\">\n" +
            "        <textarea class=\"form-control\" id=\"content" + ii +  "\" rows=\"7\" name=\"content" + ii +  "\" placeholder=\"请输入表决事项内容\" ></textarea>\n" +
            "            </div>\n" +
            "</div>\n" +
            "                                                                                            \n" +
            "                                                <div class=\"form-group col-lg-12 col-md-12 col-sm-12 col-xs-12 \" id=\"form_group_result" + ii +  "\">\n" +
            "    <label class=\"col-xs-12\" for=\"result" + ii +  "\">表决结果" + ii + "</label>\n" +
            "    <div class=\"col-sm-12\">\n" +
            "        \n" +
            "        <input class=\"form-control\" type=\"text\" id=\"result" + ii +  "\" name=\"result" + ii +  "\" value=\"\" placeholder=\"请输入表决结果\" >\n" +
            "\n" +
            "            </div>\n" +
            "</div>\n" +
            "                                                                                            \n" +
            "                                                <div class=\"form-group col-lg-12 col-md-12 col-sm-12 col-xs-12 \" id=\"form_group_agreed" + ii +  "\">\n" +
            "    <label class=\"col-xs-12\" for=\"agreed" + ii +  "\">参会人员表决通过人员" + ii + "</label>\n" +
            "    <div class=\"col-sm-12\">\n" +
            "        <select class=\"js-select2 form-control\" id=\"agreed" + ii +  "\" name=\"agreed" + ii +  "[]\" data-allow-clear=\"true\" data-placeholder=\"请选择一项或多项\" multiple=\"multiple\" multiple>\n" +
            "                    </select>\n" +
            "            </div>\n" +
            "</div>\n";

        return html;
    }


    //提交判断 获取表决事项数量值
    $(".ajax-post").click( function () {

        if($("#members").select2().val()){
            ch = $("#members").select2().val().length;
        }
        else
        {
            layer.msg('请选择参会人员', {icon: 5});
            return false;
        }


        if($("#cw_title").val() == ""){
            layer.msg('请填写村务会议主题', {icon: 5});
            return false;
        }

        //判断
        if((ch / allmember.length) < 2/3){
            layer.msg('参会人员不达标,无法提交', {icon: 5});
            return false;
        }

        if($("#content1").val() == ""){
            layer.msg('请至少填写一项表决事项', {icon: 5});
            return false;
        }

        //追加事项数量的元素
        $(this).before("<input type='hidden' name='maxitem' id='maxitem' />");
        $("#maxitem").val(count);
        //alert($("#maxitem").val());
        //return false;
    } );

});

联动效果

//事件绑定
$(function () {

    //先把所有的村缓存起来
    //镇办更新的时候
    $("#search_town").on("change", function (e) {
        //获取镇办选择项
        var town = $("#search_town option:checked").val();
        
        //取出相应的村名 并重置选项 town为空的情况 全部村名
        //alert(town);
        $.get("/admin.php/wsgk/cunju/getcunju.html", {town: town},
            function (data) {
                //清空月份
                $("#search_v_id").select2().empty();
                $("#search_v_id").select2({data: null});

                var itemList = [];
                for (var i = 0; i < data.length; i++) {
                    itemList.push({id: data[i].id, text: data[i].text})
                }

                $('#search_v_id').select2({
                    placeholder: '请选择',
                    language: "zh-CN",
                    data: itemList
                });
                $('.select2').width('100%');

            });
    })


});

修改、删除操作申请与审核

二维码海报合成

图片处理库Grafika,二维码生成库, composer安装,依赖的管理,自动添加自动载入机制

function getQrBanner($vid)
{

    $result = Db::view('wsgk_village','vname')
        ->view('wsgk_town','name,jwcontact','wsgk_town.id=wsgk_village.town')
        ->where('wsgk_village.id',$vid)
        ->find();

    $name = $result['vname'];
    $town = $result['name'];
    $tel = $result['jwcontact'];

    //看有没有二维码 有打开 没有生成,返回图像
    $erwima = config('upload_path') . DS . "qrcode/" . $vid .  "_qrcode.png";
    if(!file_exists($erwima))
    {
        create_qrcode($vid);
    }

    $editor = Grafika::createEditor();
    $editor->open($image , 'bg.jpg');
//合成上二维码
    $editor->open($image2 , $erwima);
    $editor->blend ( $image, $image2 , 'normal', 1, 'top-left',520,480);
//画圆
    $drawingObject = Grafika::createDrawingObject('Ellipse', 150, 150, array(770,730), 1, new Color('#edf4ed'), new Color('#edf4ed'));
    $editor->draw( $image, $drawingObject );
//根据字的多少来计算x的位置 一个字多宽 770-50
    $editor->text($image ,$name,30,830 - ((strlen($name) / 3 / 2) * 30),790,new Color("#f27113"),config('upload_path') . DS . "qrcode/qr.ttf",0);
    $editor->text($image ,'如有问题,请向' . $town . '纪委举报,电话:' . $tel,30,400,2200,new Color("#ffffff"),config('upload_path') . DS . "qrcode/qr.ttf",0);
//保存
    $editor->save($image,config('upload_path') . DS . "qrcode/" . $vid . '_banner.png');
}
//生成二维码图片

function create_qrcode($vid)
{

    //获取村名信息
    $vinfo = Db::name("wsgk_village")->where("id",$vid)->find();

    $url = "http://wsgk.zbsylxh.com/index.php?vid=" . $vid;
    $qrCode = new QrCode();
    $qrCode->setText($url)
        ->setSize(650)
        ->setPadding(10)
        ->setErrorCorrection('high')
        ->setForegroundColor(array('r' => 0, 'g' => 0, 'b' => 0, 'a' => 0))
        ->setBackgroundColor(array('r' => 255, 'g' => 255, 'b' => 255, 'a' => 0))

        ->setImageType(\Endroid\QrCode\QrCode::IMAGE_TYPE_PNG);


    $file_name = config('upload_path') . DS . "qrcode/" . $vid .  "_qrcode.png";
    $qrCode->save($file_name);
    return true;

}

搜索区域的下拉框多选

海豚PHP搜索区域的下拉框默认是不支持多选的,需要通过自定义模板、扩展JS等来实现

  1. 复制默认的builder\table\layout.html模板到控制器对应的VIEW目录中
  2. 修改模板中的搜索区域的select处理代码 添加multiple="multiple"
  3. 添加相应的扩展JS,处理搜索区域的SUBMIT处理事件及下拉框的联动逻辑,参考代码

    // @tofishes
    // var params = $('form').paramMap();  就可以获得整个表单的所有参数
    $.fn.paramMap = function (opts) {
        opts = $.extend({
            'separator': ',' // 同名参数的分隔符,多用于checkbox的值
        })
    
        var params = this.serializeArray()
            ,   paramMap = {}
    
            ,   i = 0
            ,   l = params.length
            ,   param;
    
        for (; i < l; i++) {
            param = params[i];
    
            if (paramMap[param.name]) {
                paramMap[param.name] += opts.separator + param.value;
            } else {
                paramMap[param.name] = param.value;
            }
        };
    
        return paramMap;
    };
    
    
    // 搜索区域
    $('#search-area-project').submit(function () {
        var items = $('#search-area-project').paramMap();
        var op  = $('#_o').val();
        var str = [];
        $.each(items, function (index, e) {
            str.push(index + '=' + e)
        });
        str = str.join('|');
        location.href = $(this).attr('action')+'?_s='+str+'&_o='+op;
        return false;
    });
    
    
    
    //事件绑定
    $(function () {
    
        //导出处理
        $("#exportbtn").on("click",function (e) {
            var items = $('#search-area-project').paramMap();
            var op  = $('#_o').val();
            var str = [];
            $.each(items, function (index, e) {
                str.push(index + '=' + e)
            });
            str = str.join('|');
            str1 = '/index.php/iot/data/export.html?_s='+str+'&_o='+op;
            //alert(str1);
            window.open(str1)
            //location.href = str1;
            return false;
        })
    
    
        //根据项目获取设备及变量
        $("#search_device_project_id").on("change", function (e) {
            //获取项目选择项
            var project_id = $("#search_device_project_id option:checked").val();
            //取出相应的从机 并重置选项 设备为空的情况 全部从机
            //alert(town);
            $.get("/index.php/iot/device/getdevicebyproject.html", {project_id: project_id},
                function (data) {
                    //初始化设备
                    $("#search_data_device_id").select2().empty();
                    $("#search_data_device_id").select2({data: null});
    
                    //初始化数据选项
                    var itemList = [];
                    //alert(data.device.length);
                    for (var i = 0; i < data.device.length; i++) {
                        itemList.push({id: data.device[i].id, text: data.device[i].text})
                    }
    
                    $('#search_data_device_id').select2({
                        placeholder: '请选择设备',
                        language: "zh-CN",
                        data: itemList
                    });
    
                    //初始化变量
                    $("#search_data_name").select2().empty();
                    $("#search_data_name").select2({data: null});
    
                    //初始化数据选项
                    var itemList1 = [];
                    for (var i = 0; i < data.data_name.length; i++) {
                        itemList1.push({id: data.data_name[i], text: data.data_name[i]})
                    }
    
                    $('#search_data_name').select2({
                        placeholder: '请选择变量',
                        language: "zh-CN",
                        data: itemList1
                    });
    
    
    
                    $('.select2').width('100%');
    
    
                });
        })
    
    
    });

最近学习流行的vue框架,开发体验确实爽,找到了当年初识jquery时的恋爱感觉

与jquery比较

vue与jquery开发方式优势何在?思想要做什么转变?通过实现相同功能的代码对比,直观的观察一下
组件化带来的革命 与es6 sass预处理器 webpack 模块化开发 带来的生产力 分工协作的革命

核心原理

vue数据响应的核心是利用了 Object.defineProperty() 对数据进行劫持,并通过订阅,传递数据,最终进行update。
简化的vue原理代码 剖析Vue实现原理 - 如何实现双向绑定mvvm

知识体系

vue vue route vuex 服务器端渲染 第三方组件

学习路线

请输入图片描述

资源推荐

视频课程,可以直观的看到vue的开发过程与工具链,配套软件的使用 现在网上教育,网课确实是学习的好方式,倍速播放更是加快学习效率

  1. 慕课网 免费课程 《3小时速成 Vue2.x 核心技术
  2. 腾讯课堂 免费Vue全家桶宝洁SFA项目
  3. 非常简单的一个vue2 + vuex的项目,整个流程一目了然,麻雀虽小,五脏俱全,适合作为入门练习

变更提升

JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部:

'use strict';

function foo() {
    var x = 'Hello, ' + y;
    console.log(x);
    var y = 'Bob';
}

foo();

虽然是strict模式,但语句var x = 'Hello, ' + y;并不报错,原因是变量y在稍后申明了。但是console.log显示Hello, undefined,说明变量y的值为undefined。这正是因为JavaScript引擎自动提升了变量y的声明,但不会提升变量y的赋值。

对于上述foo()函数,JavaScript引擎看到的代码相当于:

function foo() {
    var y; // 提升变量y的申明,此时y为undefined
    var x = 'Hello, ' + y;
    console.log(x);
    y = 'Bob';
}

JavaScript的这一怪异的“特性”,要倍加注意小心。

全局作用域

不在任何函数内定义的变量就具有全局作用域。实际上,JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性

JS的命名空间

全局变量会绑定到window上,不同的JavaScript文件如果使用了相同的全局变量,或者定义了相同名字的顶层函数,都会造成命名冲突,并且很难被发现。

减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中。例如:

// 唯一的全局变量MYAPP:
var MYAPP = {};

// 其他变量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;

// 其他函数:
MYAPP.foo = function () {
    return 'foo';
};

把自己的代码全部放入唯一的名字空间MYAPP中,会大大减少全局变量冲突的可能。

解构赋值

var [x, y, z] = ['hello', 'JavaScript', 'ES6'];

直接对多个变量进行声明和赋值

this 大坑

在一个方法内部,this是一个特殊变量,它始终指向当前对象,JavaScript的函数内部如果调用了this,那么这个this到底指向谁?

答案是,视情况而定!

如果以对象的方法形式调用,比如xiaoming.age(),该函数的this指向被调用的对象,也就是xiaoming,这是符合我们预期的。

如果单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window。

function getAge() {
    var y = new Date().getFullYear();
    return y - this.birth;
}

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};

xiaoming.age(); // 25, 正常结果
getAge(); // NaN

this指针只在age方法的函数内指向xiaoming,在函数内部定义的函数,this又指向undefined了!(在非strict模式下,它重新指向全局对象window!)

所以在函数内部定义的函数 this可以用that的方法来解决。

'use strict';

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var that = this; // 在方法内部一开始就捕获this
        function getAgeFromBirth() {
            var y = new Date().getFullYear();
            return y - that.birth; // 用that而不是this
        }
        return getAgeFromBirth();
    }
};

xiaoming.age(); // 25

用var that = this;,你就可以放心地在方法内部定义其他函数,而不是把所有语句都堆到一个方法中。

pbootcms是与aspcms一家公司开发的企业网站系统,非常完美的企业网站系统,功能齐全,方便灵活,支持sqlite/mysql数据库

模板中支持简单的php语句

 {php}echo 111+222;{/php}

数据库快速操作类 类似THINKPHP框架的方式 比较容易上手

引入命名空间
use core\basic\Model;
use core\basic\Db;

$a = Db::table('ay_content')->where('id=1')->find();
var_dump($a); 
$model = new Model();
$r = $model->table('ay_content')->where('id=1')->find();
var_dump($r);

以上两种是等价的,第一种Db通过__callstatic静态魔术方法来调用Model类的方法

pbootcms导入其它数据库的信息

public function importold()
{
    exit('已經導入新聞');
    set_time_limit(0);
    $data = json_decode('{"acode":"cn","scode":"16","subscode":"","title":"\u6807\u9898","titlecolor":"#333333","subtitle":"","filename":"","author":"admin","source":"\u672c\u7ad9","outlink":"","date":"2018-12-30 10:45:46","ico":"\/static\/upload\/image\/20181230\/1546137994102175.png","pics":"\/static\/upload\/image\/20181230\/1546138005227320.png,\/static\/upload\/image\/20181230\/1546138006814526.png","content":"<p>\u5185\u5bb9<\/p>","enclosure":"","keywords":"","description":"\u5185\u5bb9","sorting":255,"status":"1","istop":0,"isrecommend":0,"isheadline":0,"visits":0,"likes":0,"oppose":0,"create_user":"admin","update_user":"admin"}',true);
    //var_dump($data);die();

    //对应关系数组 文章 产品 单页

    $relation =  array(
        1   =>  16,
        3   =>  12,
        6   =>  38,
        8   =>  35,
        10  =>  18,
        13  =>  25,
        15  =>  31,
        18  =>  13,
        20  =>  14,
        31  =>  22,
        33  =>  27,
        34  =>  33
    );

    $i = 0;
    //php访问mdb 数据库
    //成功导入数据1611条
    $connstr = "DRIVER=Microsoft Access Driver (*.mdb);DBQ=#Database#.mdb";
    $connid = @odbc_connect($connstr,"","",SQL_CUR_USE_ODBC ) or die ("数据库连接错误!");
    $sql = "select * from jtbc_articles";
    $exec = odbc_exec($connid,$sql);
    while($row = odbc_fetch_array($exec))
    {
        //重置这些内容 以免下一个
        $data['ico'] = '';
        $data['pics'] = '';
        if(isset($relation[$row['a_class']]) && $row['a_id'] != 540) {
            //有相应的栏目对应关系的话
            $data['scode'] = $relation[$row['a_class']];
            $data['title'] = escape_string(iconv('gb2312', 'utf-8', $row['a_topic']));
            $data['content'] = iconv('gb2312', 'utf-8', $row['a_content']);
            $data['content'] = escape_string(str_replace('{$->>repath}articles/common/upload/', '/static/upload/', $data['content']));
            $data['description'] = mb_substr(strip_tags($data['content']), 0, 150, 'utf-8');
            $data['date'] = $row['a_time'];
            $data['visits'] = $row['a_count'];

            if ($row['a_content_images'] != '') {
                if (strpos($row['a_content_images'], '|') !== false) {
                    $data['pics'] = str_replace('|', ',', $row['a_content_images']);
                    $data['pics'] = str_replace('common/upload/', '/static/upload/', $data['pics']);
                    $data['ico'] = explode(',', $data['pics'])[0];
                } else {
                    $data['ico'] = $row['a_content_images'];
                }
            }

            //var_dump($data);
            //exit();
            if (! ! $id = $this->model->addContent($data)) {
                $i++;
            }

        }
    }
    echo "成功导入数据" . $i  .   '条';
}

先断点获取到输入文章时的数组,每条导入数据只需要赋值需要变更的部分,注意每次重置数据项为空

碰到的大坑
php odbc连接 查询显示不完整问题
在php.ini里找到[ODBC] 下面有odbc.defaultlrl = 4096 你改正你想要设置 的大小就ok

Kernel文件解密 仅供学习

<?php 
/**
 * @copyright (C)2016-2099 Hnaoyun Inc.
 * @license This is not a freeware, use is subject to license terms
 * @author XingMeng
 * @email hnxsh@foxmail.com
 * @date 2018-08-09 16:03:55
 *  翱云科技版权所有,除本授权文件其余代码均开源,未经许可擅自破解本文件将依法追究法律责任。
 */


namespace core\basic;
class Kernel
{
    private static $controllerPath;

    public static function run()
    {
        //self::license();
        self::loadCache();
        $path_info = self::getPathInfo();
        $path_info = self::urlBlind($path_info);
        $path_info = self::urlRoute($path_info);
        $access_path = self::getAccessPath($path_info);
        self::regAppPath($access_path);
        self::loadComm();
        self::loadController();
    }

    private static function getPathInfo()
    {
        if (isset($_SERVER['PATH_INFO']) && !mb_check_encoding($_SERVER['PATH_INFO'], 'utf-8')) {
            $_SERVER['PATH_INFO'] = mb_convert_encoding($_SERVER['PATH_INFO'], 'UTF-8', 'GBK');
        }
        if (isset($_SERVER['PATH_INFO'])) {
            $path_info = $_SERVER['PATH_INFO'];
        } elseif (isset($_SERVER["REDIRECT_URL"])) {
            $path_info = str_replace('/' . basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['REDIRECT_URL']);
            $path_info = str_replace(SITE_DIR, '', $path_info);
            $_SERVER['PATH_INFO'] = $path_info;
        } elseif (isset($_GET['s'])) {
            $path_info = $_GET['s'];
        } else {
            $path_info = '';
        }
        if ($path_info) {
            $pattern = '{^\/?([\x{4e00}-\x{9fa5}\w-\/\.' . Config::get('url_allow_char') . ']+?)?\/?$}u';
            if (preg_match($pattern, $path_info)) {
                $path_info = preg_replace($pattern, '$1', $path_info);
                $url_html_suffix = Config::get('url_suffix');
                if (substr($path_info, -strlen($url_html_suffix)) == $url_html_suffix) {
                    $path_info = substr($path_info, 0, -strlen($url_html_suffix));
                }
            } else {
                error('您访问路径含有非法字符,防注入系统提醒您请勿尝试非法操作!');
            }
        }
        return $path_info;
    }

    private static function urlBlind($pathInfo)
    {
        $path = '';
        if (!!$domains = Config::get('app_domain_blind')) {
            $server_name = str_replace(':' . $_SERVER['SERVER_PORT'], '', $_SERVER['HTTP_HOST']);
            if (isset($domains[$server_name])) {
                $path = $domains[$server_name];
            }
        }
        if (defined('URL_BLIND')) {
            if ($path) {
                if (strpos($path, URL_BLIND) === false && strpos(URL_BLIND, $path) === false) {
                    error('系统配置的域名地址绑定与入口文件地址绑定冲突,请核对!');
                } elseif (strpos($path, URL_BLIND) === false && strpos(URL_BLIND, $path) !== false) {
                    $path = URL_BLIND;
                }
            } else {
                $path = URL_BLIND;
            }
        }
        if ($path) {
            $path = trim_slash($path) . '/' . $pathInfo;
        } else {
            $path = $pathInfo;
        }
        return $path;
    }

    private static function urlRoute($pathInfo)
    {
        if (!!$route = Config::get('url_route')) {
            if (!$pathInfo && isset($route['/'])) {
                return $route['/'];
            }
            foreach ($route as $key => $value) {
                $key = str_replace('/', '\\/', trim_slash($key));
                $reg = "{(.*\/|^)" . $key . "(\/.*|$)}Ui";
                if (preg_match($reg, $pathInfo)) {
                    $value = trim_slash($value);
                    $pathInfo = preg_replace($reg, "$1$value$2", $pathInfo);
                    break;
                }
            }
        }
        return $pathInfo;
    }

    private static function getAccessPath($pathInfo)
    {
        $apps = Config::get('public_app', true);
        if ($pathInfo) {
            $path_info = trim_slash($pathInfo);
            $path_array = explode('/', $path_info);
            $path_count = count($path_array);
            if ($path_count >= 3) {
                $access_path['m'] = $path_array[0];
                $access_path['c'] = $path_array[1];
                $access_path['f'] = $path_array[2];
                for ($i = 3; $i < $path_count; $i = $i + 2) {
                    if (isset($path_array[$i + 1])) {
                        $_GET[$path_array[$i]] = $path_array[$i + 1];
                    } else {
                        $_GET[$path_array[$i]] = null;
                    }
                }
            } elseif ($path_count == 2) {
                $access_path['m'] = $path_array[0];
                $access_path['c'] = $path_array[1];
            } elseif ($path_count == 1) {
                $access_path['m'] = $path_array[0];
            }
        }
        if (!isset($access_path['m'])) {
            $access_path['m'] = $apps[0];
        }
        if (!isset($access_path['c'])) {
            $access_path['c'] = 'Index';
        }
        if (!isset($access_path['f'])) {
            $access_path['f'] = 'index';
        }
        if (!in_array(strtolower($access_path['m']), $apps)) {
            error('您访问的模块' . $access_path['m'] . '未开放,请核对后重试!');
        }
        return $access_path;
    }

    private static function regAppPath($accessPath)
    {
        define('M', strtolower($accessPath['m']));
        self::$controllerPath = self::adjustController($accessPath['c']);
        if (!!$pos = strrpos(self::$controllerPath, '/')) {
            define('C', ucfirst(substr(self::$controllerPath, $pos + 1)));
            self::$controllerPath = substr(self::$controllerPath, 0, $pos + 1) . ucfirst(substr(self::$controllerPath, $pos + 1));
        } else {
            define('C', ucfirst(self::$controllerPath));
            self::$controllerPath = ucfirst(self::$controllerPath);
        }
        define('F', $accessPath['f']);
        if (isset($_SERVER["REQUEST_URI"])) {
            define('URL', $_SERVER["REQUEST_URI"]);
        } else {
            define('URL', $_SERVER["ORIG_PATH_INFO"] . '?' . $_SERVER["QUERY_STRING"]);
        }
        define('CORE_VERSION', Config::get('core_version'));
        define('APP_CONTROLLER_PATH', APP_PATH . '/' . M . '/controller');
        define('APP_MODEL_PATH', APP_PATH . '/' . M . '/model');
        if (($tpl_dir = Config::get('tpl_dir')) && array_key_exists(M, $tpl_dir)) {
            if (strpos($tpl_dir[M], ROOT_PATH) === false) {
                define('APP_VIEW_PATH', ROOT_PATH . $tpl_dir[M]);
            } else {
                define('APP_VIEW_PATH', $tpl_dir[M]);
            }
        } else {
            define('APP_VIEW_PATH', APP_PATH . '/' . M . '/view');
        }
    }

    private static function adjustController($string)
    {
        $string = str_replace('.', '/', $string);
        $string_arr = explode('_', $string);
        if (count($string_arr) > 1) {
            $count = count($string_arr);
            for ($i = 1; $i < $count; $i++) {
                $string_arr[$i] = ucfirst($string_arr[$i]);
            }
            $string = implode($string_arr);
        }
        return $string;
    }

    private static function loadComm()
    {
        Config::get('debug') ? Check::checkAppFile() : '';
        $app_config = APP_PATH . '/' . M . '/config/config.php';
        if (file_exists($app_config)) {
            Config::assign($app_config);
        }
        define('APP_VERSION', Config::get('app_version'));
        define('RELEASE_TIME', Config::get('release_time'));
        if (M == 'api') {
            if (!!$sid = request('sid')) {
                session_id($sid);
                session_start();
            }
            header("Access-Control-Allow-Origin: *");
        } else {
            if (!ini_get('session.auto_start') && !isset($_SESSION)) {
                session_start();
            }
            Check::checkBs();
            Check::checkOs();
        }
    }

    private static function loadController()
    {
        $class_file = self::$controllerPath . 'Controller.php';
        $class_file_path = APP_CONTROLLER_PATH . '/' . $class_file;
        $class_name = '\\app\\' . M . '\\controller\\' . str_replace('/', '\\', self::$controllerPath) . 'Controller';
        $function = F;
        if (!file_exists($class_file_path)) {
            header('HTTP/1.1 404 Not Found');
            header('status: 404 Not Found');
            $file_404 = ROOT_PATH . '/404.html';
            if (file_exists($file_404)) {
                require $file_404;
                exit();
            } else {
                error('对不起,您访问的页面不存在,请核对后再试!');
            }
        }
        if (!class_exists($class_name)) {
            error('类' . $class_name . '不存在!类文件' . $class_file_path . '中无法找到!');
        }
        $app_function = APP_PATH . '/' . M . '/function/function.php';
        if (file_exists($app_function)) {
            require $app_function;
        }
        if (file_exists(APP_PATH . '/common/function.php')) {
            require APP_PATH . '/common/function.php';
        }
        if (file_exists(APP_PATH . '/common/' . ucfirst(M) . 'Controller.php')) {
            $comm_class_name = '\\app\\common\\' . ucfirst(M) . 'Controller';
            $comm_class = new $comm_class_name();
        }
        $controller = new $class_name();
        if (method_exists($class_name, $function)) {
            if (strtolower($class_name) != strtolower($function)) {
                $return = $controller->$function();
            } else {
                $return = $controller;
            }
        } else {
            if (method_exists($class_name, '_empty')) {
                $return = $controller->_empty();
            } else {
                error('方法不存在!' . M . '模块下控制器文件' . $class_file . '中不存在您调用的方法' . $function . ',可能正在开发中,请耐心等待!');
            }
        }
        if ($return !== null) {
            Response::handle($return);
        }
    }

    private static function loadCache()
    {
        if (!Config::get('tpl_html_cache') || URL_BLIND == 'api') {
            return;
        }
        $lg = isset($_COOKIE['lg']) ? cookie('lg') : '';
        Config::get();
        $config_file = RUN_PATH . '/config/' . md5('config' . $lg) . '.php';
        if (!Config::assign($config_file)) {
            return;
        }
        $lg = $lg ?: Config::get('lgs.0.acode');
        if (Config::get('open_wap') && (is_mobile() || Config::get('wap_domain') == get_http_host())) {
            $wap = 'wap';
        } else {
            $wap = '';
        }
        $cache_file = RUN_PATH . '/cache/' . md5($_SERVER["REQUEST_URI"] . $lg . $wap) . '.html';
        if (file_exists($cache_file) && time() - filemtime($cache_file) < Config::get('tpl_html_cache_time')) {
            ob_start();
            include $cache_file;
            $content = ob_get_contents();
            ob_end_clean();
            if (Config::get('gzip') && !headers_sent() && extension_loaded("zlib") && strstr($_SERVER["HTTP_ACCEPT_ENCODING"], "gzip")) {
                $content = gzencode($content, 6);
                header("Content-Encoding: gzip");
                header("Vary: Accept-Encoding");
                header("Content-Length: " . strlen($content));
            }
            echo $content;
            exit();
        }
    }

    private static function license()
    {
        if (URL_BLIND == 'admin') {
            return;
        }
        if (!!$sn = Config::get('sn', true)) {
            $host = $_SERVER['HTTP_HOST'];
            $key = strtoupper(substr(md5(substr(sha1($host), 0, 10)), 10, 10));
            $sip = isset($_SERVER['LOCAL_ADDR']) ? $_SERVER['LOCAL_ADDR'] : $_SERVER['SERVER_ADDR'];
            if ($sip != '::1' && substr($sip, 0, 6) != '127.0.' && !in_array($key, $sn)) {
                error('未匹配到本域名有效授权码,请到<a href="http://www.pbootcms.com" target="_blank">PbootCMS</a>官网获取,并填写到后台"全局配置>>配置参数"中。');
            }
        } else {
            error('配置文件中授权码为空,请到<a href="http://www.pbootcms.com" target="_blank">PbootCMS</a>官网获取,并填写到后台"全局配置>>配置参数"中。');
        }
    }
}

有子分类调用子分类 没有子分类显示同级分类

修改标签解析控制器方法 ParserController.php中的 paseSortLabel,添加case分支

case 'soncount':
                        $content = str_replace($matches[0][$i], count($this->model->getSubScodes($sort->scode)), $content);
                        break;

将apps\home\model\ParserModel.php中的getSubScodes方法改为public

 public function getSubScodes($scode)

模板标签写法

<!--没有子类-->
                        {pboot:if({sort:soncount} == 1)}
                        <div class="module-inner">
                            <div class="t3_nav1_t nav1_color1">
                                <dl>
                                    <dt>{sort:parentname}</dt>
                                    <dd>Zibo Central Hospital</dd>
                                </dl>
                            </div>
                            <div class="module-ct t3_nav1_b">
                                <ul>
                                    {pboot:nav num=100 parent={sort:pcode}}
                                    <li class="item-399 {pboot:2if('[nav:scode]'=='{sort:scode}')}current active{/pboot:2if}"><a href="[nav:link]">[nav:name]</a>
                                    </li>
                                    {/pboot:nav}

                                </ul>
                            </div>
                        </div>
                        {else}
                        <div class="module-inner">
                            <div class="t3_nav1_t nav1_color1">
                                <dl>
                                    <dt>{sort:name}</dt>
                                    <dd>Zibo Central Hospital</dd>
                                </dl>
                            </div>
                            <div class="module-ct t3_nav1_b">
                                <ul>
                                    {pboot:nav num=100 parent={sort:scode}}
                                    <li class="item-399"><a href="[nav:link]">[nav:name]</a>
                                    </li>
                                    {/pboot:nav}
                                </ul>
                            </div>
                        </div>
                        {/pboot:if}

自带分页条及样式

{page:bar}
/* 分页样式 */
.paging { margin-top: 32px; font-size: 14px; }
.paging > span { margin: auto 16px; }
.paging .page-numbar { margin: auto 0; }
.paging .page-numbar .page-num,
.paging .page-index,
.paging .page-pre,
.paging .page-next,
.paging .page-last { display: inline-block; margin: auto 4px; padding: 2px 12px; border: 1px solid #EEE; border-radius: 2px; }
.paging .page-numbar .page-num-current,
.paging .page-numbar .page-num:hover { border-color: #8667F7; color: #8667F7; }

多语言网站

系统管理>数据区域添加区域,切换数据区域,设置相应的模板目录,为不同的语言建立不同的模板文件,添加栏目版块,添加内容,前台语言切换导航添加

今晚浏览博客园看到推荐文章里的一篇名为dnSpy 强大的.Net反编译软件的文章,虽然许久不开发.net程序,不过对反编译.net也有过一定的研究,忍不住进入阅读并下载了dnSpy进行尝试,随手打开常用的基于.NET开发的仿站神器 仿站小工具,如下图
混淆后.png

代码是经过Xenocode混淆的,无法清晰的查看程序的执行流程逻辑,遂又百度有无新的反混淆工具,又发现了de4dot神器,官方的GITHUB是源码没有编译版的,找到编译版下载地址分享一下:

吾爱破解在线工具包
官方编译下载

下载后对仿站小工具进行反混淆处理:
de4dot.png

再次用dnSpy打开反混淆后的文件,可以看到代码已经清晰的多了:
反混淆后.png

dnSpy编辑dll,exe文件的功能很方便,不用其他插件或者辅助,就可以进行修改。可以根据自己的需要来对程序进行DIY改造了。