做一个博客系统
年前做的东西,早就想写个博客记录一下,然后就过年了。电脑充满电带回了家,一条电居然撑到了上班。事实证明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。
<?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方法。
<?php
namespace Lib\Base;
interface BaseTemplate
{
public static function render($data);
}
一个Template类必须有一个render方法,这样的设计下,将Template类放在主题的配置数组里,执行构建命令时就可以依次执行每个Template下的render方法来输出静态页了。
markdown解析
直接使用了SegmentFault/HyperDown
库,可以输入markdown输出html字符串。然后在模板渲染里写样式。
模板渲染
先写了一个模板渲染方法。
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片段啥的。比如首页
<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组件
<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>
和不蒜子组件
<!-- 放在页头 -->
<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>
我就可以使用模板渲染方法这样渲染一个主页
$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来代替了。