|
微擎“阅读许可协议”是下载完微擎安装程序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
|