|  | 
 
| 微擎“阅读许可协议”是下载完微擎安装程序install.php后,在浏览器里面打开这个文件进行安装时的第一个界面,如下图所示: 阅读许可协议
 
 
 本教程将详细分析这个界面是如何实现的,本系列教程将详细分析微擎到底是如何仅通过一个安装文件install.php来实现系统安装的,本教程是这一系列教程里面的第一个教程,即阅读许可协议源码分析教程。
 
 如果我们去研究一些cms系统会发现,他们的安装文件其实是非常多,有安装时的程序文件、模板文件、js、css等,而微擎则只有一个文件install.php就可以实现在线安装,来对比一下这些系统可以丰富我们开发系统的眼界,学习优秀的程序开发思想便于我们日后开发,作为管理微信公众号开源系统是值我们好好研究的。
 
 源码分析开始
 
 1)程序报错处理:
 
 复制代码error_reporting(E_ALL ^ E_NOTICE);
 
 这行代码表示:除提示错误外显示其它所有错误,也就是只有notice错误不显示,因为,notice错误一般不影响程序运行,如果您的要求极高容不得一点提示,您可以直接开启显示所有错误包括提示。
 
 显示所有错误:
 
 
 
 关闭所有错误:
 
 
 
 2)脚本最大执行时间:
 
 
 参数为零表示:不作任何限制,如果不设置参数的话,默认值为30秒,或者是在php.ini的max_execution_time被定义的值。
 
 3)条件if($_GET['res'])里面的代码:
 
 在这个条件里面的代码第一次打开时并不执行,因为,$_GET['res']值为“假”,但是,当把许可证书加载完后,即再次重装install.php网页时,此时,则会执行这个条件里面的代码,这个我们将会在后面进行详细分析,这里先提示一下。
 
 4)开启ob缓冲区:ob_start();
 
 关于ob缓冲区知识可以查看教程“PHP的输出缓冲区从入门到精通教程”,后面在使用这个ob缓冲区知识时再详细分析。
 
 下面是一堆常量的定义,不用多解释。
 
 5)定义一个安装流程用到的值的数组:
 
 复制代码$actions = array('license', 'env', 'db', 'finish');
 也就是说微擎的安装步骤就是这四步,这种思想方法在很多系统中都使用,即先把一个安装流程(不仅限于安装程序制作)然后,用到哪个流程时就可以从这个数组进行对比判断等。
 
 获取action的值:
 
 复制代码$action = $_COOKIE['action'];
 
 第一次安装时程序刚第一次执行这行代码时,$action的值为空。
 
 设置$action的默认值:
 
 复制代码$action = in_array($action, $actions) ? $action : 'license';
 
 实际上,这个三元运算不仅可以在第一次$action为空时设置一个初始的值,而且,还可以在$action有值时则重新赋一个新值给$action,这是一种即简单又非常灵活的设置方法,一举两得。
 
 设置一个默认的键REQUEST_METHOD对应的值:
 复制代码$ispost = strtolower($_SERVER['REQUEST_METHOD']) == 'post';
 
 6)判断是否已经安装了微擎:
 
 
 复制代码if(file_exists(IA_ROOT . '/data/install.lock') && $action != 'finish') {
    header('location: ./index.php');
    exit;
}
 
 当文件夹data里面有intall.lock文件并且$action不是finish时,说明这个网站已经安装过微擎了,这样就不需要再去重新安装了。例如 假设网站bbs.5ucms.com已经安装了微擎,这样再在浏览器里面打开http://bbs.5ucms.com/install.php文件后,程序会自动定位到与install.php在同目录里面的index.php文件。
 
 install.php文件就是微擎系统的入口文件,这样程序就不会再次安装了。当然,在实际的使用时当安装完微擎系统后,请把install.php文件删除掉,以免被黑客利于。
 
 7)设置一个header头:
 
 复制代码header('content-type: text/html; charset=utf-8');
 
 这是为了防止出现乱码,因为,后面的代码将是把包括中文在内的数据全部输出,所以,在输出到浏览器前先设置一下编码。
 
 8)输出数据显示“阅读许可协议”界面:
 
 
 复制代码if($action == 'license') {
    if($ispost) {
        setcookie('action', 'env');
        header('location: ?refresh');
        exit;
    }
    tpl_install_license();
}
 前7条内容里面的代码其实都是进行初始化设置的,真正的在我们在浏览输入install.php(例如,bbs.5ucms.com/install.php)后,看到上图中的“阅读许可协议”安装界面的就是这一个条件if($action == 'license')里面的内容处理的。
 
 a)在这个条件里面先判断一下条件if($ispost)值是不是存在,默认第一次执行这段代码是不存在的,即条件if($ispost)条件不成立,所以,里面的代码不执行。
 
 b)调用函数tpl_install_license():这个函数在install.php文件里面的后面,在这个函数里面定义了上图中的“阅读许可协议”所有内容,并且调用函数 tpl_frame();
 
 也就是说我们进入到安装界面的第一个界面看到的“阅读许可协议”是由这个函数tpl_install_license()来定义,即如下图所示这一块代码和内容:
 
 
 另一个函数tpl_frame()则是定义了除“阅读许可协议”外其它所有代码和内容。
 
 疑问:
 
 上面感觉应当是先加载整个网页,即先加载tpl_frame()函数,然后,再把“阅读许可协议”,即tpl_install_license()加到网页里面,但是,上面的顺序弄倒了?上面是先显示阅读协议,然后,再把整个网页引入显示,这样不就导致阅读许可协议在网页上面,而网页在阅读许可协议下面,但是,我们看到的确是正常的显示内容。
 
 解疑:
 
 看上去有问题而实际是正确的这是如何实现的呢?这就是我们上面提到的用到了ob缓冲区的知识来实现的。
 
 当我们开启ob缓冲区时(在输出前写上代码ob_start()即开启了ob缓冲区),输出的内容将被暂缓存到ob缓冲区里面。也就是调用函数tpl_install_license()后“阅读许可协议”里面的内容和代码(即函数tpl_install_license()里面定义的字符串)将全部被缓放到缓冲区里面,并没有直接输出到浏览器里面。
 
 然后,在函数tpl_frame()里面,使用函数ob_get_contents()获取ob缓冲区里面的内容保存到变量$content里面,也就是获取到的了“阅读许可协议”内容和代码。
 
 接着在函数tpl_frame()里面又使用函数ob_clean()清空了缓冲区里面的所有内容。
 
 接着声明了一字符串$tpl,这个字符串是除了“阅读许可协议”和“安装进度”外包含了所有其它网页代码和内容。
 
 在$tpl字符串里面我们能找到两个变量:安装进度{$progress}和阅读许可协议{$content}。
 
 {$content}是在函数tpl_frame()里面就已经获取到的“阅读许可协议”内容。
 
 {$progress)则是在函数tpl_frame()里面下面的代码获取到的:
 
 复制代码$progress = $step * 25 + 25;
 
 最后,输出$tpl 字符串:
 
 
 
 输出字符串相当于把整个网页输入到浏览器,也就是我们看到的安装界面的第一步。
 
 函数tpl_frame()里面的其它代码:
 
 
 复制代码    global $action, $actions;
    $action = $_COOKIE['action'];
    $step = array_search($action, $actions);
    $steps = array();
    for($i = 0; $i <= $step; $i++) {
        if($i == $step) {
            $steps[$i] = ' list-group-item-info';
        } else {
            $steps[$i] = ' list-group-item-success';
        }
    }
 
 因为第一次执行代码,所以,$_COOKIE['action']值为空,自然,$step的值为false,又因为0为false,非0为true,所以,下面的for循环时,第一次执行这里面的代码时$step的值为零,这个for循环的结果是:$steps[0]='list-group-item-info'
 
 安装进度条为:$progress = $step * 25 + 25,即$progress = 25,这就是为什么我们在微擎安装第一步里面看到的“安装进度”为25%,至于那个进度条是由bootstrap框架来实现的。
 
 安装界面logo的处理
 
 logo如下图所示:
 
 
 
 当在浏览器里面输入http://bbs.5ucms.com/install.php后,立马就会看到这个logo图片,实际上第一次执行install.php代码时并不显示这个logo,而是在第二次打开install.php这个文件时才把logo调出来显示,也就是说在浏览器打开install.php文件实际上是执行了二次打开文件install.php的请求,只是打开的速度太快我们感觉不到打开了两次,其实,第一次是不显示logo的,第二次才显示logo,但太快我们感觉不出来。
 
 可以看一下http请求头部代码就可以发现这点,如下图所示:
 
 第一次http请求
 
 我只在浏览器里面刷新了一次install.php文件,结果通过上面我们看到请求了二次php文件:一次是install.php,另一次是install.php?res=logo
 
 第一次请求后响应的内容类型为:text/html; charset=utf-8,如下图所示。
 
 响应内容类型
 
 第二次请求后响应的内容类型为:image/png,如下图所示。
 
 
 
 再回过头来研究上面提到过的代码:
 
 
 复制代码if($_GET['res']) {
    $res = $_GET['res'];
    $reses = tpl_resources();
    if(array_key_exists($res, $reses)) {
        if($res == 'css') {
            header('content-type:text/css');
        } else {
            header('content-type:image/png');
        }
        echo base64_decode($reses[$res]);
        exit();
    }
}
 上面提到过了第一次并没有执行这段代码,所以,内容类型是在install.php设置的一个header。而第二次的内容类型就变成了图片image/png,也就是logo了。
 
 在函数tpl_frame()里面有这样一行html代码:<img src="?res=logo" />
 
 也就是说第一次执行这段代码显示网页时执行到<img src="?res=logo" />时,又一次请请了当前文件而当前文件正是install.php,所以,<img src="?res=logo" />等价于<img src="intsall.php?res=logo" />
 这样程序又重新加载了一次install.php代码,此时,条件if($_GET['res'])成立,则执行这里面的代码。
 
 在函数tpl_resources()里面使用64位加密方式加密的logo图片,这就是为什么我们看到函数tpl_resources()里面是一堆看上去像乱码似的内容,其实,是logo被加密后的内容。
 
 因为参数res=logo,所以,上面的代码执行后会加载一个头header('content-type:inage/png'),这就是为什么我们在上面的http请求里面看到第二次请求时的内容类型为image/png了。
 
 (为什么选择加密呢?为了防止小白去直接修改LOGO图片是很大的原因,但邱嵩松认为其实这样做也没啥卵用,因为<img src="" />懂点HTML的人就知道是加载图片的,直接换个图片路径就可以破解掉,然后用自己想要的图了。)
 
 然后,显示logo:
 
 复制代码echo base64_decode($reses[$res]);
 
 这样我们就看到logo图片了。
 
 这里为什么要加上一个header('content-type:image/png'),因为,通过函数base64_decode($reses[$res])解密后的仍然是一堆乱码,这堆乱码就是logo,如果我们用记事本打开一个图片看到的也是类似的乱码。在输出时需要告诉浏览器这是一张图片,这样浏览器就会把这张图片显示出来。
 
 如果不加header('content-type:image/png;charset=utf-8'),这个logo的显示代码如下图所示:
 
 
 当加上这个头显示的是如下所示的正常的logo:
 
 
 
 上面就是阅读许可协议显示时所有用到的方法和内容。
 
 下一步:
 
 当选中阅读协议,点“继续”后就可以进入到第二步“环境监测”。
 
 这一段进入到“环境监测”的代码是:
 
 
 复制代码<form class="form-inline" role="form" method="post">
            <ul class="pager">
                <li class="pull-left" style="display:block;padding:5px 10px 5px 0;">
                    <div class="checkbox">
                        <label>
                            <input type="checkbox"> 我已经阅读并同意此协议
                        </label>
                    </div>
                </li>
                <li class="previous"><a href="javascript:;" onclick="if(jQuery(':checkbox:checked').length == 1){jQuery('form')[0].submit();}else{alert('您必须同意软件许可协议才能安装!')};">
继续 <span class="glyphicon glyphicon-chevron-right"></span></a></li>
            </ul>
        </form>
 
 这段html代码是在函数tpl_install_license()里面,这段代码里面有两个知识点:
 
 1)  form里面的action:当在form里同没有写action、action为空、action值是一个问号,即无action,action="",action="?"都表示提交到本页。
 
 2)使用了jquery来判断处理是不是选中,然后,把表单提交到install.php本页面:if(jQuery(':checkbox:checked').length == 1){jQuery('form')[0].submit();}else{alert('您必须同意软件许可协议才能安装!')};
 
 | 
 
x本帖子中包含更多资源您需要 登录 才可以下载或查看,没有帐号?立即注册  |