«

emlog pro 模板 API 大字典

时间:2022-11-12 12:15     作者:独元殇     分类: emlog 文档


介绍

我们对 emlog pro 的模板开发,只需符合本「字典」规范即可,无序探究 emlog pro 是怎么运行的。只要是已经成型的完整网站前端代码,都能一定程度转化为 emlog pro 模版。

因此,为了保障模板的显示质量,以及你的艺术和创意性能够不受 emlog 系统的干扰,强烈要求你在制作模板之前,先通过这个流程【纸上画出草图和创意】--【电脑画出设计稿】--【HTML CSS JS 切图还原】--【工程优化】......... 完事俱全后,再按照本字典,对接 emlog pro。

如果目标就是制作一个 emlog 的模板,那么可以先浏览一遍本字典,大概了解 emlog 对哪些参数的支持比较好,以免以后麻烦。

当然,在此之前,你得略微熟悉 PHP 的语法,知道怎么输出,怎么写函数,变量等等。

系统自带模板「default」 只是一个示范参考,不能做到万事俱全,模板开发事宜,一切以本文内容为准。

这不是模板开发教程!这不是模板开发教程!这不是模板开发教程!这是模板开发的「字典」,供 emlog 开发者复制、粘贴、查询、参考使用的开发规范,或 emlog pro 模板的游戏规则。

预祝使用愉快!

( ps: 制作一个有良好可用性的开发字典是个有挑战性的事,目前这种形式只是一种解决方案,如有更好建议,敬请提出。)

模板文件系统

模板位置

emlog 的模版位置位于 ./content/templates/< 模版文件夹 >。

模板文件(夹)命名规范

模板的「文件夹」名称,为模板的英文名称。

如 default、sunshine。

./content/templates/default/

./content/templates/sunshine/

模板文件夹内部,系统的硬性要求有五个文件,即模板里必须要包含以下五个文件,否则系统会报错。

文件名 介绍
header.php 模板中,博客的 html 头部
log_list.php 模板中,博客的首页(一般为博客文章的列出)
echo_log.php 模板中,博客某个文章的文章阅读页
page.php 模板中,博客某个页面的页面显示页(这个后台有设置,用户也可用其他文件显示,比如 page1.php,但 page.php 是默认,必须有)
404.php 404 页面
preview.jpg 模板在后台「模板外观设置」页面里的预览图。建议尺寸为 300×225 或这个比例。

当然,也有个文件可有,可没有

文件名 介绍
pw.php 文章密码输入页(如果没有这个文件,则使用系统默认的密码输入页)

除了上面这些文件,其余的 php 文件结构,大家可据自己的编码和架构风格来确定,如果是全新制作的模板,可参考系统自带模板 default 的模板代码结构(比如 module.php、side.php、css 文件夹)。

模板文件的调用模式

系统对模板的调用模式

上面的七个文件,是 emlog 系统可以直接获取的七个文件,像 DNA 一样刻在了 emlog 系统核心代码里,一切我们的博客行为,都是系统搭配以上文件来调用的。

这些搭配模式 emlog 只是方便常见的博客行为而设计。大家可灵活运用,来适配自己的模板中博客交互设计方式。

emlog pro 后端程序是以路由映射表来控制我们博客页面的显示,我们可理解成「搭配模式」,或「调用模式」。

现在我们假设,我们有了一个博客,首页域名为 http://127.0.0.1/ ,而且我们也暂时没开「伪静态」。

显示「首页」模式

即访问 http://127.0.0.1/

系统输出 header.php + log_list.php

输出就是,执行上面两文件的 php 代码内容。当然,非直接执行,是系统通过一些措施来执行,上面两个 php 文件可以访问系统的很多变量。比如 php 常量 BLOG_URL (博客的地址)。

阅读某个「博文」模式

如访问 http://127.0.0.1/?post=4 (4 是文章 ID,每个文章或页面都有它独有的 ID 号)

系统输出 header.php + echo_log.php

显示某个「页面」模式

如访问 http://127.0.0.1/?post=6 (6 是页面 ID)

系统输出 header.php + page.php

如果用户在后台设置了其他页面模板,如 page0001,则调用输出相应文件.

系统输出 header.php + page0001.php

显示「作者文章」模式

如访问 http://127.0.0.1/?author=1 (1 是作者 ID)

系统输出 header.php + log_list.php

我们看到,这个和「首页」模式一样。其实此时,emlog pro 向模板传递的数据不一样。这次,只传递了属于这个作者文章的数据。

下面几个模式也一样道理。

显示「归档文章」模式

如访问 http://127.0.0.1/?record=20221110 (显示日期为 2022 年 11 月 10 日的文章)

系统输出 header.php + log_list.php

显示「搜索文章」模式

如访问 http://127.0.0.1/?keyword=emlog(搜索 emlog 后,系统的显示)

系统输出 header.php + log_list.php

显示「分类文章」模式

如访问 http://127.0.0.1/?sort=1 (1 是这个文章分类的 ID)

系统输出 header.php + log_list.php

显示「标签文章」模式

如访问 http://127.0.0.1/?tag=1 (1 是这个标签分类的 ID)

系统输出 header.php + log_list.php

显示「404」模式

如访问 http://127.0.0.1/?post=400 (400 是一个不存在的文章 ID)

系统输出 404.php

显示「密码输入」模式

如访问 http://127.0.0.1/?post=25 (25 是一个有设置密码的文章的 ID)

系统输出 pw.php 或 系统默认的密码输入界面。

前端(模板)怎么知道当前调用模式

这个,目前最简单的办法,就是在前端进行判断。

如果特殊情况下,不想使用 log_list.php 等文件的话(比如我们只是把 emlog pro 当做一个平台,想在此基础上做一些比较复杂的网站的话),可将 log_list.php 等文件空白(空白可以,但一定要有这个文件,当然,如非特别必要,还是建议使用这些系统建议的文件),可以只使用 header.php。

在 hearder.php 文件中,使用类似如下代码进行逻辑判断,这些代码,在 header.php 中是有效的。

<?php
if(isset($record) && isset($page)) {
    echo "当前是「归档」模式,日期数据是".$record."<br>";
    echo "当前是第".$page."页";
}

if(isset($author) && isset($page)) {
    echo "当前是「作者」模式,查询作者的 ID 是".$author."<br>";
    echo "当前是第".$page."页";
}

if(isset($keyword) && isset($page)) {
    echo "当前是「搜索」模式,搜索数据是".$keyword."<br>";
    echo "当前是第".$page."页";
}

if(isset($sortid) && isset($page)) {
    echo "当前是「分类」模式,查询分类的 ID 是".$sortid."<br>";
    echo "当前是第".$page."页";
}

if(isset($tag) && isset($page)) {
    echo "当前是「标签」模式,标签数据是".$tag."<br>";
    echo "当前是第".$page."页";
}

if(isset($type)) {
    if(!empty($password)){
        echo "<br>当前是已经根据之前 cookie 中储存的文章密码而跳转到的文章界面";
    }
    if($type === "blog"){
        echo "<br>当前是「文章」阅读模式";
    }
    if ($type === "page") {
        echo "<br>当前是「页面」显示模式";
    }
}

至于 「404」模式和「密码输入」模式,这个轮不到 header.php 判断,emlog pro 系统会直接只输出 404.php 或 pw.php(或默认的密码输入界面)。

怎么自定义模式

例:自定义「用户搜索模式」

除了上面的模式,我们可能还会有其他的模式需求,比如「用户搜索」模式。

这个如果想实现伪静态的话,是有点麻烦。有这方面需求,建议使用系统面板中的页面来搞定,如果没有,像其他一样,使用 GET 协议来搞定。

假定我们使用 GET,我们访问的链接是 http://127.0.0.1/?userkeyword=Tom ,那么我们代码就可像上面那样判断了。

$sunshine_uk = isset($_GET["userkeyword"]) ? addslashes($_GET["userkeyword"]) : "";
// 为防止出现变量冲突,这些直接在全局声明的变量,最好要带上如 sunshine_ 这样的前缀

if(!empty($sunshine_uk)) {
    echo "当前是「用户搜索」模式,参数值是".$sunshine_uk;
}

目前,模式有了,但业务代码,只能自己去写了......

例:移动设备模式

如果我们的模板并非响应式的,是桌面端一套模板、移动端一套模板,那也可在 header.php 中进行逻辑判断,这里可以使用如下函数。

function is_mobile() {
    $user_agent = $_SERVER['HTTP_USER_AGENT'];
    $mobile_browser = Array(
    "mqqbrowser",  // 手机 QQ 浏览器
    "opera mobi",  // 手机 opera
    "juc","iuc",  // uc 浏览器
    "fennec","ios","applewebKit/420","applewebkit/525","applewebkit/532","ipad","iphone","ipaq","ipod",
    "iemobile", "windows ce",  // windows phone
    "240×320","480×640","acer","android","anywhereyougo.com","asus","audio","blackberry","blazer","coolpad" ,"dopod", "etouch", "hitachi","htc","huawei", "jbrowser", "lenovo","lg","lg-","lge-","lge", "mobi","moto","nokia","phone","samsung","sony","symbian","tablet","tianyu","wap","xda","xde","zte"
    );
    $is_mobile = false;
    foreach ($mobile_browser as $device) {
        if (stristr($user_agent, $device)) {
            $is_mobile = true;
            break;
        }
    }
    return $is_mobile;
}

if(is_mobile()){
    echo "当前是移动设备模式";
}else{
    echo "当前是桌面设备模式";
}

使用 View::getView(); 引入我们的模板文件

View::getView() 的用法如下。

// 一般,我们在模板 php 代码中引入除上述七个系统必要的文件之外的 php 文件时
// 可能会使用 require_once include 语句,如下
require_once 'function.php';
include 'footer.php';

// 而在 emlog 模板中,我们统一使用如下语句来代替后面的内容
require_once View::getView("function");
include View::getView("footer");

使用 View::getView() 与直接使用 require、include 的区别有一个。

提示一下:

require 和 include 的区别?

require 生成一个致命错误(E_COMPILE_ERROR),在错误发生后脚本会停止执行。
include 生成一个警告(E_WARNING),在错误发生后脚本会继续执行。

模板的代码规范

emlog pro 版本的模板,必须符合以下的代码规范。否则将是不合格的模板。

模板体积

体积应以精简为本。最好不要超过 5MB,否则无法在官方商店上线。

模板信息

模板信息要写在 header.php 中,内容很简单。我们假设以「阳光」为例,以下是一个案例。

含义依次为「模板名(最好是中文名)」、「模板的官方 url」、「模板版本号」、「模板的简介」、「模板作者昵称」、「模板作者的个人主页 url」。

这些内容建议尽量不要留空。

/*
Template Name:阳光
Template Url:https://www.test.com/sunshine/
Version:1.3.3
Description:这是一个以「阳光」为主题的模板,简约大方,适合做个人生活、心情记录使用
Author:张三
Author Url:https://www.test.com
*/

防跨权限访问

为防止模板文件被直接访问(有暴露系统敏感信息的隐患),固在模板中的所有 php 文件的最开头,都应有如下代码。

if(!defined('EMLOG_ROOT')) {exit('error!');}

模板文件调用 getView

模板中的 php 文件可分为两种。

对于第一类,函数库、组件库文件,比如这个 php 文件中有一些计算日期类的函数等等,使用以下语句引入。如 function.php。

require_once View::getView("function");

对于第二类,主要是储存前端 HTML 代码的 php 文件,比如 side.php、footer.php,我们使用以下语句引入。

include View::getView("footer");

模板钩子(挂载点)

为了紧密配合 emlog pro 系统钩子机制的正常运行,每个模板中都应有如下六个挂载点。

挂载点代码 挂载点含义 挂载点位置
<?php doAction('index_head') ?> HTML 头部。用于向博客添加 CSS 等内容。 模板中 HTML 里 <head>标签的最后面。
<?php doAction('index_navi_ext') ?> 导航栏上的扩展。可用于向导航栏上添加内容,比如插件的页面,或一些类似搜索的小组件。 模板中导航栏 HTML 代码的最后面。
<?php doAction('index_loglist_top');?> 首页的内容区最开始。可用于添加主页的公告等。 模板中,首页导航栏外后,首页主体内容的最开头。
<?php doAction('log_related', $logData) ?> 添加文章相关内容,比如“打赏”、“收藏、“分享”。 模板中,文章阅读页,紧邻文章阅读结尾的区域。
<?php doAction('diff_side'); ?> 侧边栏控制点。【非必须】 侧边栏组件上方。
<?php doAction('index_footer') ?> 足部扩展。用于系统和插件在博客页脚处输出内容以及添加 JS 脚本内容。 博客模板页脚处内容区。

因为各模板各皆有差异,详细位置不做严格要求,但一定要保证挂载点在插件调用时能发挥其应有的作用。

安全方面

因前端模板的性质比较特殊,不能将 XSS 隐患一概过滤,但还是应十分谨慎。

对于用户输入的内容,以及系统输出的内容,如果不是 emlog pro 自带的交互功能,而理论上也不应包含 < script > 的地方,都应使用 php 进行代码过滤。(比如接收网址里的 GET 参数)

示例如下:

$action = isset($_GET["action"]) ? addslashes($_GET["action"]) : "";

SEO

网站 SEO 优化以个人经验量力而行。这里给出两个建议。

  1. 在做完模板后,可验证一下 W3C :https://validator.w3.org/ 可以避免犯一些 HTML 语法上的错误。当然它的这些建议仅供参考。
  2. 可以使用 Chrome 浏览器自带的 dev tool 工具中的 lighthouse 工具来跑一下分,它会给出一些 SEO 上的优化建议。

模板主要变量信息获取

<?= $someValue ?> 是 php 的一种简写语法,等同于 <?php echo $somevalue; ?>

模板 head 头部

代码 (代码描述)输出示例 备注
<?= $site_title ?> (站点标题)张三的博客 用户可在后台 SEO 中设置 ,这是站点浏览器标签页标题
<?= $site_key ?> (站点关键字)张三 大学生 运动 摄影 个人网站 用户可在后台 SEO 中设置
<?= $site_description ?> (站点描述/文章描述)张三分享自己的生活,写一些心灵感悟。 1.在首页,它是站点描述。2.在文章阅读页,它是文章的摘要。
<?= BLOG_URL ?> (站点的首页 URL )http://127.0.0.1 可用于引入站点的浏览器图标等
<?= TEMPLATE_URL ?> (站点模板的 URL)http://127.0.0.1/content/templates 可用于向前台引入模板一些 CSS 文件等。

模板页顶

代码 (代码描述)输出示例 备注
<?= BLOG_URL ?> ( 站点的首页 URL)http://127.0.0.1 可用于设置博客标题< a >标签 href
<?= $blogname ?> (博客标题)张三博客 HTML 页面显示的博客标题
<?= $bloginfo ?> (博客副标题)记录心情、生活、照片..... HTML 页面显示的博客副标题

文章列出页(文章目录页)

$logs 是博客首页在当前请求下,系统给出的所有文章目录的集合。可以先判断一下,$log 是否为空。然后再循环输出文章。

if(!empty($logs)) {
    foreach ($logs as $value) {
        if (!empty($value['log_cover'])) {  // 是否设置了「文章封面」图片
            echo '封面图片地址是' . $value['log_cover'];
        }
    }
} else {
    echo '没有文章';
}

其他

缓存,也就是

模板向系统信息的传递

模板 Ajax 获取内容

模板设置

emlog pro 函数大礼包

额......其实吧,开发模板,有这么几种情况:

如果已经有 html 了,那很简单可以照搬过来,毕竟只是后端往 html 里玩几个填字游戏而已。用不到什么更多的 API 手册了。

如果没有,只是仿站,那大多数情况下是面对一些简单要求的客户的,那尽可寥寥草草套换一下,也费不了什么功夫。

如果只是做着玩,0 开始,那...... 为什么不直接在 默认模版的基础上删删减减呢?

时间宝贵,效率宝贵,有可用性好的轮子,就不要重复造轮子,就不要重复造轮子,就不要重复造轮子!!!对自己,对别人,对未来,都好。不丢脸。

因此,在下面,我不像上面一样更新什么细节了,直接把 默认模板的重要文件(除 CSS)给放到下面。

header.php

<?php
/*
Template Name:默认模板
Template Url:https://www.emlog.net/template/
Description:这是emlog pro的默认模板
Author:emlog官方
Author Url:https://www.emlog.net
*/
if (!defined('EMLOG_ROOT')) {
    exit('error!');
}
require_once View::getView('module');
?>
<!doctype html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title><?= $site_title ?></title>
    <meta name="keywords" content="<?= $site_key ?>"/>
    <meta name="description" content="<?= $site_description ?>"/>
    <base href="<?= BLOG_URL ?>"/>
    <link rel="shortcut icon" href="<?= BLOG_URL ?>favicon.ico"/>
    <link rel="alternate" title="RSS" href="<?= BLOG_URL ?>rss.php" type="application/rss+xml"/>
    <link href="<?= TEMPLATE_URL ?>css/style.css?t=<?= Option::EMLOG_VERSION_TIMESTAMP ?>" rel="stylesheet" type="text/css"/>
    <link href="<?= TEMPLATE_URL ?>css/markdown.css?t=<?= Option::EMLOG_VERSION_TIMESTAMP ?>" rel="stylesheet" type="text/css"/>
    <script src="<?= TEMPLATE_URL ?>js/jquery.min.3.5.1.js?v=<?= Option::EMLOG_VERSION_TIMESTAMP ?>"></script>
    <script>function sendinfo(url) {  // 日历生成和翻页
            $("#calendar").load(url)
        }</script>
    <?php doAction('index_head') ?>
</head>

<body>
<nav class="blog-header">
    <div class="blog-header-c container">
        <a class="blog-header-title" href="<?= BLOG_URL ?>"><?= $blogname ?></a>
        <div class="blog-header-subtitle subtitle-overflow" title="<?= $bloginfo ?>"><?= $bloginfo ?></div>
        <div class="blog-header-toggle">
            <svg class="blogtoggle-icon">
                <rect x="1" y="1" fill="#5F5F5F" width="26" height="1.6"/>
                <rect x="1" y="8" fill="#5F5F5F" width="26" height="1.6"/>
                <rect x="1" y="15" fill="#5F5F5F" width="26" height="1.6"/>
            </svg>
        </div>

        <?php blog_navi() ?>
        <?php doAction('index_navi_ext') ?>

    </div>
</nav>

log_list.php

<?php
/**
 * 首页模板
 */
if (!defined('EMLOG_ROOT')) {
    exit('error!');
}
?>
    <main class="container blog-container">
        <div class="row">
            <div class="column-big">
                <?php doAction('index_loglist_top');
                if (!empty($logs)):
                    foreach ($logs as $value):
                        ?>
                        <div class="shadow-theme bottom-5">
                            <?php if (!empty($value['log_cover'])) : ?>
                                <div class="loglist-cover">
                                    <img src="<?= $value['log_cover'] ?>" alt="article cover" class="rea-width" data-action="zoom">
                                </div>
                            <?php endif ?>
                            <div class="card-padding loglist-body">
                                <h3 class="card-title">
                                    <a href="<?= $value['log_url'] ?>" class="loglist-title"><?= $value['log_title'] ?></a>
                                    <?php topflg($value['top'], $value['sortop'], isset($sortid) ? $sortid : '') ?>
                                    <?php bloglist_sort($value['logid']) ?>
                                </h3>
                                <div class="loglist-content markdown"><?= $value['log_description'] ?></div>
                                <div class="loglist-tag"><?php blog_tag($value['logid']) ?></div>
                            </div>
                            <hr class="list-line"/>
                            <div class="row info-row">
                                <div class="log-info">
                                    <?php blog_author($value['author']) ?>&nbsp;发布于&nbsp;
                                    <?= date('Y-n-j H:i', $value['date']) ?>&nbsp;
                                    <span class="mh"><?php editflg($value['logid'], $value['author']) ?></span>
                                </div>
                                <div class="log-count">
                                    <a href="<?= $value['log_url'] ?>#comment">评论(<?= $value['comnum'] ?>)&nbsp;</a>
                                    <a href="<?= $value['log_url'] ?>">浏览(<?= $value['views'] ?>)</a>
                                </div>
                            </div>
                        </div>
                    <?php
                    endforeach;
                else:
                    ?>
                    <p>抱歉,暂时还没有内容。</p>
                <?php endif ?>
                <div class="pagination bottom-5">
                    <?= $page_url ?>
                </div>
            </div>
            <?php include View::getView('side') ?>
        </div>
    </main>

<?php include View::getView('footer') ?>

footer.php

<?php
/**
 * 页面底部信息
 */
if (!defined('EMLOG_ROOT')) {
    exit('error!');
}
?>
<footer class="blog-footer">
    <div class="container footinfo">
        <?php
        if (!empty($icp)) {
            echo '<div><a href="https://beian.miit.gov.cn/" target="_blank">' . $icp . '</a></div>';
        }
        ?>
        <?= $footer_info ?>
        <?php doAction('index_footer') ?>
    </div>
</footer>
<script src="<?= TEMPLATE_URL ?>js/common_tpl.js?t=<?= Option::EMLOG_VERSION_TIMESTAMP ?>"></script>
<script src="<?= TEMPLATE_URL ?>js/zoom.js?t=<?= Option::EMLOG_VERSION_TIMESTAMP ?>"></script>
</body>
</html>

echo_log.php

<?php
/**
 * 阅读文章页面
 */
if (!defined('EMLOG_ROOT')) {
    exit('error!');
}
?>
<article class="container log-con blog-container">
    <span class="back-top mh" onclick="history.go(-1);">&laquo;</span>
    <h1 class="log-title"><?php topflg($top) ?><?= $log_title ?></h1>
    <p class="date">
        <b>时间:</b><?= date('Y-n-j H:i', $date) ?>&nbsp;&nbsp;&nbsp;&nbsp;
        <b>作者:</b><?php blog_author($author) ?>&nbsp;&nbsp;&nbsp;&nbsp;
        <b>分类:</b><?php blog_sort($logid) ?>
        <?php editflg($logid, $author) ?>
    </p>
    <hr class="bottom-5"/>
    <div class="markdown" id="emlogEchoLog"><?= $log_content ?></div>
    <p class="top-5"><?php blog_tag($logid) ?></p>

    <?php doAction('log_related', $logData) ?>

    <nav class="neighbor-log"><?php neighbor_log($neighborLog) ?></nav>

    <?php blog_comments_post($logid, $ckname, $ckmail, $ckurl, $verifyCode, $allow_remark) ?>
    <?php blog_comments($comments) ?>

    <div style="clear:both;"></div>
</article>
<?php include View::getView('footer') ?>

page.php

<?php
/**
 * 自建页面模板
 */
if (!defined('EMLOG_ROOT')) {
    exit('error!');
}
?>
    <article class="container blog-container">
        <div class="row">
            <div class="column-big log-con " id="page">
                <h1 class="page-title"><?= $log_title ?></h1>
                <div class="markdown">
                    <?= $log_content ?>
                </div>
                <?php blog_comments_post($logid, $ckname, $ckmail, $ckurl, $verifyCode, $allow_remark) ?>
                <?php blog_comments($comments) ?>
            </div>
            <?php
            include View::getView('side');
            ?>
        </div>
    </article>
<?php
include View::getView('footer');
?>

pw.php

<?php
/**
 * 加密文章输入密码页面
 */
if (!defined('EMLOG_ROOT')) {
    exit('error!');
}
?>
<!doctype html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>请输入文章访问密码</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f5f5f5;
        }

        form {
            background-color: #fff;
            border: 1px solid #ccc;
            border-radius: 5px;
            margin: 20px auto;
            max-width: 500px;
            padding: 20px;
        }

        h1 {
            font-size: 24px;
            color: #333333;
            margin: 0 0 20px;
            text-align: center;
        }

        input[type="password"] {
            border-radius: 3px;
            border: 1px solid #ccc;
            font-size: 14px;
            height: 25px;
            padding: 8px;
            width: calc(100% - 100px);
        }

        button[type="submit"] {
            background-color: #007bff;
            border: none;
            border-radius: 3px;
            color: #fff;
            cursor: pointer;
            font-size: 16px;
            font-weight: bold;
            height: 40px;
            margin-left: 10px;
            transition: all .3s ease-in-out;
            width: 100px;
        }

        button[type="submit"]:hover {
            background-color: #0069d9;
        }

        a {
            color: #007bff;
            display: block;
            margin-top: 20px;
            text-align: center;
            text-decoration: none;
            font-size: 14px;
        }
    </style>
</head>
<body>
<form action="" method="post">
    <h1>请输入文章访问密码</h1>
    <div style="display: flex;">
        <input type="password" id="logpwd" name="logpwd" required autofocus>
        <button type="submit">提交</button>
    </div>
    <a href="<?= BLOG_URL ?>">&larr;返回首页</a>
</form>
</body>
</html>

404.php

<?php
/**
 * 自定义404页面
 */
if (!defined('EMLOG_ROOT')) {
    exit('error!');
}
?>
<!doctype html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <title>错误提示-页面未找到</title>
    <style>
        body {
            background-color: #F7F7F7;
            font-family: Arial;
            font-size: 12px;
            line-height: 150%
        }

        .main {
            background-color: #FFFFFF;
            font-size: 12px;
            color: #666666;
            width: 650px;
            margin: 60px auto 0px;
            padding: 30px 10px;
            box-shadow: 0 2px 8px 0 rgba(0, 0, 0, .02);
            border-radius: 10px;
            transition: box-shadow 0.4s
        }

        .main p {
            text-align: center;
            font-weight: 600;
            font-size: 2rem
        }

        .main p a {
            border: 1px solid #ccc !important;
            padding: 8px;
            border-radius: 10px !important;
            color: #929292;
            font-size: initial;
            text-decoration: none
        }
    </style>
</head>
<body>
<div class="main">
    <p>404 Not Found !</p>
    <p><a href="<?= BLOG_URL ?>">首页</a></p>
</div>
</body>
</html>

module.php

<?php
/**
 * 侧边栏组件、页面模块
 */
if (!defined('EMLOG_ROOT')) {
    exit('error!');
}
?>
<?php
/**
 * 侧边栏:链接
 */
function widget_link($title) {
    global $CACHE;
    $link_cache = $CACHE->readCache('link');
    //if (!blog_tool_ishome()) return;#只在首页显示友链去掉双斜杠注释即可
    ?>
    <div class="widget shadow-theme">
        <div class="widget-title">
            <h3><?= $title ?></h3>
        </div>
        <ul class="widget-list no-margin-bottom unstyle-li">
            <?php foreach ($link_cache as $value): ?>
                <li><a href="<?= $value['url'] ?>" title="<?= $value['des'] ?>" target="_blank"><?= $value['link'] ?></a></li>
            <?php endforeach ?>
        </ul>
    </div>
<?php } ?>
<?php
/**
 * 侧边栏:个人资料
 */
function widget_blogger($title) {
    global $CACHE;
    $user_cache = $CACHE->readCache('user');
    $name = $user_cache[1]['name'] ?>
    <div class="widget shadow-theme">
        <div class="widget-title">
            <h3><?= $title ?></h3>
        </div>
        <div class="unstyle-li bloggerinfo">
            <?php if (!empty($user_cache[1]['photo']['src'])): ?>
                <div>
                    <img class='bloggerinfo-img' src="<?= BLOG_URL . $user_cache[1]['photo']['src'] ?>" alt="blogger"/>
                </div>
            <?php endif ?>
            <div class='bloginfo-name'><b><?= $name ?></b></div>
            <div class='bloginfo-descript'><?= $user_cache[1]['des'] ?></div>
        </div>
    </div>
<?php } ?>
<?php
/**
 * 侧边栏:日历
 */
function widget_calendar($title) { ?>
    <div class="widget shadow-theme">
        <div class="widget-title m">
            <h3><?= $title ?></h3>
        </div>
        <div class="unstyle-li">
            <div id="calendar"></div>
            <script>sendinfo('<?= Calendar::url() ?>', 'calendar');</script>
        </div>
    </div>
<?php } ?>
<?php
/**
 * 侧边栏:标签
 */
function widget_tag($title) {
    global $CACHE;
    $tag_cache = $CACHE->readCache('tags') ?>
    <div class="widget shadow-theme">
        <div class="widget-title m">
            <h3><?= $title ?></h3>
        </div>
        <div class="unstyle-li tag-container">
            <?php foreach ($tag_cache as $value): ?>
                <span style="font-size:<?= $value['fontsize'] ?>pt; line-height:30px;">
            <a href="<?= Url::tag($value['tagurl']) ?>" title="<?= $value['usenum'] ?> 篇文章" class='tags-side'><?= $value['tagname'] ?></a></span>
            <?php endforeach ?>
        </div>
    </div>
<?php } ?>
<?php
/**
 * 侧边栏:分类
 */
function widget_sort($title) {
    global $CACHE;
    $sort_cache = $CACHE->readCache('sort') ?>
    <div class="widget shadow-theme">
        <div class="widget-title m">
            <h3><?= $title ?></h3>
        </div>
        <ul class="unstyle-li log-classify-f">
            <?php
            foreach ($sort_cache as $value):
                if ($value['pid'] != 0) continue;
                ?>
                <li>
                    <a href="<?= Url::sort($value['sid']) ?>" title="<?= $value["description"] ?>"><?= $value['sortname'] ?>
                        &nbsp;&nbsp;<?= (($value['lognum']) > 0) ? '(' . ($value['lognum']) . ')' : '' ?></a>
                    <?php if (!empty($value['children'])): ?>
                        <ul class="log-classify-c">
                            <?php
                            $children = $value['children'];
                            foreach ($children as $key):
                                $value = $sort_cache[$key];
                                ?>
                                <li>
                                    <a href="<?= Url::sort($value['sid']) ?>" title="<?= $value["description"] ?>">--&nbsp;&nbsp;<?= $value['sortname'] ?>
                                        &nbsp;&nbsp;(<?= $value['lognum'] ?>)</a>
                                </li>
                            <?php endforeach ?>
                        </ul>
                    <?php endif ?>
                </li>
            <?php endforeach ?>
        </ul>
    </div>
<?php } ?>
<?php
/**
 * 侧边栏:最新评论
 */
function widget_newcomm($title) {
    global $CACHE;
    $com_cache = $CACHE->readCache('comment');
    $isGravatar = Option::get('isgravatar');
    ?>
    <div class="widget shadow-theme">
        <div class="widget-title">
            <h3><?= $title ?></h3>
        </div>
        <hr>
        <ul class="unstyle-li">
            <?php
            foreach ($com_cache as $value):
                $url = Url::comment($value['gid'], $value['page'], $value['cid']);
                ?>
                <li class="comment-info">
                    <?php if ($isGravatar == 'y'): ?>
                        <img class='comment-info_img' src="<?= getGravatar($value['mail']) ?>" alt="commentator"/>
                    <?php endif ?>
                    <span class='comm-lates-name'><?= $value['name'] ?></span>
                    <span class='logcom-latest-time'><?= smartDate($value['date']) ?></span><br/>
                    <a href="<?= $url ?>"><?= $value['content'] ?></a>
                    <hr>
                </li>
            <?php endforeach ?>
        </ul>
    </div>
<?php } ?>
<?php
/**
 * 侧边栏:最新文章
 */
function widget_newlog($title) {
    global $CACHE;
    $newLogs_cache = $CACHE->readCache('newlog');
    ?>
    <div class="widget shadow-theme">
        <div class="widget-title m">
            <h3><?= $title ?></h3>
        </div>
        <ul class="unstyle-li">
            <?php foreach ($newLogs_cache as $value): ?>
                <li class="blog-lates"><a href="<?= Url::log($value['gid']) ?>"><?= $value['title'] ?></a></li>
            <?php endforeach ?>
        </ul>
    </div>
<?php } ?>
<?php
/**
 * 侧边栏:热门文章
 */
function widget_hotlog($title) {
    $index_hotlognum = Option::get('index_hotlognum');
    $Log_Model = new Log_Model();
    $hotLogs = $Log_Model->getHotLog($index_hotlognum) ?>
    <div class="widget shadow-theme">
        <div class="widget-title m">
            <h3><?= $title ?></h3>
        </div>
        <ul class="unstyle-li">
            <?php foreach ($hotLogs as $value): ?>
                <li class="blog-hot"><a href="<?= Url::log($value['gid']) ?>"><?= $value['title'] ?></a></li>
            <?php endforeach ?>
        </ul>
    </div>
<?php } ?>
<?php
/**
 * 侧边栏:搜索
 */
function widget_search($title) { ?>
    <div class="widget shadow-theme">
        <div class="widget-title">
            <h3><?= $title ?></h3>
        </div>
        <div class="unstyle-li" style="text-align: center;">
            <form name="keyform" method="get" action="<?= BLOG_URL ?>index.php">
                <input name="keyword" class="search form-control" autocomplete="off" aria-label="Search" type="text"/>
                <input type="submit" value="搜索">
            </form>
        </div>
    </div>
<?php } ?>
<?php
/**
 * 侧边栏:归档
 */
function widget_archive($title) {
    $bar_id = "36";
    global $CACHE;
    $record_cache = $CACHE->readCache('record');
    ?>
    <div class="widget shadow-theme">
        <div class="widget-title m">
            <h3><?= $title ?></h3>
        </div>
        <select id="archive" class="archive">
            <?php foreach ($record_cache as $value): ?>
                <option value="<?= Url::record($value['date']) ?>"><?= $value['record'] ?>&nbsp;(<?= $value['lognum'] ?>)</option>
            <?php endforeach ?>
        </select>
    </div>
<?php } ?>
<?php
/**
 * 侧边栏:自定义组件
 */
function widget_custom_text($title, $content) { ?>
    <div class="widget shadow-theme">
        <div class="widget-title m">
            <h3><?= $title ?></h3>
        </div>
        <ul class="unstyle-li">
            <?= $content ?>
        </ul>
    </div>
<?php } ?>
<?php
/**
 * 页顶:导航
 */
function blog_navi() {
    global $CACHE;
    $navi_cache = $CACHE->readCache('navi');
    ?>
    <div class="blog-header-nav" id="navbarResponsive">
        <ul class="nav-list">
            <?php
            foreach ($navi_cache as $value):
                if ($value['pid'] != 0) {
                    continue;
                }
                if ($value['url'] == 'admin' && (!User::isVistor())):
                    ?>
                    <li class="list-item list-menu"><a href="<?= BLOG_URL ?>admin/" class="nav-link">管理</a></li>
                    <li class="list-item list-menu"><a href="<?= BLOG_URL ?>admin/account.php?action=logout" class="nav-link">退出</a></li>
                    <?php
                    continue;
                endif;
                $newtab = $value['newtab'] == 'y' ? 'target="_blank"' : '';
                $value['url'] = $value['isdefault'] == 'y' ? BLOG_URL . $value['url'] : trim($value['url'], '/');
                $current_tab = BLOG_URL . trim(Dispatcher::setPath(), '/') == $value['url'] ? 'active' : '';
                ?>
                <?php if (!empty($value['children']) || !empty($value['childnavi'])) : ?>
                <li class="list-item list-menu">
                    <?php if (!empty($value['children'])): ?>
                        <a class="nav-link has-down" id="nav_link" href="<?= $value['url'] ?>" <?= $newtab ?>><?= $value['naviname'] ?></a>
                        <ul class="dropdown-menus">
                            <?php foreach ($value['children'] as $row) {
                                echo '<li class="list-item list-menu"><a class="nav-link" href="' . Url::sort($row['sid']) . '">' . $row['sortname'] . '</a></li>';
                            } ?>
                        </ul>
                    <?php endif ?>
                    <?php if (!empty($value['childnavi'])) : ?>
                        <a class='nav-link has-down' id="nav_link" <?= $newtab ?> ><?= $value['naviname'] ?></a>
                        <ul class="dropdown-menus">
                            <?php foreach ($value['childnavi'] as $row) {
                                $newtab = $row['newtab'] == 'y' ? 'target="_blank"' : '';
                                echo '<li class="list-item list-menu"><a class="nav-link" href="' . $row['url'] . "\" $newtab >" . $row['naviname'] . '</a></li>';
                            } ?>
                        </ul>
                    <?php endif ?>
                </li>
            <?php else: ?>
                <li class="list-item list-menu"><a class="nav-link" href="<?= $value['url'] ?>" <?= $newtab ?>><?= $value['naviname'] ?></a></li>
            <?php endif ?>
            <?php endforeach ?>
        </ul>
    </div>
<?php } ?>
<?php
/**
 * 文章列出卡片:置顶标志
 */
function topflg($top, $sortop = 'n', $sortid = null) {
    $ishome_flg = '<span title="首页置顶" class="log-topflg" >置顶</span>';
    $issort_flg = '<span title="分类置顶" class="log-topflg" >分类置顶</span>';
    if (blog_tool_ishome()) {
        echo $top == 'y' ? $ishome_flg : '';
    } elseif ($sortid) {
        echo $sortop == 'y' ? $issort_flg : '';
    }
}

?>
<?php
/**
 * 文章详情页:编辑链接
 */
function editflg($logid, $author) {
    $editflg = User::haveEditPermission() || $author == UID ? '&nbsp;&nbsp;&nbsp;<a href="' . BLOG_URL . 'admin/article.php?action=edit&gid=' . $logid . '" target="_blank">编辑</a>' : '';
    echo $editflg;
}

?>
<?php
/**
 * 文章详情页:分类
 */
function blog_sort($blogid) {
    $Log_Model = new Log_Model();
    $logInfo = $Log_Model->getDetail($blogid);
    $sortID = isset($logInfo['sid']) ? $logInfo['sid'] : '';
    $sortName = isset($logInfo['sortname']) ? $logInfo['sortname'] : '';
    ?>
    <?php if (!empty($sortName)) { ?>
        <a href="<?= Url::sort($sortID) ?>"><?= $sortName ?></a>
    <?php } else { ?>
        <a href="#" title="未分类">无</a>
    <?php }
} ?>
<?php
/**
 * 首页文章列表:分类
 */
function bloglist_sort($blogid) {
    $Log_Model = new Log_Model();
    $logInfo = $Log_Model->getDetail($blogid);
    $sortID = isset($logInfo['sid']) ? $logInfo['sid'] : '';
    $sortName = isset($logInfo['sortname']) ? $logInfo['sortname'] : '';
    ?>
    <?php if (!empty($sortName)) { ?>
        <span class="loglist-sort">
            <a href="<?= Url::sort($sortID) ?>"><?= $sortName ?></a>
        </span>
    <?php }
} ?>
<?php
/**
 * 首页文章列表和文章详情页:标签
 */
function blog_tag($blogid) {
    $tag_model = new Tag_Model();
    $tag_ids = $tag_model->getTagIdsFromBlogId($blogid);
    $tag_names = $tag_model->getNamesFromIds($tag_ids);
    if (!empty($tag_names)) {
        $tag = '标签:';
        foreach ($tag_names as $key => $value) {
            $tag .= "    <a href=\"" . Url::tag(rawurlencode($value)) . "\" class='tags' title='标签' >" . htmlspecialchars($value) . '</a>';
        }
        echo $tag;
    }
}

?>
<?php
/**
 * 首页文章列表和文章详情页:作者
 */
function blog_author($uid) {
    $User_Model = new User_Model();
    $user_info = $User_Model->getOneUser($uid);
    $author = $user_info['nickname'];
    echo '<a href="' . Url::author($uid) . "\">$author</a>";
}

?>
<?php
/**
 * 文章详情页:相邻文章
 */
function neighbor_log($neighborLog) {
    extract($neighborLog) ?>
    <?php if ($prevLog): ?>
        <span class="prev-log"><a href="<?= Url::log($prevLog['gid']) ?>" title="<?= $prevLog['title'] ?>">上一篇</a></span>
    <?php endif ?>
    <?php if ($nextLog): ?>
        <span class="next-log"><a href="<?= Url::log($nextLog['gid']) ?>" title="<?= $nextLog['title'] ?>">下一篇</a></span>
    <?php endif ?>
<?php } ?>
<?php
/**
 * 文章详情页:评论列表
 */
function blog_comments($comments) {
    extract($comments);
    if ($commentStacks): ?>
        <div class="comment-header"><b>评论:</b></div>
    <?php endif ?>
    <?php
    $isGravatar = Option::get('isgravatar');

    foreach ($commentStacks as $cid):
        $comment = $comments[$cid];
        $comment['poster'] = $comment['url'] ? '<a href="' . $comment['url'] . '" rel="external nofollow" target="_blank">' . $comment['poster'] . '</a>' : $comment['poster'];
        ?>
        <div class="comment" id="<?= $comment['cid'] ?>">
            <?php if ($isGravatar == 'y'): ?>
                <div class="avatar"><img src="<?= getGravatar($comment['mail']) ?>" alt="avatar"/></div>
                <div class="comment-infos">
                    <div class="arrow"></div>
                    <b><?= $comment['poster'] ?> </b><span class="comment-time"><?= $comment['date'] ?></span>
                    <div class="comment-content"><?= $comment['content'] ?></div>
                    <div class="comment-reply">
                        <button class="com-reply comment-replay-btn">回复</button>
                    </div>
                </div>
            <?php else: ?>
                <div class="comment-infos-unGravatar">
                    <b><?= $comment['poster'] ?> </b><span class="comment-time"><?= $comment['date'] ?></span>
                    <div class="comment-content"><?= $comment['content'] ?></div>
                    <div class="comment-reply">
                        <button class="com-reply comment-replay-btn">回复</button>
                    </div>
                </div>
            <?php endif ?>
            <?php blog_comments_children($comments, $comment['children']) ?>
        </div>
    <?php endforeach ?>
    <div id="pagenavi">
        <?= $commentPageUrl ?>
    </div>
<?php } ?>
<?php
/**
 * 文章详情页:子评论
 */
function blog_comments_children($comments, $children) {
    $isGravatar = Option::get('isgravatar');
    foreach ($children as $child):
        $comment = $comments[$child];
        $comment['poster'] = $comment['url'] ? '<a href="' . $comment['url'] . '" rel="external nofollow" target="_blank">' . $comment['poster'] . '</a>' : $comment['poster'];
        ?>
        <div class="comment comment-children" id="<?= $comment['cid'] ?>">
            <?php if ($isGravatar == 'y'): ?>
                <div class="avatar"><img src="<?= getGravatar($comment['mail']) ?>" alt="commentator"/></div>
                <div class="comment-infos">
                    <div class="arrow"></div>
                    <b><?= $comment['poster'] ?> </b><span class="comment-time"><?= $comment['date'] ?></span>
                    <div class="comment-content"><?= $comment['content'] ?></div>
                    <?php if ($comment['level'] < 4): ?>
                        <div class="comment-reply">
                            <button class="com-reply comment-replay-btn">回复</button>
                        </div><?php endif ?>
                </div>
            <?php else: ?>
                <div class="comment-infos-unGravatar">
                    <b><?= $comment['poster'] ?> </b><span class="comment-time"><?= $comment['date'] ?></span>
                    <div class="comment-content"><?= $comment['content'] ?></div>
                    <?php if ($comment['level'] < 4): ?>
                        <div class="comment-reply">
                            <button class="com-reply comment-replay-btn">回复</button>
                        </div><?php endif ?>
                </div>
            <?php endif ?>
            <?php blog_comments_children($comments, $comment['children']) ?>
        </div>
    <?php endforeach ?>
<?php } ?>
<?php
/**
 * 文章详情页:评论表单
 */
function blog_comments_post($logid, $ckname, $ckmail, $ckurl, $verifyCode, $allow_remark) {
    $isNeedChinese = Option::get('comment_needchinese');
    if ($allow_remark == 'y'): ?>
        <div id="comments">
            <div class="comment-post" id="comment-post">
                <div class="cancel-reply" id="cancel-reply" style="display:none">
                    <button class="comment-replay-btn">取消回复</button>
                </div>
                <form class="commentform" method="post" name="commentform" action="<?= BLOG_URL ?>index.php?action=addcom" id="commentform"
                      is-chinese="<?= $isNeedChinese ?>">
                    <input type="hidden" name="gid" value="<?= $logid ?>"/>
                    <textarea class="form-control log_comment" name="comment" id="comment" rows="10" tabindex="4" required></textarea>
                    <?php if (User::isVistor()): ?>
                        <div class="comment-info" id="comment-info">
                            <input class="form-control com_control comment-name" id="info_n" autocomplete="off" type="text" name="comname" maxlength="49"
                                   value="<?= $ckname ?>" size="22"
                                   tabindex="1" placeholder="昵称*" required/>
                            <input class="form-control com_control comment-mail" id="info_m" autocomplete="off" type="text" name="commail" maxlength="128"
                                   value="<?= $ckmail ?>" size="22"
                                   tabindex="2" placeholder="邮箱"/>
                            <input class="form-control com_control comment-url" id="info_u" autocomplete="off" type="text" name="comurl" maxlength="128"
                                   value="<?= $ckurl ?>" size="22"
                                   tabindex="3" placeholder="个人主页"/>
                        </div>
                    <?php endif ?>

                    <span class="com_submit_p">
                        <input class="btn"<?php if ($verifyCode != "") { ?> type="button" data-toggle="modal" data-target="#myModal"<?php } else { ?> type="submit" <?php } ?>
                               id="comment_submit" value="发布评论" tabindex="6"/>
                    </span>
                    <?php if ($verifyCode != "") { ?>
                        <!-- 验证窗口 -->
                        <div class="modal" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
                            <div class="modal-dialog">
                                <div class="modal-content" style="display: table-cell;">
                                    <div class="modal-header" style="border-bottom: 0px;">
                                        输入验证码
                                    </div>
                                    <?= $verifyCode ?>
                                    <div class="modal-footer" style="border-top: 0px;">
                                        <button type="button" class="btn" id="close-modal" data-dismiss="modal">关闭</button>
                                        <button type="submit" class="btn" id="comment_submit2">提交</button>
                                    </div>
                                </div>
                            </div>
                            <div class="lock-screen"></div>
                        </div>
                        <!-- 验证窗口(end) -->
                    <?php } ?>
                    <input type="hidden" name="pid" id="comment-pid" value="0" tabindex="1"/>
                </form>
            </div>
        </div>
    <?php endif ?>
<?php } ?>
<?php
/**
 * 判断函数:是否是首页
 */
function blog_tool_ishome() {
    if (BLOG_URL . trim(Dispatcher::setPath(), '/') == BLOG_URL) {
        return true;
    } else {
        return FALSE;
    }
}
?>

side.php

<?php
/**
 * 侧边栏
 */
if (!defined('EMLOG_ROOT')) {
    exit('error!');
}
?>
<div class="column-small side-bar">
    <?php
    $widgets = !empty($options_cache['widgets1']) ? unserialize($options_cache['widgets1']) : array();
    doAction('diff_side');
    foreach ($widgets as $val) {
        $widget_title = @unserialize($options_cache['widget_title']);
        $custom_widget = @unserialize($options_cache['custom_widget']);
        if (strpos($val, 'custom_wg_') === 0) {
            $callback = 'widget_custom_text';
            if (function_exists($callback)) {
                call_user_func($callback, htmlspecialchars($custom_widget[$val]['title']), $custom_widget[$val]['content']);
            }
        } else {
            $callback = 'widget_' . $val;
            if (function_exists($callback)) {
                preg_match("/^.*\s\((.*)\)/", $widget_title[$val], $matchs);
                $wgTitle = isset($matchs[1]) ? $matchs[1] : $widget_title[$val];
                call_user_func($callback, htmlspecialchars($wgTitle));
            }
        }
    }
    ?>
</div>

标签: emlog 原创

推荐阅读: