ThinkPHP 3.2.3实现页面静态化功能的方法详解


Posted in PHP onAugust 03, 2017

前言

大家都知道PHP 的页面静态化有多种实现方式,比如使用输出缓冲(output buffering),该种方式是把数据缓存在 PHP 的缓冲区(内存)中,下一次取数据时直接从缓冲区中读取数据,从而避免了脚本的编译和访问数据库等过程;另一种方式是直接生成静态的 HTML 文件,使用文件读写函数来实现,一些内容不经常改动的页面可以使用静态页面,访客访问到的页面就是真实的 HTML 页面,一些常见的 CMS 会使用该种方法。

以第二种方法为例,参考 DedeCMS 5.7 的静态化功能,在 ThinkPHP 3.2.3 下实现该方法。由于 ThinkPHP 是单入口系统,而且每一个页面都要对应控制器中的某个方法,因此不能直接把静态文件的地址作为实际访问的地址,而是需要在控制器中以模版加载的方式读取静态文件。

首页静态化的实现

在 DedeCMS 5.7 中,可以生成静态的首页、栏目页和文章页。其中首页的生成在后台的“生成”栏目进行设置,包括模板的选择、首页静态文件的存放路径以及首页模式(使用动态首页还是静态首页),DedeCMS 还专门为首页的设置设计了一张表 dede_homepageset,包含的字段包括 templet(模板位置)、position(首页静态文件的路径)、showmod(首页模式),通过在后台进行设置与生成,来控制网站首页使用动态首页还是静态首页,用到的核心文件是 \dede\makehtml_homepage.php。

流程大致是:

① 在后台选择生成静态页面时,通过表单向 makehtml_homepage.php 发送请求,参数包括 dede_homepageset 的所有字段

② 根据传递参数中的 templet、position、showmod 更新 dede_homepageset 表

③ 如果 showmod 是使用静态,加载模板,把模板保存为静态文件。使用的方法是 fopen(),fwrite() 和 fclose(),非常简单

④ 生成了静态页面之后,访客访问的就直接是静态的 index.html,如果首页发生了改变,则手动在后台重新生成一下首页

在 ThinkPHP 中可以这样设计:

config.php

<?php
return array(
 //'配置项'=>'配置值'
 'INDEX_MOD'=>1,//首页模式 0-动态模式 1-静态模式
 'INDEX_HTML_FILE'=>__ROOT__.'Application/Home/View/Index/index_html.html',//静态首页地址
);

/Application/Home/Controller/IndexController.php

<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
 
 //首页
 public function index() {
  if(1 == C('INDEX_MOD')) {
   //静态
   $this->display('index_html');
  } else {
   //动态
   $list = M('category')->select();
   $this->assign('list', $list);
   $this->display('index_php');
  }
 }
 
 //根据动态首页的内容生成静态页面
 public function makehtml_homepage() {
  $homepage = 'http://'.$_SERVER['HTTP_HOST'].U('Home/Index/index_php'); 
  $content = @file_get_contents($homepage);
  file_put_contents(C('INDEX_HTML_FILE'), $content);
 }
 
 //动态首页数据
 public function index_php() {
  C('INDEX_MOD', 0);
  $this->index();
 }
}

模版文件 /Application/Home/View/Index/index_php.php

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>
</head>
<body>
 <volist name="list" id="vo">
  {$vo.cat_name}<br />
 </volist> 
</body>
</html>

在执行 http://ServerName/Home/Index/makehtml_homepage ,即手动生成静态首页后,在 /Application/Home/View/Index/ 路径下生成了静态文件:index_html.html,根据配置文件中设置的 INDEX_MODE 为静态,访问 http://ServerName 实际访问的就是新生成的静态文件。

ThinkPHP 也自带了生成静态文件的方法 buildHtml,使用方法是 buildHtml('生成的静态文件名称', '生成的静态文件路径', '指定要调用的模板文件');

方法在 /ThinkPHP/Library/Think/Controller.class.php,Line 86:

/**
  * 创建静态页面
  * @access protected
  * @htmlfile 生成的静态文件名称
  * @htmlpath 生成的静态文件路径
  * @param string $templateFile 指定要调用的模板文件
  * 默认为空 由系统自动定位模板文件
  * @return string
  */
 protected function buildHtml($htmlfile='',$htmlpath='',$templateFile='') {
  $content = $this->fetch($templateFile);
  $htmlpath = !empty($htmlpath)?$htmlpath:HTML_PATH;
  $htmlfile = $htmlpath.$htmlfile.C('HTML_FILE_SUFFIX');
  Storage::put($htmlfile,$content,'html');
  return $content;
 }

其中 Storage 类在 /ThinkPHP/Library/Think/Storage.class.php

<?php
// +----------------------------------------------------------------------
// | TOPThink [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://topthink.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think;
// 分布式文件存储类
class Storage {

 /**
  * 操作句柄
  * @var string
  * @access protected
  */
 static protected $handler ;

 /**
  * 连接分布式文件系统
  * @access public
  * @param string $type 文件类型
  * @param array $options 配置数组
  * @return void
  */
 static public function connect($type='File',$options=array()) {
  $class = 'Think\\Storage\\Driver\\'.ucwords($type);
  self::$handler = new $class($options);
 }

 static public function __callstatic($method,$args){
  //调用缓存驱动的方法
  if(method_exists(self::$handler, $method)){
   return call_user_func_array(array(self::$handler,$method), $args);
  }
 }
}

默认的文件类型是 File,所以实例化的类的地址在 /ThinkPHP/Library/Think/Storage/Driver/File.class.php

<?php
// +----------------------------------------------------------------------
// | TOPThink [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://topthink.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Storage\Driver;
use Think\Storage;
// 本地文件写入存储类
class File extends Storage{

 private $contents=array();

 /**
  * 架构函数
  * @access public
  */
 public function __construct() {
 }

 /**
  * 文件内容读取
  * @access public
  * @param string $filename 文件名
  * @return string  
  */
 public function read($filename,$type=''){
  return $this->get($filename,'content',$type);
 }

 /**
  * 文件写入
  * @access public
  * @param string $filename 文件名
  * @param string $content 文件内容
  * @return boolean   
  */
 public function put($filename,$content,$type=''){
  $dir   = dirname($filename);
  if(!is_dir($dir))
   mkdir($dir,0755,true);
  if(false === file_put_contents($filename,$content)){
   E(L('_STORAGE_WRITE_ERROR_').':'.$filename);
  }else{
   $this->contents[$filename]=$content;
   return true;
  }
 }

 /**
  * 文件追加写入
  * @access public
  * @param string $filename 文件名
  * @param string $content 追加的文件内容
  * @return boolean  
  */
 public function append($filename,$content,$type=''){
  if(is_file($filename)){
   $content = $this->read($filename,$type).$content;
  }
  return $this->put($filename,$content,$type);
 }

 /**
  * 加载文件
  * @access public
  * @param string $filename 文件名
  * @param array $vars 传入变量
  * @return void  
  */
 public function load($_filename,$vars=null){
  if(!is_null($vars))
   extract($vars, EXTR_OVERWRITE);
  include $_filename;
 }

 /**
  * 文件是否存在
  * @access public
  * @param string $filename 文件名
  * @return boolean  
  */
 public function has($filename,$type=''){
  return is_file($filename);
 }

 /**
  * 文件删除
  * @access public
  * @param string $filename 文件名
  * @return boolean  
  */
 public function unlink($filename,$type=''){
  unset($this->contents[$filename]);
  return is_file($filename) ? unlink($filename) : false; 
 }

 /**
  * 读取文件信息
  * @access public
  * @param string $filename 文件名
  * @param string $name 信息名 mtime或者content
  * @return boolean  
  */
 public function get($filename,$name,$type=''){
  if(!isset($this->contents[$filename])){
   if(!is_file($filename)) return false;
   $this->contents[$filename]=file_get_contents($filename);
  }
  $content=$this->contents[$filename];
  $info = array(
   'mtime'  => filemtime($filename),
   'content' => $content
  );
  return $info[$name];
 }
}

可以看到 get 和 put 方法所使用的方法是 file_get_contents() file_put_contents()

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
PHP提示Notice: Undefined variable的解决办法
Nov 24 PHP
解析如何通过PHP函数获取当前运行的环境 来进行判断执行逻辑(小技巧)
Jun 25 PHP
ThinkPHP3.1之D方法实例详解
Jun 20 PHP
PHP连接MSSQL2008/2005数据库(SQLSRV)配置实例
Oct 22 PHP
PHP中new static() 和 new self() 的区别介绍
Jan 09 PHP
php基于ob_start(ob_gzhandler)实现网页压缩功能的方法
Feb 18 PHP
PHP实现的mysql主从数据库状态检测功能示例
Jul 20 PHP
弹出模态框modal的实现方法及实例
Sep 19 PHP
ThinkPHP3.1.x修改成功与失败跳转页面的方法
Sep 29 PHP
Mac系统下安装PHP Xdebug
Mar 30 PHP
Linux下源码包安装Swoole及基本使用操作图文详解
Apr 02 PHP
TP5框架实现上传多张图片的方法分析
Mar 29 PHP
PHP7扩展开发教程之Hello World实现方法示例
Aug 03 #PHP
Kindeditor编辑器添加图片上传水印功能(php代码)
Aug 03 #PHP
phpStudy中升级MySQL版本到5.7.17的方法步骤
Aug 03 #PHP
使用PHP json_decode可能遇到的坑与解决方法
Aug 03 #PHP
Yii 2中的load()和save()示例详解
Aug 03 #PHP
Yii2使用表单上传文件的实例代码
Aug 03 #PHP
yii2学习教程之5种内置行为类详解
Aug 03 #PHP
You might like
Fine Uploader文件上传组件应用介绍
2013/01/06 PHP
php selectradio和checkbox默认选择的实现方法详解
2013/06/29 PHP
php接口与接口引用的深入解析
2013/08/09 PHP
php计算两个整数的最大公约数常用算法小结
2015/03/05 PHP
PHP生成条形码大揭秘
2015/09/24 PHP
基于jQuery的固定表格头部的代码(IE6,7,8测试通过)
2010/05/18 Javascript
JS随即打乱数组实现代码
2012/12/03 Javascript
JQuery+CSS提示框实现思路及代码(纯手工打造)
2013/05/07 Javascript
鼠标悬浮停留三秒后自动显示大图js代码
2014/09/09 Javascript
node.js中使用socket.io制作命名空间
2014/12/15 Javascript
jquery图片切换实例分析
2015/04/15 Javascript
JS组件Bootstrap Table布局详解
2016/05/27 Javascript
原生js更改css样式的两种方式
2017/03/15 Javascript
详解vue组件化开发-vuex状态管理库
2017/04/10 Javascript
angularjs实现天气预报功能
2020/06/16 Javascript
jquery实现楼层滚动效果
2018/01/01 jQuery
vue-cli中使用高德地图的方法示例
2019/03/28 Javascript
v-slot和slot、slot-scope之间相互替换实例
2020/09/04 Javascript
Vue Elenent实现表格相同数据列合并
2020/11/30 Vue.js
JS addEventListener()和attachEvent()方法实现注册事件
2021/01/11 Javascript
[39:00]Optic vs VP 2018国际邀请赛淘汰赛BO3 第三场 8.24
2018/08/25 DOTA
[00:52]玛尔斯技能全介绍
2019/03/06 DOTA
python中列表元素连接方法join用法实例
2015/04/07 Python
python实现梯度下降算法
2020/03/24 Python
Pytorch .pth权重文件的使用解析
2020/02/14 Python
Python生成随机验证码代码实例解析
2020/06/09 Python
全网最细 Python 格式化输出用法讲解(推荐)
2021/01/18 Python
预订奥兰多和佛罗里达州公园门票:FloridaTix
2018/01/03 全球购物
家庭睡衣和家庭用品:Little Blue House
2018/03/18 全球购物
extern是什么意思
2016/03/10 面试题
高中的自我鉴定
2013/12/16 职场文书
保密工作实施方案
2014/02/24 职场文书
教师辞职信范文
2015/02/28 职场文书
宿舍卫生管理制度
2015/08/05 职场文书
2019优秀干部竞聘演讲稿范文!
2019/07/02 职场文书
56句经典英文座右铭
2019/08/09 职场文书