1 Star 0 Fork 0

veeooo/markdownphp

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
mdphp.php 19.90 KB
一键复制 编辑 原始数据 按行查看 历史
紫薯 提交于 5年前 . 完善主题模板功能
<?php
namespace MdPHP;
/**
* 开发调试
* 运行方法:
* cd ../
* php -S 127.0.0.1:5000
* http://127.0.0.1:5000/pmd/serve.php
* 依赖:composer require erusev/parsedown
* see: https://github.com/erusev/parsedown
* 流程:
* 1. 运行 serve 命令的时候,会把主题模板复制到 ./static/theme/ 目录,主题模板的 ./src/themes/{theme}/static 目录会合并到 ./static 目录
* 2. 内容页面的图片路径使用 /static/ 目录前缀
* TODO: UI管理方式(可在线新增/编辑/删除/预览文档)
*/
// 引入自动加载器
require './vendor/autoload.php';
// 版本号
const VERSION = '1.0.0';
define('CONTENT_PATH', './src/content/');
define('CONFIG_PATH', './src/config/');
// 命令行模式,在命令行输入命令 "php mdphp.php --help" 查看命令帮助
if (php_sapi_name() == 'cli') {
// argv[0] 是当前文件名,argv[1] 是第一个命令,从 argv[2] 开始是以等号(=)隔开的参数
$cmdName = isset($argv[1]) ? $argv[1] : '';
$kv = [];
$params = [];
for ($i = 0; $i < $argc; $i++) {
if ($i > 1) {
$kv = explode('=', $argv[$i], 2);
$params[$kv[0]] = $kv[1];
}
}
MdPHPCli::run($cmdName, $params);
exit();
}
// 显示页面
MdPHPMain::showPage();
// ========================================================================
// ============================= 函数库 ===================================
// ========================================================================
/**
* 主功能类库
*/
class MdPHPMain
{
/**
* 遍历 Content 目录,将目录和文件结构写入到菜单配置数据临时文件
*/
public static function writeMenuFile()
{
$menus = listDir(CONTENT_PATH, strlen(CONTENT_PATH));
// 保存菜单配置数据到 menu-temp.php 临时文件,然后从 menu.php 读取菜单数据(你可以在 menu.php 中调整好文件排序)
$menuFilePath = CONFIG_PATH . 'menu.php';
$tempFilePath = './temp/';
if (!is_dir($tempFilePath)) {
mkdir($tempFilePath);
}
$tempFilePath .= 'menu_temp.php';
if (file_exists($menuFilePath)) {
fwrite(STDOUT, "菜单配置文件已存在({$menuFilePath}),是否覆盖?[yes/No]:");
$input = trim(fgets(STDIN));
if ($input == 'yes') {
file_put_contents($menuFilePath, '<?php' . PHP_EOL . 'return ' . varExport($menus) . ';');
} else {
echo '>: 取消覆盖菜单配置文件。', PHP_EOL;
file_put_contents($tempFilePath, '<?php' . PHP_EOL . 'return ' . varExport($menus) . ';');
echo '>: 已将最新菜单数据写入到临时配置文件中:', $tempFilePath, PHP_EOL;
echo '>: 您可以在菜单配置文件中编辑文档排序。', PHP_EOL;
}
} else {
file_put_contents($menuFilePath, '<?php' . PHP_EOL . 'return ' . varExport($menus) . ';');
echo '>: 已生成菜单配置文件:', $menuFilePath, PHP_EOL;
echo '>: 您可以在菜单配置文件中编辑文档排序。', PHP_EOL;
}
}
/**
* 编译网站
*/
public static function build()
{
// 清空目录
deldir('./dist');
// 生成最新菜单配置文件
self::writeMenuFile();
// 预处理
self::preprocessForServe();
self::preprocessForBuild();
// 实例化 Markdown 插件
$parsedown = new \Parsedown();
$menus = require './src/config/menu.php';
$pathLength = strlen(CONTENT_PATH);
// 读取配置文件中的数据
$config = require './src/config/config.php';
// 读取主题模板内容
$theme = $config['theme'];
$themePath = './src/themes/' . $theme . '/index.php';
$themeFileContent = file_get_contents($themePath);
$themeFileContent = str_replace([' href="static/', ' href="./static/'], " href=\"/static/themes/{$theme}/", $themeFileContent);
$themeFileContent = str_replace([' src="static/', ' src="./static/'], " src=\"/static/themes/{$theme}/", $themeFileContent);
$themePath = './static/themes/' . $theme . '/index.php';
file_put_contents($themePath, $themeFileContent);
// 获取菜单配置数据中的文件路径
if ($config['langset']) {
foreach ($config['langset'] as $lang => $text) {
if (isset($menus[$lang]['children'])) {
$assign = [
'menus' => $menus[$lang]['children'],
'isBuildEnv' => true
];
self::writeOutputFile($assign['menus'], $pathLength, $themePath, $parsedown, $assign);
}
}
} else {
$assign = [
'menus' => $menus,
'isBuildEnv' => true
];
self::writeOutputFile($menus, $pathLength, $themePath, $parsedown, $assign);
}
echo '编译完成.';
}
/**
* 显示页面
*/
public static function showPage()
{
// 实例化 Markdown 插件
$parsedown = new \Parsedown();
// 读取菜单配置文件
$menus = require('./src/config/menu.php');
// 读取配置文件中的数据
$config = require './src/config/config.php';
$langset = $config['langset'];
// 获取浏览器 post 参数指定的文件路径
$filepath = input('post');
if ($filepath == 'index.html') {
require CONTENT_PATH . 'index.html';
return;
}
$lang = input('lang');
if (!$lang && $langset) {
$lang = key($langset);
}
if (!isset($menus[$lang])) {
exit("语言 {$lang} 对应的菜单不存在!");
}
$assign = [
'menus' => $menus[$lang]['children'],
'isBuildEnv' => false
];
extract($assign);
// 主题模板文件路径
$themePath = './static/themes/' . $config['theme'] . '/index.php';
$content = '';
if ($filepath) {
$filepath = CONTENT_PATH . $filepath;
if (file_exists($filepath)) {
$content = file_get_contents($filepath);
if (substr($filepath, -3) == '.md') {
$content = $parsedown->text($content);
}
} else {
$content = '文件不存在:' . $filepath;
}
}
// 读取主题模板内容
require $themePath;
}
/**
* 将页面内容写入到输出目录
*/
public static function writeOutputFile($nodes, $pathLength, $themePath, &$parsedown, $assign)
{
foreach ($nodes as $k => $node) {
if (is_numeric($k)) {
// 普通文档文件(.md|.html)
$filepath = CONTENT_PATH . $node['path'];
$isMdFile = substr($filepath, -3) == '.md';
$content = '';
if (!file_exists($filepath)) {
echo '文件不存在:', $filepath, PHP_EOL;
continue;
}
$content = file_get_contents($filepath);
if ($isMdFile) {
$content = $parsedown->text($content);
}
if ($isMdFile) {
$filepath = substr($filepath, 0, strlen($filepath) - 3) . '.html';
}
$outputPath = './dist/' . substr($filepath, $pathLength);
$dir = dirname($outputPath);
echo '编译文件: ', $outputPath, PHP_EOL;
if ($dir != '.' && !is_dir($dir)) {
mkdir($dir);
}
// index.html 不要套用主题模板,替换静态资源路径
if ($node['name'] == 'index.html') {
file_put_contents($outputPath, $content);
continue;
}
extract($assign);
ob_start();
require $themePath;
$pageHtml = ob_get_contents();
ob_end_clean();
file_put_contents($outputPath, $pageHtml);
continue;
}
// 子目录
if (isset($node['children'])) {
self::writeOutputFile($node['children'], $pathLength, $themePath, $parsedown, $assign);
}
}
}
/**
* 构建-预处理
*/
public static function preprocessForBuild()
{
// 复制 ./static 目录到 dist/static 目录
$source = "./static/";
$dest = './dist/static/';
copydir($source, $dest);
}
/**
* 预览-预处理
*/
public static function preprocessForServe()
{
// 复制主题模板文件到 ./static/themes 目录
$config = require './src/config/config.php';
$theme = $config['theme'];
$dest = "./static/themes/{$theme}/";
if (is_dir($dest)) {
fwrite(STDOUT, "主题模板目录已存在({$dest}),是否覆盖?[yes/No]:");
$input = trim(fgets(STDIN));
if ($input == 'yes') {
$source = "./src/themes/{$theme}/";
copydir("{$source}static/", $dest);
copy($source . 'index.php', $dest . 'index.php');
} else {
echo '>: 取消覆盖主题模板目录。', PHP_EOL;
}
}
}
/**
* 执行 serve 命令
*/
public static function runServ($params)
{
// 生成最新菜单配置文件
self::writeMenuFile();
// 预处理
self::preprocessForServe();
// 启动 PHP 嵌入式服务器
$timestamp = date('Y-m-d H:i:s');
// $docRoot = dirname(__DIR__) . DIRECTORY_SEPARATOR;
$host = empty($params['--host']) ? '127.0.0.1' : $params['--host'];
$port = empty($params['--port']) ? 5000 : $params['--port'];
$command = "php -S {$host}:{$port}";
echo <<<tpl
MdPHP Development server is started at {$timestamp} on http://{$host}:{$port}/mdphp.php
You can exit with [CTRL-C]
tpl, PHP_EOL;
passthru($command);
}
}
/**
* 命令行类库
*/
class MdPHPCli
{
public static function run($cmdName, $params)
{
switch ($cmdName) {
case '--help': // 查看帮助:php mdphp --help
echo <<<tpl
--help 显示帮助文档
--version 获取版本号信息
phpinfo 获取 phpinfo() 信息
serve 启动内置服务器,实时预览文档
build 编译文档,生成静态网站
build:menu 遍历 Content 目录生成菜单数据临时文件
build:theme 打包主题模板
modify:theme 编辑主题模板
make:theme 创建新的主题模板
make:post 创建新的文档页面
count 统计文档数量和容量
tpl;
break;
case '--version': // 查看版本号:php mdphp --version
echo 'MarkdownPHP Version ', VERSION, PHP_EOL;
break;
case 'phpinfo': // 查看 phpinfo 信息:php mdphp phpinfo
phpinfo();
break;
case 'build': // 编译成html静态网站:php mdphp build --output "./dist"
MdPHPMain::build();
break;
case 'build:menu': // 遍历 Content 目录生成菜单数据临时文件,修改后覆盖到 menu.php
MdPHPMain::writeMenuFile();
echo <<<tpl
菜单配置文件生成成功:./temp/menu_temp.php
请参照 menu_temp.php 临时文件中的最新菜单数据,修改到 ./src/config/menu.php 菜单配置文件中,然后运行 serve 或 build 命令
tpl, PHP_EOL;
break;
case 'build:theme': // 打包主题模板,其实就是把 ./static/themes/{theme}/static/ 目录 复制到 ./src/themes/{theme}/statics/ 目录
if (!isset($params['--name'])) {
echo '必须输入参数 --name。你可以输入 build:theme --help 查看帮助文档。', PHP_EOL;
return;
}
$name = $params['--name'];
copydir("./static/themes/{$name}/", "./src/themes/{$name}/");
echo "主题模板已经打包到 ./src/themes/$name/ 目录,您可以将您的主题文件压缩后发送到 14507247@qq.com,审核通过后,我们将发布到官方主题模板市场。", PHP_EOL;
break;
case 'make:theme': // 生成主题模板框架。新建目录 ./static/themes/{theme}/static/,新增文件 ./src/themes/{theme}/index.php
// 命令:
if (array_key_exists('--help', $params)) {
echo <<<tpl
帮助文档 [make:theme --help]:
创建新的主题模板框架:make:theme --name=mytheme
从已有的主题模板创建新的主题模板框架:make:theme --name=mytheme --from=default
tpl, PHP_EOL;
exit;
}
if (!isset($params['--name'])) {
echo '必须输入参数 --name。你可以输入 make:post --help 查看帮助文档。', PHP_EOL;
exit;
}
$name = $params['--name'];
$from = isset($params['--from']) ? $params['--from'] : '';
if ($from) {
copydir("./src/themes/{$from}/", "./src/themes/{$name}/");
copydir("./src/themes/{$from}/", "./static/themes/{$name}/");
} else {
mkdir("./static/themes/{$name}/static/", 0777, true);
mkdir("./src/themes/{$name}/static/", 0777, true);
}
echo <<<tpl
主题模板框架生成完成。
请编辑主题模板文件:./src/themes/{$name}/index.php
静态资源请存放到目录:./static/themes/{$name}/static/
tpl, PHP_EOL;
break;
case 'modify:theme':
if (!isset($params['--name'])) {
echo '必须输入参数 --name。你可以输入 modify:theme --help 查看帮助文档。', PHP_EOL;
exit;
}
$name = $params['--name'];
copydir("./src/themes/{$name}/", "./static/themes/{$name}/");
echo <<<tpl
主题模板复制完成。
请编辑主题模板文件:./src/themes/{$name}/index.php
静态资源请存放到目录:./static/themes/{$name}/static/
tpl, PHP_EOL;
break;
case 'make:post':
if (array_key_exists('--help', $params)) {
echo <<<tpl
帮助文档 [make:post --help]:
创建 Markdown 文档:make:post --name="关于/介绍.md"
注意:文件名中间不要有空格,不要包含特殊符号。如果文件名没有后缀,会自动补上 .md 后缀名。
tpl, PHP_EOL;
exit;
}
if (!isset($params['--name'])) {
echo '必须输入参数 --name。你可以输入 make:post --help 查看帮助文档。', PHP_EOL;
exit;
}
$name = CONTENT_PATH . $params['--name'];
// 自动补全文件名后缀
if (!in_array(pathinfo($name, PATHINFO_EXTENSION), ['md', 'html'])) {
$name .= '.md';
}
if (!is_dir(dirname($name))) {
mkdir(dirname($name), 0777, true);
}
$now = date('Y-m-d H:i:s');
$content = <<<tpl
---
title: "文章标题"
date: {$now}
---
tpl;
file_put_contents($name, $content);
echo "文档文件创建成功:{$name}";
break;
default: // 启动嵌入式服务器,实时预览效果:php mdphp.php serve --port=6000 --host="127.0.0.1"
MdPHPMain::runServ($params);
break;
}
}
}
/**
* 获取浏览器参数的值
*/
function input($name, $defv = '')
{
if (isset($_GET[$name])) {
return $_GET[$name];
}
return $defv;
}
/**
* 遍历目录
*/
function listDir($path, $trimStart = 0)
{
$tree = [];
if ($handle = opendir($path)) {
$filepath = '';
while (false !== ($file = readdir($handle))) {
if ($file == '.' || $file == '..') {
continue;
}
$filepath = $path . $file;
if (is_dir($filepath)) {
$tree[$file]['children'] = listDir($filepath . '/', $trimStart);
continue;
}
$tree[] = ['name' => $file, 'path' => $trimStart ? substr($filepath, $trimStart) : $filepath];
}
closedir($handle);
}
return $tree;
}
/**
* 复制文件夹
* @param $source
* @param $dest
*/
function copydir($source, $dest)
{
if (!$source || !is_dir($source)) {
return;
}
if (!file_exists($dest)) {
mkdir($dest, 0777, true);
}
$handle = opendir($source);
while (($file = readdir($handle)) !== false) {
if ($file == '.' || $file == '..') {
continue;
}
$_source = $source . '/' . $file;
$_dest = $dest . '/' . $file;
if (is_file($_source)) {
copy($_source, $_dest);
}
if (is_dir($_source)) {
copydir($_source, $_dest);
}
}
closedir($handle);
}
/**
* 删除当前目录及其目录下的所有目录和文件
* @param string $dir 待删除的目录
* @param boolean $isDelSelf 是否删除目录本身
*/
function deldir($dir, $isDelSelf = false)
{
$dir = rtrim($dir, '/');
if (!$dir || !is_dir($dir)) {
return;
}
$handle = opendir($dir);
while (($file = readdir($handle)) !== false) {
if ($file == '.' || $file == '..') {
continue;
}
$_dir = $dir . '/' . $file;
if (is_file($_dir)) {
//如果是文件直接删除
@unlink($_dir);
}
if (is_dir($_dir)) {
//递归删除
deldir($_dir, true);
//目录内的子目录和文件删除后删除空目录
@rmdir($_dir);
}
}
closedir($handle);
if ($isDelSelf) {
@rmdir($dir);
}
}
/**
* ver_export() 方法的现代风格版
* @param array $var
* @param string $indent 缩进空格
* @param boolean $skipNumberKey 是否省略数值键名
*/
function varExport($var, $indent = "", $skipNumberKey = true)
{
switch (gettype($var)) {
case "string":
return '\'' . addcslashes($var, "\\\$\"\r\n\t\v\f") . '\'';
case "array":
$indexed = array_keys($var) === range(0, count($var) - 1);
$r = [];
foreach ($var as $key => $value) {
if ($skipNumberKey && is_numeric($key)) {
$r[] = "$indent " . varExport($value, "$indent ");
continue;
}
$r[] = "$indent " . ($indexed ? "" : varExport($key) . " => ") . varExport($value, "$indent ");
}
return "[\n" . implode(",\n", $r) . "\n" . $indent . "]";
case "boolean":
return $var ? "TRUE" : "FALSE";
default:
return var_export($var, true);
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
PHP
1
https://gitee.com/veeooo/markdownphp.git
git@gitee.com:veeooo/markdownphp.git
veeooo
markdownphp
markdownphp
master

搜索帮助