fresh start

This commit is contained in:
sagrrecn
2026-02-19 13:13:03 +08:00
commit 9bbf98d0b9
322 changed files with 15696 additions and 0 deletions

121
core/backup.php Normal file
View File

@@ -0,0 +1,121 @@
<?php use Utils\Helper;
$name = "jasmine";
$db = Typecho_Db::get();
if (isset($_POST["type"])) {
if ($_POST["type"] == "备份设置") {
$value = $db->fetchRow(
$db
->select()
->from("table.options")
->where("name = ?", "theme:" . $name)
)["value"];
if (
$db->fetchRow(
$db
->select()
->from("table.options")
->where("name = ?", "theme:" . $name . "_backup")
)
) {
$db->query(
$db
->update("table.options")
->rows(["value" => $value])
->where("name = ?", "theme:" . $name . "_backup")
); ?>
<script>
alert("备份更新成功!");
window.location.href = '<?php Helper::options()->adminUrl("options-theme.php"); ?>'
</script>
<?php
} else {
?>
<?php if ($value) {
$db->query(
$db
->insert("table.options")
->rows(["name" => "theme:" . $name . "_backup", "user" => "0", "value" => $value])
); ?>
<script>
alert("备份成功!");
window.location.href = '<?php Helper::options()->adminUrl("options-theme.php"); ?>'
</script>
<?php
}
}
}
if ($_POST["type"] == "还原备份") {
if (
$db->fetchRow(
$db
->select()
->from("table.options")
->where("name = ?", "theme:" . $name . "_backup")
)
) {
$_value = $db->fetchRow(
$db
->select()
->from("table.options")
->where("name = ?", "theme:" . $name . "_backup")
)["value"];
$db->query(
$db
->update("table.options")
->rows(["value" => $_value])
->where("name = ?", "theme:" . $name)
);
?>
<script>
alert("还原成功!");
window.location.href = '<?php Helper::options()->adminUrl("options-theme.php"); ?>'
</script>
<?php
} else {
?>
<script>
alert("未备份过数据,无法恢复!");
window.location.href = '<?php Helper::options()->adminUrl("options-theme.php"); ?>'
</script>
<?php
} ?>
<?php
}
?>
<?php if ($_POST["type"] == "删除备份") {
if (
$db->fetchRow(
$db
->select()
->from("table.options")
->where("name = ?", "theme:" . $name . "_backup")
)
) {
$db->query($db->delete("table.options")->where("name = ?", "theme:" . $name . "_backup")); ?>
<script>
alert("删除成功");
window.location.href = '<?php Helper::options()->adminUrl("options-theme.php"); ?>'
</script>
<?php
} else {
?>
<script>
alert("没有备份内容,无法删除!");
window.location.href = '<?php Helper::options()->adminUrl("options-theme.php"); ?>'
</script>
<?php
} ?>
<?php
} ?>
<?php
}
?>
<?php echo '
<form class="backup" action="?Joe_backup" method="post">
<input type="submit" name="type" value="备份设置" />
<input type="submit" name="type" value="还原备份" />
<input type="submit" name="type" value="删除备份" />
</form>';

84
core/common.php Normal file
View File

@@ -0,0 +1,84 @@
<?php
if (!defined("__TYPECHO_ROOT_DIR__")) {
exit();
}
class Widget_Comments_Recent extends Widget_Abstract_Comments
{
public function __construct($request, $response, $params = null)
{
parent::__construct($request, $response, $params);
$this->parameter->setDefault(["pageSize" => 8, "parentId" => 0]);
}
public function execute()
{
$select = $this->select()
->limit($this->parameter->pageSize)
->where("table.comments.status = ?", "approved")
->order("table.comments.coid", Typecho_Db::SORT_DESC);
if ($this->parameter->parentId) {
$select->where("cid = ?", $this->parameter->parentId);
}
if ($this->options->commentsShowCommentOnly) {
$select->where("type = ?", "comment");
}
$select->where("ownerId <> authorId");
$this->db->fetchAll($select, [$this, "push"]);
}
}
/**
* 评论添加 @
* @param $coid
* @return void
*/
function getCommentAt($coid)
{
$db = Typecho_Db::get();
$prow = $db->fetchRow(
$db
->select("parent")
->from("table.comments")
->where("coid = ? AND status = ?", $coid, "approved")
);
$parent = $prow["parent"];
if ($prow && $parent != "0") {
$arow = $db->fetchRow(
$db
->select("author")
->from("table.comments")
->where("coid = ? AND status = ?", $parent, "approved")
);
echo '<span class="comment-at float-left mr-1 px-1 text-white jasmine-primary-bg rounded">@' .
$arow["author"] .
"</span>";
}
}
/**
* 评论作者
* @param $obj
* @param $autoLink
* @param $noFollow
* @return void
*/
function getCommentAuthor($obj, $autoLink = null, $noFollow = null)
{
$options = Helper::options();
$autoLink = $autoLink ? $autoLink : $options->commentsShowUrl;
$noFollow = $noFollow ? $noFollow : $options->commentsUrlNofollow;
if ($obj->url && $autoLink) {
echo '<a href="' .
$obj->url .
'"' .
($noFollow ? ' rel="external nofollow"' : null) .
(strstr($obj->url, $options->index) == $obj->url ? null : ' target="_blank"') .
">" .
$obj->author .
"</a>";
} else {
echo $obj->author;
}
}

14
core/index.php Normal file
View File

@@ -0,0 +1,14 @@
<?php
if (!defined("__TYPECHO_ROOT_DIR__")) {
exit();
}
require_once "utils.php";
require_once "options.php";
require_once "meta.php";
require_once "post.php";
require_once "common.php";

40
core/meta.php Normal file
View File

@@ -0,0 +1,40 @@
<?php
use Widget\Metas\Category\Rows;
if (!defined("__TYPECHO_ROOT_DIR__")) {
exit();
}
class Jasmine_Meta_Row extends Rows
{
public function __construct($request, $response, $params = null)
{
parent::__construct($request, $response, $params);
}
/**
* 执行函数
*
* @throws Db\Exception
*/
public function execute()
{
$this->stack = $this->getCategories(getMiddleTopCategoryIds());
}
}
/**
* 判断当前是菜单否激活
* @param $self
* @return string
*/
function isActiveMenu($self, $slug): string
{
if ($self->is("category") || $self->is("post")) {
if ($self->category === $slug) {
return "jasmine-primary-bg shadow-lg !text-white";
}
}
return "";
}

201
core/options.php Normal file
View File

@@ -0,0 +1,201 @@
<?php
use Typecho\Common;
use Typecho\Widget\Helper\Form\Element\Checkbox;
use Typecho\Widget\Helper\Form\Element\Text;
use Typecho\Widget\Helper\Form\Element\Textarea;
use Typecho\Widget\Helper\Form\Element\Radio;
use Utils\Helper;
use Widget\Notice;
use Widget\Options;
if (!defined("__TYPECHO_ROOT_DIR__")) {
exit();
}
/**
* 主题配置
* @param $form
* @return void
*/
function themeConfig($form)
{
$icon = new Text(
"icon",
null,
null,
_t("Favicon"),
_t("图片地址, 浏览器标签栏显示ICON默认值为站点路径下 /favicon.ico")
);
$form->addInput($icon);
$logoUrl = new Text("logoUrl", null, null, _t("LOGO"), _t("图片地址, 用于显示站点 LOGO ,留空不显示"));
$form->addInput($logoUrl);
$stickyPost = new Text(
"stickyPost",
null,
null,
"置顶文章",
"格式文章的ID || 文章的ID || 文章的ID"
);
$form->addInput($stickyPost);
$avatarWebsite = new Radio(
"avatarWebsite",
[
"gravatar" => _t("Gravatar"),
"qq" => _t("QQ 头像"),
],
"gravatar",
_t("设置显示头像优先级"),
_t("默认通过邮箱,获取 Gravatar 头像")
);
$customStyle = new Textarea("customStyle", null, null, "自定义样式", "不需要添加 &lt;style&gt; 标签");
$form->addInput($customStyle);
$customScript = new Textarea("customScript", null, null, "自定义脚本", "不需要添加 &lt;script&gt; 标签");
$form->addInput($customScript);
backupThemeData();
}
/**
* 备份主题数据
* @return void
*/
function backupThemeData()
{
$name = "sagrre";//注意修改主题名称,这里也要跟着修改;
$db = Typecho_Db::get();
if (isset($_POST["type"])) {
if ($_POST["type"] == "创建备份") {
$value = $db->fetchRow(
$db
->select()
->from("table.options")
->where("name = ?", "theme:" . $name)
)["value"];
if (
$db->fetchRow(
$db
->select()
->from("table.options")
->where("name = ?", "theme:" . $name . "_backup")
)
) {
$db->query(
$db
->update("table.options")
->rows(["value" => $value])
->where("name = ?", "theme:" . $name . "_backup")
);
Notice::alloc()->set("备份更新成功", "success");
Options::alloc()->response->redirect(Common::url("options-theme.php", Options::alloc()->adminUrl));
?>
<?php
} else {
?>
<?php if ($value) {
$db->query(
$db
->insert("table.options")
->rows(["name" => "theme:" . $name . "_backup", "user" => "0", "value" => $value])
);
Notice::alloc()->set("备份成功", "success");
Options::alloc()->response->redirect(Common::url("options-theme.php", Options::alloc()->adminUrl));
?>
<?php
}
}
}
if ($_POST["type"] == "还原备份") {
if (
$db->fetchRow(
$db
->select()
->from("table.options")
->where("name = ?", "theme:" . $name . "_backup")
)
) {
$_value = $db->fetchRow(
$db
->select()
->from("table.options")
->where("name = ?", "theme:" . $name . "_backup")
)["value"];
$db->query(
$db
->update("table.options")
->rows(["value" => $_value])
->where("name = ?", "theme:" . $name)
);
Notice::alloc()->set("备份还原成功", "success");
Options::alloc()->response->redirect(Common::url("options-theme.php", Options::alloc()->adminUrl));
?>
<?php
} else {
Notice::alloc()->set("无备份数据,请先创建备份", "error");
Options::alloc()->response->redirect(Common::url("options-theme.php", Options::alloc()->adminUrl));
?>
<?php
} ?>
<?php
}
?>
<?php if ($_POST["type"] == "删除备份") {
if (
$db->fetchRow(
$db
->select()
->from("table.options")
->where("name = ?", "theme:" . $name . "_backup")
)
) {
$db->query($db->delete("table.options")->where("name = ?", "theme:" . $name . "_backup"));
Notice::alloc()->set("删除备份成功", "success");
Options::alloc()->response->redirect(Common::url("options-theme.php", Options::alloc()->adminUrl));
?>
<?php
} else {
Notice::alloc()->set("无备份数据,无法删除", "success");
Options::alloc()->response->redirect(Common::url("options-theme.php", Options::alloc()->adminUrl));
?>
<?php
} ?>
<?php
} ?>
<?php
}
?>
</form>
<?php echo '<br/><div class="message error">请先点击右下角的保存设置按钮,创建备份!<br/><br/><form class="backup" action="?jasmine_backup" method="post">
<input type="submit" name="type" class="btn primary" value="创建备份" />
<input type="submit" name="type" class="btn primary" value="还原备份" />
<input type="submit" name="type" class="btn primary" value="删除备份" /></form></div>';
}
/**
* 输出所有分类
* @return void
*/
function getCategoryies()
{
$db = Typecho_Db::get();
$prow = $db->fetchAll(
$db
->select()
->from("table.metas")
->where("type = ?", "category")
);
$text = "";
foreach ($prow as $item) {
$text .= $item["name"] . "(" . $item["mid"] . ")" . "&nbsp;&nbsp;&nbsp;&nbsp;";
}
return $text;
}

122
core/post.php Normal file
View File

@@ -0,0 +1,122 @@
<?php
if (!defined("__TYPECHO_ROOT_DIR__")) {
exit();
}
/**
* 获取热门文章
* @param $limit 页数
* @param $order 排序
*/
function getHotPosts($limit = 10)
{
$db = Typecho_Db::get();
$options = Helper::options();
$posts = $db->fetchAll(
$db
->select("DISTINCT table.contents.cid, table.contents.*")
->from("table.contents")
->join("table.relationships", "table.contents.cid = table.relationships.cid")
->join("table.metas", "table.metas.mid = table.relationships.mid")
->where("table.relationships.mid <> ?", getOptions()->shuoshuoCategoryId)
->where("table.metas.type = ?", "category")
->where(
"table.contents.type = ? AND table.contents.status = ? AND table.contents.created < ?",
"post",
"publish",
$options->time
)
->order("table.contents.commentsNum", Typecho_Db::SORT_DESC)
->limit($limit),
[Typecho_Widget::widget("Widget_Abstract_Contents"), "filter"]
);
return $posts;
}
/**
* 获取文章归档
* @param $widget
* @return array
*/
function getArchives($widget)
{
$db = Typecho_Db::get();
$rows = $db->fetchAll(
$db
->select()
->from("table.contents")
->order("table.contents.created", Typecho_Db::SORT_DESC)
->where("table.contents.type = ?", "post")
->where("table.contents.status = ?", "publish")
);
$stat = [];
foreach ($rows as $row) {
$row = $widget->filter($row);
$arr = [
"cid" => $row["cid"],
"title" => $row["title"],
"permalink" => $row["permalink"],
];
$stat[date("Y", $row["created"])][$row["created"]] = $arr;
}
return $stat;
}
class Widget_Post_Random extends Widget_Abstract_Contents
{
public function __construct($request, $response, $params = null)
{
parent::__construct($request, $response, $params);
$this->parameter->setDefault(["pageSize" => 1, "parentId" => 0, "ignoreAuthor" => false, "mid" => 0, "cid" => 0]);
}
public function execute()
{
$adapterName = $this->db->getAdapterName(); //兼容非MySQL数据库
if (
$adapterName == "pgsql" ||
$adapterName == "Pdo_Pgsql" ||
$adapterName == "Pdo_SQLite" ||
$adapterName == "SQLite"
) {
$order_by = "RANDOM()";
} else {
$order_by = "RAND()";
}
$select = $this->select()
->from("table.contents")
->join("table.relationships", "table.contents.cid = table.relationships.cid");
if ($this->parameter->mid > 0) {
$select->where("table.relationships.mid = ?", $this->parameter->mid);
}
$select
->where("table.contents.cid <> ?", $this->parameter->cid)
->where("table.contents.password IS NULL OR table.contents.password = ''")
->where("table.contents.type = ?", "post")
->limit($this->parameter->pageSize)
->order($order_by);
$this->db->fetchAll($select, [$this, "push"]);
}
}
/**
* 当前文章分类是否为说说分类
* @return false
*/
function isShuoShuoType($cid)
{
$shuoshuoCategoryId = getOptions()->shuoshuoCategoryId;
if (empty($shuoshuoCategoryId)) {
return false;
}
$db = getDb();
$row = $db->fetchRow(
$db
->select()
->from("table.relationships")
->where("table.relationships.cid = ? and table.relationships.mid = ?", $cid, $shuoshuoCategoryId)
);
return !empty($row);
}

257
core/utils.php Normal file
View File

@@ -0,0 +1,257 @@
<?php
use Typecho\Plugin;
use Utils\Helper;
use Widget\Options;
if (!defined("__TYPECHO_ROOT_DIR__")) {
exit();
}
/**
* 获取 Options
* @return Options
*/
function getOptions(): Options
{
return Helper::options();
}
function getDb()
{
return Typecho_Db::get();
}
/**
* 获取左边栏菜单
*/
function getLeftSidebarMenu()
{
return json_decode(getOptions()->leftSidebarMenu, true);
}
/**
* 获取置顶文章
*/
function getStickyPost(): array
{
$sticky_text = getOptions()->stickyPost;
if (empty($sticky_text)) {
return [];
}
$sticky_cids = explode("||", strtr($sticky_text, " ", ""));
return $sticky_cids;
}
/**
* 获取顶部分类
* @return array
*/
function getMiddleTopCategoryIds(): array
{
$middleTopCategoryIds = getOptions()->middleTopCategoryIds;
return array_map("intval", explode("||", strtr($middleTopCategoryIds, " ", "")));
}
/**
* 获取文章自定义字段
* @param $cid 文章id
* @param $filedNames 字段名
*/
function getFieldByCidAndName($cid, $filedName)
{
$db = Typecho_Db::get();
$field = $db->fetchRow(
$db
->select()
->from("table.fields")
->where("cid = ? and name = ?", $cid, $filedName)
);
return $field;
}
/**
* 获取文章缩略图
* @param $cid 文章 id
* @return string 图片 url
*/
function getThumbnail($cid, $defaultThumbnail): string
{
$filed = getFieldByCidAndName($cid, "thumbnail");
if (empty($filed)) {
return $defaultThumbnail;
}
$thumbnail = $filed[$filed["type"] . "_value"];
// 使用自定义字段,设置缩略图
if (!empty($thumbnail)) {
return $thumbnail;
}
return $defaultThumbnail;
}
/**获取文章描述 2025.11.04**/
function getDescription($cid, $defaultDescription = ""): string
{
$field = getFieldByCidAndName($cid, "description");
if (empty($field)) {
return $defaultDescription;
}
$description = $field[$field["type"] . "_value"];
// 使用自定义字段,设置描述
if (!empty($description)) {
return $description;
}
return $defaultDescription;
}
/**
* 人性化日期
* @param $created 日期
* @return string xx 前
*/
function getHumanizedDate(int $created)
{
if (Helper::options()->timeFormat != "") {
return date(Helper::options()->timeFormat, $created);
} else {
//计算时间差
$diff = time() - $created;
$d = floor($diff / 3600 / 24);
$Y = date("Y", $created);
//输出时间
if (date("Y-m-d", $created) == date("Y-m-d")) {
return "今天";
} elseif ($d <= 1) {
return "昨天";
} elseif ($d == 2) {
return "前天";
} elseif ($d <= 31) {
return $d . " 天前";
} elseif ($Y == date("Y")) {
return date("m-d", $created);
} else {
return date("Y-m-d", $created);
}
}
}
/**
* 获取版权日期
*/
function getCopyrightDate(): string
{
$text = "";
if (!empty(getOptions()->startDate)) {
$startDate = date_create(getOptions()->startDate);
$text .= date_format($startDate, "Y");
$text .= " - ";
}
$text .= date("Y", time());
return $text;
}
/**
* 获取评论头像
* @param $mail 邮箱
* @package $isOwner 是否为作者
*/
function getAvatarByMail($mail, $isOwner = false)
{
if ($isOwner) {
$authorAvatar = getOptions()->authorAvatar;
if (!empty($authorAvatar)) {
return $authorAvatar;
}
}
$gravatarsUrl = "https://cravatar.cn/avatar/";
$mailLower = strtolower($mail);
$md5MailLower = md5($mailLower);
$avatarWebsite = getOptions()->avatarWebsite;
if (!isset($avatarWebsite) || $avatarWebsite == "gravatar") {
return $gravatarsUrl . $md5MailLower . "?d=mm";
}
$qqMail = str_replace("@qq.com", "", $mailLower);
if (strstr($mailLower, "qq.com") && is_numeric($qqMail) && strlen($qqMail) < 11 && strlen($qqMail) > 4) {
return getQQAvatar($qqMail);
} else {
return $gravatarsUrl . $md5MailLower . "?d=mm";
}
}
/**
* 获取 QQ 头像
*/
function getQQAvatar($qq)
{
$url = "https://s.p.qq.com/pub/get_face?img_type=3&uin=" . $qq;
$response = get_headers($url, 1)["Location"];
return str_replace("http://", "https://", $response);
}
/**
* 获取主题版本号
*/
function getThemeVersion()
{
$info = Plugin::parseInfo(Helper::options()->themeFile(Helper::options()->theme, "index.php"));
return $info["version"];
}
/**
* 处理正文
* @param $content
* @return array|string|string[]|null
*/
function handleContent($content)
{
return imageLazyLoad($content);
}
/**
* 图片懒加载
* @param $content
* @return array|string|string[]|null
*/
function imageLazyLoad($content)
{
return preg_replace("/<img([^>]+)>/i", '<img$1 loading="lazy">', $content);
}
/**
* 判断插件是否可用 add by Meteor
*
* @return bool
*/
function isPluginAvailable($name)
{
$plugins = Typecho_Plugin::export();
$plugins = $plugins["activated"];
return is_array($plugins) && array_key_exists($name, $plugins);
}
/**
* 获取选项值,无法获取则返回默认值数据
* @param $name 选项名
* @param $defaultValue 默认值
*/
function getOptionValueOrDefault($name, $defaultValue)
{
return getOptions()->$name ? getOptions()->$name : $defaultValue;
}
/**
* 查找数组选项值,无法获取则返回默认值
* @param $optionName 名称
* @param $searchName 数组名
* @param $defaultValue 默认值
*/
function inArrayOptionValueOrDefault($optionName, $searchName, $defaultValue)
{
if ($optionValue = getOptions()->$optionName) {
return in_array($searchName, $optionValue);
} else {
return $defaultValue;
}
}