做一个博客系统

年前做的东西,早就想写个博客记录一下,然后就过年了。电脑充满电带回了家,一条电居然撑到了上班。事实证明mbp的电池是可以在开机状态下合盖待机11天的。

今天的课题是用php做一个静态网站生成器,也叫博客系统。

东西已经做完了,官网是 Hikari 官网,文档里边有,文档本身就是示例,所以这一个地址点进去啥都有。

如果你是在公众号阅读的这篇文章,上边的Hikari官网可能不能点击。你需要点击左下角阅读原文进入原文链接,再点链接进入官网。或者直接复制网址http://hikari.website访问。

文档写得挺详细了,这边就记录一些知识点和坑吧。第一次用php写控制台程序,有很多东西都是之前没用过的。

控制台程序

在php程序中,使用$argc获取控制台参数数量,使用$argv获取控制台参数数组。比较难受的是,就算控制台里按照选项和选项值(command -a 1 -b 2)来输入,$argv也不会给出索引数组,而是将选项也当做一个值。如果要将程序设计成需要分析选项的,就需要特别处理才能获取到选项和选项值的索引数组了。

psr4自动加载

使用composer安装类库的话,项目根目录下就会有vendor目录,我们需要在项目启动的时候引入/vendor/autoload.php,来让composer加载类库。

接口

interface规定程序模板,让实现同一个接口的类都遵循一样的模板。在Hikari中用interface规定了Cmd和Template。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php


namespace Lib\Base;


interface BaseCmd
{
/**
* A command line command must have a `handle` function which is public and static!
* @return mixed
*/
public static function handle($argv);
}

一个Cmd类必须有handle方法,这样才能根据控制台输入找到对应的Cmd类,来执行对应类的handle方法。

1
2
3
4
5
6
7
8
9
10
<?php


namespace Lib\Base;


interface BaseTemplate
{
public static function render($data);
}

一个Template类必须有一个render方法,这样的设计下,将Template类放在主题的配置数组里,执行构建命令时就可以依次执行每个Template下的render方法来输出静态页了。

markdown解析

直接使用了SegmentFault/HyperDown库,可以输入markdown输出html字符串。然后在模板渲染里写样式。

模板渲染

先写了一个模板渲染方法。

1
2
3
4
5
6
7
8
9
10
11
12
function C($filePath, $replaceData = []) {
if (!file_exists($filePath)) {
return "";
}
$contents = file_get_contents($filePath);
if (!empty($replaceData)) {
foreach ($replaceData as $k => $v) {
$contents = str_replace("{{{$k}}}", $v, $contents);
}
}
return $contents;
}

然后准备了一个页面目录pages和组件目录Components,里边存带有模板语法的html片段啥的。比如首页

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
<body>
{{navbar}}
<div class="container">
<img class="logo" src="/hikarilogo.png"></img>
<h2 id="title">
{{title}}
<!-- <span class="version">beta 1</span> -->
</h2>
<h3 id="subtitle">{{subtitle}}</h3>
<div id="menus">
{{menu}}
<script>
((function() {
var menus = document.getElementsByClassName('menu-action')
for (var i = 0; i < menus.length; i ++) {
menus[i].addEventListener('click', function() {
window.location.href = this.getAttribute('link')
})
}
})())
</script>
</div>
</div>
{{footer}}
</body>

footer组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<style>
.footer {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 100px;
color: #3E4857;
font-size: 13px;
}
</style>
<div class="footer">
<div class="footer-author">
使用 <a href="https://gitee.com/xtzero/hikari">Hikari</a> 构建
</div>
<div class="footer-desc">一个简洁、高效、可定制的博客框架。</div>
<div class="footer-statistic">
{{busuanzi}}
</div>
<div class="footer-police">*ICP备*号-*</div>
</div>

和不蒜子组件

1
2
3
4
5
<!-- 放在页头 -->
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

<!-- 显示代码是 -->
<span id="busuanzi_container_site_pv">👁 <span id="busuanzi_value_site_pv">加载中...</span></span>

我就可以使用模板渲染方法这样渲染一个主页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$html = C(THEME_BASE_DIR . '/page/index.html', [
'title' => ENV['title'],
'subtitle' => ENV['subtitle'],
'navbar' => C(THEME_BASE_DIR . '/components/navbar', [
"title" => ENV['title'],
"items" => implode("\n", array_map(function($v) {
return C(THEME_BASE_DIR . '/components/navbarItem', $v);
}, THEME_CONFIG['navbar']))
]),
'menu' => implode("\n", array_map(function($v) {
return C(THEME_BASE_DIR . '/components/indexNav', $v);
}, THEME_CONFIG['homepageMenu'])),
'footer' => C(THEME_BASE_DIR . '/components/footer', [
"busuanzi" => C(THEME_BASE_DIR . '/components/busuanzi')
])
]);

要是模板能支持条件和循环渲染就好了,暂时还没做,只能用implode和array_map来代替了。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!