docker的web管理工具

海鸥

Docker Pulls
GoDoc
Gitter

简介

Seagull 友好的docker Web界面管理工具

  • 易于安装和卸载在Docker容器
  • 单击开始/停止/删除容器和镜像
  • 超快速(小于10ms)的搜索和过滤
  • 支持多主机管理和监控
  • 国际化主要包括英语、汉语、德语和法语

更多信息, 请到 dockerseagull.com, 观看 三分钟视频官方的幻灯片.

github地址

点击跳转: https://github.com/tobegit3hub/seagull

安装

  1. docker run -d -p 10086:10086 -v /var/run/docker.sock:/var/run/docker.sock tobegit3hub/seagull

或运行 docker-compose up -d.

截图

多主机

Seagull支持监控多台服务器。确保你开始Docker守护这样。

  1. docker -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock -api-enable-cors=true -d

参与

Seagull is written in Go with tools like Docker, Beego, AngularJS, Bootstrap and JQuery.

  1. Install golang and setup $GOPATH
  2. go get github.com/astaxie/beego
  3. go get github.com/tobegit3hub/seagull
  4. go build seagull.go
  5. sudo ./seagull

More detail in seagull-design-and-implement and we have excellent documents in docs.

提醒

The issue #2 每个人都可以在IP和端口海鸥接触访问您的码头工人守护。为了安全,你可以绑定到本地主机的访问限制。

  1. docker run -d -p 127.0.0.1:10086:10086 -v /var/run/docker.sock:/var/run/docker.sock tobegit3hub/seagull

类似的Docker项目

现在有很多类似的项目提供了Web界面来监控Docker。海鸥就是受他们影响并且期望做得比他们更好。

我想把这些项目都介绍给你们,任何人都可以根据他们所需要的进行选择。

Dockerui

这是它的Github主页,https://github.com/crosbymichael/dockerui.

你可以发现海鸥的UI是有点像Dockerui。因为我们都使用了Bootstrap和AngularJS作为前端框架。它是一个很好的项目并且在Github上有差不多2000个关注。

海鸥从Dockerui中学习了很多,包括使用JQuery.Gritter作为网站通知。但Dockerui的界面不够简洁,而且它没有考虑到国际化的需求,而我们考虑到了。我们愿意为全世界的开发者多做些事情。Dockerui还没有实现搜索功能而海鸥则很擅长这点。

Dockerui和海鸥是同类型产品,用于监控Docker。你没必要同时使用他们。而我们的目标就是用一个更友好、更实用的UI满足用户,并且取代Dockerui。

Zdocker

这是它的Github主页,https://github.com/love320/Zdocker.

Zdocker做了同类的事情来监控Docker镜像和容器。但它是使用Java实现的,而且没有提供Docker镜像,而且人们很难使用和学习。

这只能算是个人项目,我并不建议你去使用。因为目前为止我也不知道该怎样去运行它。

Shipyard

这是它的Github主页,https://github.com/shipyard/shipyard.

Shipyard设计来管理一个Docker集群。你必须输入服务器的SSH认证代码才能部署Shipyard引擎。然后你就可以通过命令行或者Web界面在你管理的服务器上部署容器了。

它和海鸥是非常不同的,因为海鸥仅仅是监控Docker而不会要求更多的权限。因此你可以使用Shipyard作为管理系统,同时使用海鸥来监控Docker。

CAdvisor

这是它的Github主页,https://github.com/google/cadvisor.

CAdvisor来自于Google,它主要是为了分析容器的资源。你可以使用它来监控你的容器占用CPU或者内存的历史情况。

然后,你不能用CAdivsor来管理你的镜像和容器。

Docker Registry Web

这是它的Github主页,https://github.com/atc-/docker-registry-web.

这是为Docker参与设计的Web界面。它的UI展示不错但你必须手动添加私有仓库地址。它用了Cookies来存储这个地址所以每次你运行时都要重新添加。

当我尝试去搜索Docker镜像时程序崩溃了。当我尝试去或者镜像详细信息的时候它显示“方法未授权”。

我希望他们可以在我们添加私有仓库时就默认添加Docker官方仓库。但我不太可能因为http://registry.hub.docker.com不支持CORS。

Docker Registry UI

这是它的Github主页,https://github.com/worksap-ate/docker-registry-ui.

这也是为Docker仓库设计的Web界面。它能用但是UI不是很好。

Docker Register Frontend

这是它的Github主页,https://github.com/kwk/docker-registry-frontend.

这几乎是跟Docker-registry-web和Docker-registry-ui是一样的东西。

angularjs的$http发送post请求

刚开始用angularjs的post方法时, 后台总是接收不到数据, 查了资料发现是因为angularjs的post提交方式和jquery的不一样, jquery默认就是模拟form提交数据, 而angularjs则使用的是 request payload, 所有使用$_POST是获取不到数据的, 解放方法:

  1. $http({
  2. url: url,
  3. method: 'post',
  4. headers: {
  5. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  6. },
  7. data: {
  8. order_id: orderId
  9. },
  10. transformRequest: function(obj) {
  11. var str = [];
  12. for (var p in obj) {
  13. str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
  14. }
  15. return str.join("&");
  16. }
  17. }).success(function(data, header, config, status) {
  18. // 正确返回
  19. }).error(function(data, header, config, status) {
  20. //处理响应失败
  21. });

php-angular模板引擎

源码地址: https://github.com/php-angular/php-angular

仿angularjs的php模板引擎

目前实现了一下几种标签和用法

标签

  1. php-if
  2. php-for
  3. php-foreach
  4. php-repeat
  5. php-show
  6. php-hide
  7. php-include
  8. php-init
  9. php-exec

变量输出
{$var}
{$array.name}
{$array[‘name’]}
{:func()}
{$var ? ‘’ : ‘’}

结合框架使用

具体的框架驱动可以在 /drivers 目录中找到

直接使用方法 /test/index.php

  1. <?php
  2. require '../lib/angular.php';
  3. // 配置
  4. $config = array(
  5. 'tpl_path' => './view/',
  6. 'tpl_suffix' => '.html',
  7. 'cache_path' => './cache/',
  8. 'attr' => 'php-',
  9. 'debug' => true,
  10. );
  11. // 实例化
  12. $view = new Angular($config);
  13. // 数据
  14. $data = array(
  15. 'title' => 'Hello PHP Angular',
  16. 'list' => array(
  17. array('name' => 'name_1', 'email' => 'email_1@qq.com'),
  18. array('name' => 'name_2', 'email' => 'email_2@qq.com'),
  19. array('name' => 'name_3', 'email' => 'email_3@qq.com'),
  20. array('name' => 'name_4', 'email' => 'email_4@qq.com'),
  21. array('name' => 'name_5', 'email' => 'email_5@qq.com'),
  22. ),
  23. );
  24. // 向模板引擎设置数据
  25. $view->assign($data);
  26. // 输出解析结果
  27. $view->display('index');
  28. // 获取输出结果
  29. // $view->fetch('index');

模板实例 /test/view/index.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>php-angular</title>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <style type="text/css">
  8. .box {
  9. padding: 10px;
  10. font-size: 12px;
  11. margin: 10px 5px;
  12. background: #CCC;
  13. }
  14. </style>
  15. </head>
  16. <body>
  17. <div class="box" php-show="$title">{$title}</div>
  18. <div class="box" php-hide="$title">如果title的值为空, 则可以显示这条消息, 否则不显示</div>
  19. <div class="box">
  20. <span>foreach by [1,2,3,4,5]</span>
  21. <ul>
  22. <li php-foreach="[1,2,3,4,5] as $i">foreach {$i}</li>
  23. </ul>
  24. </div>
  25. <div class="box">
  26. <span>repeat by [1,2,3,4,5]</span>
  27. <ul>
  28. <li php-repeat="[1,2,3,4,5] as $i">foreach {$i}</li>
  29. </ul>
  30. </div>
  31. <div class="box" php-show="$list">
  32. <span>foreach by $list as $item</span>
  33. <ul>
  34. <li php-foreach="$list as $item">name:{$item.name} -- email: {$item.email}</li>
  35. </ul>
  36. </div>
  37. <div class="box" php-show="$list">
  38. <span>repeat by $list as $item</span>
  39. <ul>
  40. <li php-repeat="$list as $item">name:{$item.name} -- email: {$item.email}</li>
  41. </ul>
  42. </div>
  43. <div class="box" php-if="$list">
  44. <span>foreach by $list as $key => $item</span>
  45. <ul>
  46. <li php-foreach="$list as $key => $item">{$key} -- name:{$item.name} -- email: {$item.email}</li>
  47. </ul>
  48. </div>
  49. <div class="box">
  50. <span>for by ($i = 1; $i <= 10; $i++;)</span>
  51. <ul>
  52. <li php-for="$i = 1; $i <= 10; $i++">for {$i}</li>
  53. </ul>
  54. </div>
  55. <div class="box" php-if="$list">
  56. <span>$list 不为空</span>
  57. </div>
  58. </body>
  59. </html>

解析结果 /test/cache/6a992d5529f459a44fee58c733255e86.php

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>php-angular</title>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <style type="text/css">
  8. .box {
  9. padding: 10px;
  10. font-size: 12px;
  11. margin: 10px 5px;
  12. background: #CCC;
  13. }
  14. </style>
  15. </head>
  16. <body>
  17. <?php if ($title) { ?><div class="box" ><?php echo $title; ?></div><?php } ?>
  18. <?php if (!($title)) { ?><div class="box" >如果title的值为空, 则可以显示这条消息, 否则不显示</div><?php } ?>
  19. <div class="box">
  20. <span>foreach by [1,2,3,4,5]</span>
  21. <ul>
  22. <?php foreach ([1,2,3,4,5] as $i) { ?><li >foreach <?php echo $i; ?></li><?php } ?>
  23. </ul>
  24. </div>
  25. <div class="box">
  26. <span>repeat by [1,2,3,4,5]</span>
  27. <ul>
  28. <?php foreach ([1,2,3,4,5] as $i) { ?><li >foreach <?php echo $i; ?></li><?php } ?>
  29. </ul>
  30. </div>
  31. <?php if ($list) { ?><div class="box" >
  32. <span>foreach by $list as $item</span>
  33. <ul>
  34. <?php foreach ($list as $item) { ?><li >name:<?php echo $item["name"]; ?> -- email: <?php echo $item["email"]; ?></li><?php } ?>
  35. </ul>
  36. </div><?php } ?>
  37. <?php if ($list) { ?><div class="box" >
  38. <span>repeat by $list as $item</span>
  39. <ul>
  40. <?php foreach ($list as $item) { ?><li >name:<?php echo $item["name"]; ?> -- email: <?php echo $item["email"]; ?></li><?php } ?>
  41. </ul>
  42. </div><?php } ?>
  43. <?php if ($list) { ?><div class="box" >
  44. <span>foreach by $list as $key => $item</span>
  45. <ul>
  46. <?php foreach ($list as $key => $item) { ?><li ><?php echo $key; ?> -- name:<?php echo $item["name"]; ?> -- email: <?php echo $item["email"]; ?></li><?php } ?>
  47. </ul>
  48. </div><?php } ?>
  49. <div class="box">
  50. <span>for by ($i = 1; $i <= 10; $i++;)</span>
  51. <ul>
  52. <?php for ($i = 1; $i <= 10; $i++) { ?><li >for <?php echo $i; ?></li><?php } ?>
  53. </ul>
  54. </div>
  55. <?php if ($list) { ?><div class="box" >
  56. <span>$list 不为空</span>
  57. </div><?php } ?>
  58. </body>
  59. </html>

写了一个ThinkPHP的模板引擎, 仿angular的, 简单版

前段时间学习angularjs, 里面的模板思想和实现方法很酷, 就心血来潮, 想实现一个php版的, 今天试着写了一下, 发现貌似可以, 具体看源码.

./ThinkPHP/Library/Think/Template/Driver/Angular.class.php

  1. <?php
  2. namespace Think\Template\Driver;
  3. use Think\Storage;
  4. /**
  5. * Angular模板引擎驱动
  6. */
  7. class Angular {
  8. private $config = array();
  9. private $tpl_var = array();
  10. /**
  11. * 架构函数
  12. */
  13. public function __construct() {
  14. $this->config['cache_path'] = C('CACHE_PATH');
  15. $this->config['tpl_dir'] = THEME_PATH;
  16. $this->config['cache_path'] = C('CACHE_PATH');
  17. $this->config['template_suffix'] = C('TMPL_TEMPLATE_SUFFIX');
  18. $this->config['cache_suffix'] = C('TMPL_CACHFILE_SUFFIX');
  19. $this->config['tmpl_cache'] = C('TMPL_CACHE_ON');
  20. $this->config['cache_time'] = C('TMPL_CACHE_TIME');
  21. $this->config['attr'] = 'tp-';
  22. }
  23. /**
  24. * 编译模板
  25. * @param type $tpl_file 模板文件
  26. * @param type $tpl_var 模板变量
  27. */
  28. public function fetch($tpl_file, $tpl_var) {
  29. $this->tpl_var = $tpl_var;
  30. $tpl_file = $this->load_template($tpl_file);
  31. Storage::load($tpl_file, $tpl_var, null, 'tpl');
  32. }
  33. /**
  34. * 加载主模板并缓存
  35. * @param string $tpl_file 模板文件名
  36. * @return string 缓存的模板文件名
  37. */
  38. public function load_template($tpl_file) {
  39. if (is_file($tpl_file)) {
  40. // 读取模板文件内容
  41. $tpl_content = file_get_contents($tpl_file);
  42. } else {
  43. $tpl_content = $tpl_file;
  44. }
  45. // 根据模版文件名定位缓存文件
  46. $tpl_cache_file = $this->config['cache_path'] . md5($tpl_file) . $this->config['cache_suffix'];
  47. if (Storage::has($tpl_cache_file) && !APP_DEBUG && $this->config['tmpl_cache']) {
  48. return $tpl_cache_file;
  49. }
  50. // 编译模板内容
  51. $tpl_content = $this->compiler($tpl_content);
  52. Storage::put($tpl_cache_file, trim($tpl_content), 'tpl');
  53. return $tpl_cache_file;
  54. }
  55. /**
  56. * 编译模板内容
  57. * @param string $tpl_content 模板内容
  58. * @return string 编译后端php混编代码
  59. */
  60. protected function compiler($tpl_content) {
  61. //模板解析
  62. $tpl_content = $this->parse($tpl_content);
  63. // 添加安全代码
  64. $tpl_content = '<?php if (!defined(\'THINK_PATH\')) exit();?>' . $tpl_content;
  65. // 优化生成的php代码
  66. $tpl_content = str_replace('?><?php', '', $tpl_content);
  67. return strip_whitespace($tpl_content);
  68. }
  69. /**
  70. * 解析模板标签属性
  71. * @param string $content 要模板代码
  72. * @return string 解析后的模板代码
  73. */
  74. public function parse($content) {
  75. while (true) {
  76. $sub = $this->match($content);
  77. if ($sub) {
  78. $method = 'parse_' . $sub['attr'];
  79. if (method_exists($this, $method)) {
  80. $content = $this->$method($content, $sub);
  81. } else {
  82. E("模板属性" . $this->config['attr'] . $sub['attr'] . '没有对应的解析规则');
  83. break;
  84. }
  85. } else {
  86. break;
  87. }
  88. }
  89. $content = $this->parse_value($content);
  90. return $content;
  91. }
  92. /**
  93. * 解析include属性
  94. * @param string $content 源模板内容
  95. * @param array $match 一个正则匹配结果集, 包含 html, value, attr
  96. * @return string 解析后的模板内容
  97. */
  98. private function parse_include($content, $match) {
  99. $tpl_name = $match['value'];
  100. if (substr($tpl_name, 0, 1) == '$') {
  101. //支持加载变量文件名
  102. $tpl_name = $this->get(substr($tpl_name, 1));
  103. }
  104. $array = explode(',', $tpl_name);
  105. $parse_str = '';
  106. foreach ($array as $tpl) {
  107. if (empty($tpl))
  108. continue;
  109. if (false === strpos($tpl, $this->config['template_suffix'])) {
  110. // 解析规则为 模块@主题/控制器/操作
  111. $tpl = T($tpl);
  112. }
  113. // 获取模板文件内容
  114. $parse_str .= file_get_contents($tpl);
  115. }
  116. return str_replace($match['html'], $parse_str, $content);
  117. }
  118. /**
  119. * 解析if属性
  120. * @param string $content 源模板内容
  121. * @param array $match 一个正则匹配结果集, 包含 html, value, attr
  122. * @return string 解析后的模板内容
  123. */
  124. private function parse_if($content, $match) {
  125. $new = "<?php if ({$match['value']}) { ?>";
  126. $new .= str_replace($match['exp'], '', $match['html']);
  127. $new .= '<?php } ?>';
  128. return str_replace($match['html'], $new, $content);
  129. }
  130. /**
  131. * 解析repeat属性
  132. * @param string $content 源模板内容
  133. * @param array $match 一个正则匹配结果集, 包含 html, value, attr
  134. * @return string 解析后的模板内容
  135. */
  136. private function parse_repeat($content, $match) {
  137. $new = "<?php foreach ({$match['value']}) { ?>";
  138. $new .= str_replace($match['exp'], '', $match['html']);
  139. $new .= '<?php } ?>';
  140. return str_replace($match['html'], $new, $content);
  141. }
  142. /**
  143. * 解析show属性
  144. * @param string $content 源模板内容
  145. * @param array $match 一个正则匹配结果集, 包含 html, value, attr
  146. * @return string 解析后的模板内容
  147. */
  148. private function parse_show($content, $match) {
  149. $new = "<?php if ({$match['value']}) { ?>";
  150. $new .= str_replace($match['exp'], '', $match['html']);
  151. $new .= '<?php } ?>';
  152. return str_replace($match['html'], $new, $content);
  153. }
  154. /**
  155. * 解析hide属性
  156. * @param string $content 源模板内容
  157. * @param array $match 一个正则匹配结果集, 包含 html, value, attr
  158. * @return string 解析后的模板内容
  159. */
  160. private function parse_hide($content, $match) {
  161. $new = "<?php if (!({$match['value']})) { ?>";
  162. $new .= str_replace($match['exp'], '', $match['html']);
  163. $new .= '<?php } ?>';
  164. return str_replace($match['html'], $new, $content);
  165. }
  166. /**
  167. * 解析普通变量和函数{$title}{:function_name}
  168. * @param string $content 源模板内容
  169. * @return string 解析后的模板内容
  170. */
  171. private function parse_value($content) {
  172. $content = preg_replace('/\{(\$.*?)\}/', '<?php echo \1 ?>', $content);
  173. $content = preg_replace('/\{\:(.*?)\}/', '<?php echo \1 ?>', $content);
  174. return $content;
  175. }
  176. /**
  177. * 获取第一个表达式
  178. * @param string $content 要解析的模板内容
  179. * @return array 一个匹配的标签数组
  180. */
  181. private function match($content) {
  182. $reg = '#<(?<tag>[\w]+)[^>]*?\s(?<exp>' . preg_quote($this->config['attr']) . '(?<attr>[\w]+)=([\'"])(?<value>[^\4]*?)\4)[^>]*>#s';
  183. $match = null;
  184. if (!preg_match($reg, $content, $match)) {
  185. return null;
  186. }
  187. $sub = $match[0];
  188. $tag = $match['tag'];
  189. /* 如果是但标签, 就直接返回 */
  190. if (substr($sub, -2) == '/>') {
  191. $match['html'] = $match[0];
  192. return $match;
  193. }
  194. /* 查找完整标签 */
  195. $start_tag_len = strlen($tag) + 1; // <div
  196. $end_tag_len = strlen($tag) + 3; // </div>
  197. $start_tag_count = 0;
  198. $content_len = strlen($content);
  199. $pos = strpos($content, $sub);
  200. $start_pos = $pos + strlen($sub);
  201. while ($start_pos < $content_len) {
  202. $is_start_tag = substr($content, $start_pos, $start_tag_len) == '<' . $tag;
  203. $is_end_tag = substr($content, $start_pos, $end_tag_len) == "</$tag>";
  204. if ($is_start_tag) {
  205. $start_tag_count++;
  206. }
  207. if ($is_end_tag) {
  208. $start_tag_count--;
  209. }
  210. if ($start_tag_count < 0) {
  211. $match['html'] = substr($content, $pos, $start_pos - $pos + $end_tag_len);
  212. return $match;
  213. }
  214. $start_pos++;
  215. }
  216. return null;
  217. }
  218. }

./Application/Home/Controller/TestController.class.php

  1. <?php
  2. namespace Home\Controller;
  3. use Think\Controller;
  4. class TestController extends Controller {
  5. public function index() {
  6. C('SHOW_PAGE_TRACE', true);
  7. C('TMPL_ENGINE_TYPE', 'Angular');
  8. $data = array();
  9. $data['title'] = '标题';
  10. $data['nav'] = array(
  11. array('title' => '首页', 'url' => '/'),
  12. array('title' => '文章', 'url' => '/article'),
  13. array('title' => '图片', 'url' => '/pic'),
  14. array('title' => '新闻', 'url' => '/news'),
  15. );
  16. $data['count'] = 6;
  17. $data['list'] = array(
  18. array('id' => 1, 'title' => '这是标题1', 'create_time' => strtotime('-5 seconds')),
  19. array('id' => 2, 'title' => '这是标题2', 'create_time' => strtotime('-4 seconds')),
  20. array('id' => 3, 'title' => '这是标题3', 'create_time' => strtotime('-3 seconds')),
  21. array('id' => 4, 'title' => '这是标题4', 'create_time' => strtotime('-2 seconds')),
  22. array('id' => 5, 'title' => '这是标题5', 'create_time' => strtotime('-1 seconds')),
  23. array('id' => 6, 'title' => '这是标题6', 'create_time' => NOW_TIME),
  24. );
  25. $this->assign($data);
  26. $this->display('index');
  27. }
  28. }

./Application/Home/View/Test/index.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Angular 模板测试 - {$title}</title>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <style>
  8. * {
  9. margin: 0px;
  10. padding: 0px;
  11. font-size: 12px;
  12. color: #333;
  13. line-height: 20px;
  14. }
  15. a {
  16. color: #33F;
  17. text-decoration: none;
  18. }
  19. a:hover {
  20. color: #f00;
  21. text-decoration: underline;
  22. }
  23. .center {
  24. text-align: center;
  25. }
  26. h1{
  27. font-size: 30px;
  28. line-height: 50px;
  29. }
  30. .nav {
  31. line-height: 30px;
  32. }
  33. .nav a{
  34. padding: 0px;
  35. margin: 0px 20px;
  36. }
  37. .main table{
  38. width: 500px;
  39. margin: 0px auto;
  40. }
  41. table {
  42. border: 1px solid #666;
  43. }
  44. table td,
  45. table th{
  46. border: 1px solid #666;
  47. line-height: 20px;
  48. padding: 0px 5px;
  49. }
  50. table th{
  51. background: #CCC;
  52. }
  53. #footer p{
  54. text-align: center;
  55. line-height: 30px;
  56. }
  57. </style>
  58. </head>
  59. <body>
  60. <div class="header">
  61. <h1 class="center">Angular 模板测试 - {$title}</h1>
  62. <div class="nav center" tp-if="$nav">
  63. <a tp-repeat="$nav as $vo" href="{$vo['url']}">{$vo['title']}</a>
  64. </div>
  65. </div>
  66. <div class="main">
  67. <table>
  68. <tr>
  69. <th>编号</th>
  70. <th>标题</th>
  71. <th>创建时间</th>
  72. <th>操作</th>
  73. </tr>
  74. <tr tp-if="$list" tp-repeat="$list as $vo">
  75. <td>{$vo['id']}</td>
  76. <td>{$vo['title']}</td>
  77. <td>{:date('Y-m-d H:i:s', $vo['create_time'])}</td>
  78. <td><a href="#del={$vo['id']}">删除</a></td>
  79. </tr>
  80. <tr tp-if="$count">
  81. <td colspan="4" class="center">共 {$count} 条数据</td>
  82. </tr>
  83. <tr tp-hide="$list">
  84. <td colspan="4" class="center">没有数据</td>
  85. </tr>
  86. </table>
  87. </div>
  88. <div tp-include="footer"></div>
  89. </body>
  90. </html>
  1. <footer id="footer">
  2. <div class="foot-warp">
  3. <p>
  4. © 2015 {:C('SITE_TITLE')} zhaishuaigan@qq.com    豫ICP备13012601号
  5. </p>
  6. </div>
  7. </footer>

运行/Test/index, 显示结果

目前只是实现了简单的解析, 还需要进一步完善, 比如配置啊, 扩展更多的标签啊什么的.