前言
大家都知道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
1
2
3
4
5
6
|
<?php
return array (
//'配置项'=>'配置值'
'INDEX_MOD' =>1, //首页模式 0-动态模式 1-静态模式
'INDEX_HTML_FILE' =>__ROOT__. 'Application/Home/View/Index/index_html.html' , //静态首页地址
);
|
/Application/Home/Controller/IndexController.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
<?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
1
2
3
4
5
6
7
8
9
10
11
12
|
<!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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/**
* 创建静态页面
* @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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
<?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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
<?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()
。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:http://www.cnblogs.com/dee0912/p/5068691.html