From 9cd3a08ae8915b86ab26c5515b938c394514cc39 Mon Sep 17 00:00:00 2001 From: XIGE <710062962@qq.com> Date: Mon, 23 Feb 2026 21:07:09 +0800 Subject: [PATCH] 1.0 --- Plugin.php | 738 +++++++++++++++++ ..._rss_05dcfb9e27c0962be4b9eeb22890752e.json | 1 + ..._rss_42ee12556016036c574bad550123b617.json | 1 + ..._rss_5183118a4cdf42e0ada38021d97010e1.json | 1 + ..._rss_654c826cb2c90984bb49f0f0e35c6a60.json | 1 + ..._rss_73eec24dcca952e233da2cca94934cbe.json | 1 + ..._rss_793cec81c1e4252d705c3acc2d269499.json | 1 + ..._rss_89b3663668a5e92b3f14aa0810604239.json | 1 + ..._rss_be6990da569447c7d7208090fac12b39.json | 1 + ..._rss_bf7b4e27897662caa50d8dd3fbdd7bdb.json | 1 + ..._rss_d784852781a2b92ae796d60487b4aa19.json | 1 + ..._rss_db319d1bc187a10e0357e1d9fdada2b3.json | 1 + ..._rss_eca84b343569d6d5cc9d6885a0011da0.json | 1 + manage-users.php | 781 ++++++++++++++++++ 使用说明.md | 373 +++++++++ 15 files changed, 1904 insertions(+) create mode 100644 Plugin.php create mode 100644 cache/usercard_rss_05dcfb9e27c0962be4b9eeb22890752e.json create mode 100644 cache/usercard_rss_42ee12556016036c574bad550123b617.json create mode 100644 cache/usercard_rss_5183118a4cdf42e0ada38021d97010e1.json create mode 100644 cache/usercard_rss_654c826cb2c90984bb49f0f0e35c6a60.json create mode 100644 cache/usercard_rss_73eec24dcca952e233da2cca94934cbe.json create mode 100644 cache/usercard_rss_793cec81c1e4252d705c3acc2d269499.json create mode 100644 cache/usercard_rss_89b3663668a5e92b3f14aa0810604239.json create mode 100644 cache/usercard_rss_be6990da569447c7d7208090fac12b39.json create mode 100644 cache/usercard_rss_bf7b4e27897662caa50d8dd3fbdd7bdb.json create mode 100644 cache/usercard_rss_d784852781a2b92ae796d60487b4aa19.json create mode 100644 cache/usercard_rss_db319d1bc187a10e0357e1d9fdada2b3.json create mode 100644 cache/usercard_rss_eca84b343569d6d5cc9d6885a0011da0.json create mode 100644 manage-users.php create mode 100644 使用说明.md diff --git a/Plugin.php b/Plugin.php new file mode 100644 index 0000000..22753d5 --- /dev/null +++ b/Plugin.php @@ -0,0 +1,738 @@ +getPrefix(); + + try { + $db->query("ALTER TABLE `{$prefix}users` ADD `user_feed` VARCHAR(255) DEFAULT NULL"); + } catch (Exception $e) { + // 字段可能已存在 + } + + // 添加管理菜单 + Helper::addPanel(3, 'UserCard/manage-users.php', 'RSS卡片', 'RSS卡片', 'administrator'); + + // 前端资源 + Typecho_Plugin::factory('Widget_Archive')->header = array('UserCard_Plugin', 'addHeader'); + + return _t('用户卡片插件已激活'); + } + + /** + * 禁用插件 + */ + public static function deactivate() + { + // 移除管理菜单 + Helper::removePanel(3, 'UserCard/manage-users.php'); + return _t('用户卡片插件已禁用'); + } + + /** + * 插件配置 + */ + public static function config(Typecho_Widget_Helper_Form $form) + { + // 管理员评论是否显示卡片 + $show_admin_card = new Typecho_Widget_Helper_Form_Element_Radio( + 'show_admin_card', + array( + '1' => _t('显示'), + '0' => _t('不显示') + ), + '1', + _t('管理员评论卡片'), + _t('是否在管理员发表的评论上显示用户卡片(普通用户不受此设置影响)') + ); + $form->addInput($show_admin_card); + + // RSS缓存时间 + $cache_time = new Typecho_Widget_Helper_Form_Element_Text( + 'cache_time', + NULL, + '3600', + _t('RSS缓存时间(秒)'), + _t('RSS数据缓存时间,建议设置为3600秒(1小时)') + ); + $form->addInput($cache_time->addRule('required', _t('必须填写缓存时间'))->addRule('isInteger', _t('请输入整数'))); + + // 最多显示条数 + $max_items = new Typecho_Widget_Helper_Form_Element_Text( + 'max_items', + NULL, + '5', + _t('最多显示文章数'), + _t('用户卡片中最多显示的RSS文章数量') + ); + $form->addInput($max_items->addRule('required', _t('必须填写显示条数'))->addRule('isInteger', _t('请输入整数'))); + + // RSS超时时间 + $timeout = new Typecho_Widget_Helper_Form_Element_Text( + 'timeout', + NULL, + '10', + _t('RSS请求超时时间(秒)'), + _t('获取RSS数据时的超时时间') + ); + $form->addInput($timeout->addRule('required', _t('必须填写超时时间'))->addRule('isInteger', _t('请输入整数'))); + + // 添加卡片显示延迟 + $hover_delay = new Typecho_Widget_Helper_Form_Element_Text( + 'hover_delay', + NULL, + '200', + _t('卡片显示延迟(毫秒)'), + _t('鼠标悬停后显示卡片的延迟时间,防止误触发') + ); + $form->addInput($hover_delay->addRule('required', _t('必须填写延迟时间'))->addRule('isInteger', _t('请输入整数'))); + } + + /** + * 个人配置 - 保持为空 + */ + public static function personalConfig(Typecho_Widget_Helper_Form $form) + { + // 不在个人页面显示RSS地址字段 + } + + /** + * 添加头部资源 + */ + public static function addHeader() + { + // 只在文章页面加载 + if (!Typecho_Widget::widget('Widget_Archive')->is('single')) { + return; + } + + // 获取配置 + $options = Typecho_Widget::widget('Widget_Options')->plugin('UserCard'); + $hover_delay = isset($options->hover_delay) ? intval($options->hover_delay) : 200; + + echo ''; + + echo ''; + } + + /** + * 生成用户卡片(供主题调用) + */ + public static function render($comments) + { + if (!$comments || $comments->authorId == 0) { + // 游客 + if ($comments->url) { + return '' . $comments->author . ''; + } else { + return $comments->author; + } + } + + try { + $db = Typecho_Db::get(); + $user = $db->fetchRow($db->select() + ->from('table.users') + ->where('uid = ?', $comments->authorId)); + + if (!$user) { + return $comments->author; + } + + // 获取插件配置 + $options = Typecho_Widget::widget('Widget_Options')->plugin('UserCard'); + $show_admin_card = isset($options->show_admin_card) ? intval($options->show_admin_card) : 1; + + // 检查用户是否为管理员 + $is_admin = ($user['group'] == 'administrator'); + + // 如果是管理员且配置为不显示卡片,则返回普通链接 + if ($is_admin && !$show_admin_card) { + if (!empty($user['url'])) { + return '' . $comments->author . ''; + } else { + return $comments->author; + } + } + + // 评论数 + $commentCount = $db->fetchObject($db->select('COUNT(*) as cnt') + ->from('table.comments') + ->where('authorId = ?', $user['uid']) + ->where('status = ?', 'approved'))->cnt; + + // RSS文章 + $rssItems = array(); + if (!empty($user['user_feed'])) { + $rssItems = self::getRssItems($user['user_feed']); + } + + // 基本信息 + $displayName = !empty($user['screenName']) ? $user['screenName'] : $user['name']; + $userUrl = !empty($user['url']) ? $user['url'] : '#'; + + // 构建HTML + $html = ''; + + return $html; + + } catch (Exception $e) { + // 出错时返回简单链接 + if ($comments->url) { + return '' . $comments->author . ''; + } else { + return $comments->author; + } + } + } + + /** + * 获取RSS文章 + */ + private static function getRssItems($url) + { + if (empty($url)) { + return array(); + } + + // 检查缓存 + $cacheKey = 'usercard_rss_' . md5($url); + $cache = self::getCache($cacheKey); + + if ($cache !== false) { + return $cache; + } + + // 获取配置 + $options = Typecho_Widget::widget('Widget_Options')->plugin('UserCard'); + $timeout = isset($options->timeout) ? intval($options->timeout) : 10; + + // 固定从RSS获取最多10条数据保存到缓存 + $fetch_max_items = 10; + + // 获取RSS + $context = stream_context_create(array( + 'http' => array('timeout' => $timeout), + 'ssl' => array('verify_peer' => false) + )); + + $content = @file_get_contents($url, false, $context); + + if (empty($content)) { + return array(); + } + + $xml = @simplexml_load_string($content); + if (!$xml) { + return array(); + } + + $items = array(); + $counter = 0; + + // RSS格式 + if (isset($xml->channel->item)) { + foreach ($xml->channel->item as $item) { + if ($counter >= $fetch_max_items) break; + + $title = trim((string)$item->title); + $link = trim((string)$item->link); + + if ($title && $link) { + $pubDate = isset($item->pubDate) ? strtotime((string)$item->pubDate) : time(); + + $items[] = array( + 'title' => $title, + 'link' => $link, + 'date' => $pubDate + ); + $counter++; + } + } + } + + // 设置缓存 + $cacheTime = isset($options->cache_time) ? intval($options->cache_time) : 3600; + self::setCache($cacheKey, $items, $cacheTime); + + return $items; + } + + /** + * 获取缓存 + */ + private static function getCache($key) + { + $cacheFile = dirname(__FILE__) . '/cache/' . $key . '.json'; + + if (file_exists($cacheFile)) { + $data = json_decode(file_get_contents($cacheFile), true); + if ($data && isset($data['expire']) && $data['expire'] > time()) { + return $data['data']; + } + } + + return false; + } + + /** + * 设置缓存 + */ + private static function setCache($key, $data, $expire = 3600) + { + $cacheDir = dirname(__FILE__) . '/cache'; + + if (!is_dir($cacheDir)) { + @mkdir($cacheDir, 0777, true); + } + + $cacheFile = $cacheDir . '/' . $key . '.json'; + $cacheData = array( + 'data' => $data, + 'expire' => time() + $expire + ); + + @file_put_contents($cacheFile, json_encode($cacheData, JSON_UNESCAPED_UNICODE)); + } +} \ No newline at end of file diff --git a/cache/usercard_rss_05dcfb9e27c0962be4b9eeb22890752e.json b/cache/usercard_rss_05dcfb9e27c0962be4b9eeb22890752e.json new file mode 100644 index 0000000..15e44d1 --- /dev/null +++ b/cache/usercard_rss_05dcfb9e27c0962be4b9eeb22890752e.json @@ -0,0 +1 @@ +{"data":[{"title":"乌托邦咖啡","link":"https:\/\/bluehe.cn\/archives\/utopia-cafe","date":1770528420},{"title":"南宁视角:灵龟山的落羽杉红了","link":"https:\/\/bluehe.cn\/archives\/lingguishan-bald-cypress","date":1770528360},{"title":"千问ai的生态服务融合","link":"https:\/\/bluehe.cn\/archives\/ai-qianwen","date":1770521880},{"title":"竖图风景:从闲逛到成片","link":"https:\/\/bluehe.cn\/archives\/one-day-nanning-itinerary","date":1768055640},{"title":"Gist:2025最佳Folo替代品","link":"https:\/\/bluehe.cn\/archives\/gist-rss","date":1766896920},{"title":"2025:从草稿箱到收件箱","link":"https:\/\/bluehe.cn\/archives\/2025-written-here","date":1766311560},{"title":"骑楼里的南宁:复古滤镜","link":"https:\/\/bluehe.cn\/archives\/nanning-qilou-slow","date":1766298660},{"title":"当城市开始变暖:逛青秀山菊展","link":"https:\/\/bluehe.cn\/archives\/qxs-chrys-photo","date":1766071920},{"title":"回邮美学:“会说话的界面”","link":"https:\/\/bluehe.cn\/archives\/email-reply","date":1764507480},{"title":"一条盘山路:把呼吸调成“大明山模式”","link":"https:\/\/bluehe.cn\/archives\/damingshan-mode","date":1763878320}],"expire":1771140234} \ No newline at end of file diff --git a/cache/usercard_rss_42ee12556016036c574bad550123b617.json b/cache/usercard_rss_42ee12556016036c574bad550123b617.json new file mode 100644 index 0000000..aa940d9 --- /dev/null +++ b/cache/usercard_rss_42ee12556016036c574bad550123b617.json @@ -0,0 +1 @@ +{"data":[{"title":"高定旅行29:春节战绩 出人意料","link":"https:\/\/www.shitoucuo.com\/13875.html","date":1771735745},{"title":"2026年云服务器矩阵","link":"https:\/\/www.shitoucuo.com\/13871.html","date":1771730032},{"title":"夕日小记56_20260221","link":"https:\/\/www.shitoucuo.com\/xiaoaji_20260221.html","date":1771665276},{"title":"新年西部数码域名活动","link":"https:\/\/www.shitoucuo.com\/13862.html","date":1771662240},{"title":"Gitea再次折腾:突破","link":"https:\/\/www.shitoucuo.com\/13861.html","date":1771589059},{"title":"中国移动线上销户","link":"https:\/\/www.shitoucuo.com\/13859.html","date":1771513530},{"title":"Gitea迁移仓库功能妙用","link":"https:\/\/www.shitoucuo.com\/13843.html","date":1771457777},{"title":"春节假期第二天:烟花","link":"https:\/\/www.shitoucuo.com\/13842.html","date":1771327475},{"title":"一个新博客","link":"https:\/\/www.shitoucuo.com\/13821.html","date":1771307455},{"title":"春节假期第一天","link":"https:\/\/www.shitoucuo.com\/13819.html","date":1771226222}],"expire":1771825114} \ No newline at end of file diff --git a/cache/usercard_rss_5183118a4cdf42e0ada38021d97010e1.json b/cache/usercard_rss_5183118a4cdf42e0ada38021d97010e1.json new file mode 100644 index 0000000..6a1f0a2 --- /dev/null +++ b/cache/usercard_rss_5183118a4cdf42e0ada38021d97010e1.json @@ -0,0 +1 @@ +{"data":[{"title":"夜登梧桐山奇遇","link":"https:\/\/www.wordpace.com\/night-hike-wutong-mountain-encounter\/","date":1767539805},{"title":"记账工具 Firefly III","link":"https:\/\/www.wordpace.com\/personal-finance-manager-firefly-iii\/","date":1765097401},{"title":"湛江东海岛之旅","link":"https:\/\/www.wordpace.com\/donghai-island-trip\/","date":1757252593},{"title":"迎风而立","link":"https:\/\/www.wordpace.com\/standing-tall-against-the-wind\/","date":1751982821},{"title":"用壁纸引擎制作BB动态壁纸","link":"https:\/\/www.wordpace.com\/creating-wallpapers-with-wallpaper-engine\/","date":1748100023},{"title":"儿子入托 时间得以宽裕","link":"https:\/\/www.wordpace.com\/letting-go-gaining-time\/","date":1743930359},{"title":"家有宝贝 让人爱让人怜","link":"https:\/\/www.wordpace.com\/snippets-of-life-250212\/","date":1739345195},{"title":"告别","link":"https:\/\/www.wordpace.com\/farewell-250128\/","date":1738487113},{"title":"有折腾有吐槽 还有进宝","link":"https:\/\/www.wordpace.com\/snippets-of-life-250121\/","date":1737428034},{"title":"新年给博客迁新服","link":"https:\/\/www.wordpace.com\/new-server-for-the-blog\/","date":1736174880}],"expire":1770893862} \ No newline at end of file diff --git a/cache/usercard_rss_654c826cb2c90984bb49f0f0e35c6a60.json b/cache/usercard_rss_654c826cb2c90984bb49f0f0e35c6a60.json new file mode 100644 index 0000000..745d638 --- /dev/null +++ b/cache/usercard_rss_654c826cb2c90984bb49f0f0e35c6a60.json @@ -0,0 +1 @@ +{"data":[{"title":"上了PDD的贼船","link":"https:\/\/www.chener.net\/archives\/pddfans\/","date":1769086380},{"title":"前尘往事,相“忘”江湖。","link":"https:\/\/www.chener.net\/archives\/wang\/","date":1767363720},{"title":"2025渝超联赛","link":"https:\/\/www.chener.net\/archives\/yuchao\/","date":1765858440},{"title":"从一个极端到另一个极端","link":"https:\/\/www.chener.net\/archives\/lefttoright\/","date":1764907560},{"title":"感觉又回到了三年前","link":"https:\/\/www.chener.net\/archives\/liugan25\/","date":1764130380},{"title":"给我的钱包加把锁","link":"https:\/\/www.chener.net\/archives\/findwallet\/","date":1763560440},{"title":"家里谁是最辛苦的人?","link":"https:\/\/www.chener.net\/archives\/studentinschool\/","date":1762853460},{"title":"启用云邮件推送API","link":"https:\/\/www.chener.net\/archives\/alimailapi\/","date":1762321620},{"title":"随着网线飘荡的灵魂","link":"https:\/\/www.chener.net\/archives\/2788\/","date":1761984420},{"title":"小陈不小,陈二真二","link":"https:\/\/www.chener.net\/archives\/outmanbychener\/","date":1761877860}],"expire":1769740190} \ No newline at end of file diff --git a/cache/usercard_rss_73eec24dcca952e233da2cca94934cbe.json b/cache/usercard_rss_73eec24dcca952e233da2cca94934cbe.json new file mode 100644 index 0000000..334db39 --- /dev/null +++ b/cache/usercard_rss_73eec24dcca952e233da2cca94934cbe.json @@ -0,0 +1 @@ +{"data":[{"title":"回望与期待","link":"https:\/\/www.iamlm.com\/blog\/193.%E5%9B%9E%E6%9C%9B%E4%B8%8E%E6%9C%9F%E5%BE%85\/","date":1766220720},{"title":"人生如戏 何必认真","link":"https:\/\/www.iamlm.com\/blog\/192.%E4%BA%BA%E7%94%9F%E5%A6%82%E6%88%8F%20%E4%BD%95%E5%BF%85%E8%AE%A4%E7%9C%9F\/","date":1755497640},{"title":"博客接入 EdgeOne","link":"https:\/\/www.iamlm.com\/blog\/191.%E5%8D%9A%E5%AE%A2%E6%8E%A5%E5%85%A5%20EdgeOne\/","date":1754548200},{"title":"将网易云歌单转移到 Apple Music","link":"https:\/\/www.iamlm.com\/blog\/190.%E5%B0%86%E7%BD%91%E6%98%93%E4%BA%91%E6%AD%8C%E5%8D%95%E8%BD%AC%E7%A7%BB%E5%88%B0%20Apple%20Music\/","date":1749366900},{"title":"阿里云轻量服务器出网流量监控脚本","link":"https:\/\/www.iamlm.com\/blog\/189.%E9%98%BF%E9%87%8C%E4%BA%91%E8%BD%BB%E9%87%8F%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%87%BA%E7%BD%91%E6%B5%81%E9%87%8F%E7%9B%91%E6%8E%A7%E8%84%9A%E6%9C%AC\/","date":1747192260},{"title":"在群晖虚拟机上安装 OpenWRT 来解决网络问题","link":"https:\/\/www.iamlm.com\/blog\/188.%E5%9C%A8%E7%BE%A4%E6%99%96%E8%99%9A%E6%8B%9F%E6%9C%BA%E4%B8%8A%E5%AE%89%E8%A3%85%20OpenWRT%20%E6%9D%A5%E8%A7%A3%E5%86%B3%E7%BD%91%E7%BB%9C%E9%97%AE%E9%A2%98\/","date":1746026400},{"title":"macOS 自动连接蓝牙音箱","link":"https:\/\/www.iamlm.com\/blog\/187.macOS%20%E8%87%AA%E5%8A%A8%E8%BF%9E%E6%8E%A5%E8%93%9D%E7%89%99%E9%9F%B3%E7%AE%B1\/","date":1737792000},{"title":"删除 macOS 启动台上 Creative Cloud 的相关图标","link":"https:\/\/www.iamlm.com\/blog\/186.%E5%88%A0%E9%99%A4%20macOS%20%E5%90%AF%E5%8A%A8%E5%8F%B0%E4%B8%8A%20Creative%20Cloud%20%E7%9A%84%E7%9B%B8%E5%85%B3%E5%9B%BE%E6%A0%87\/","date":1737623400},{"title":"利用 Repository Dispatch 触发 Github Actions 工作流","link":"https:\/\/www.iamlm.com\/blog\/185.%E5%88%A9%E7%94%A8%20Repository%20Dispatch%20%E8%A7%A6%E5%8F%91%20Github%20Actions%20%E5%B7%A5%E4%BD%9C%E6%B5%81\/","date":1737364200},{"title":"四年博客路,成长与淡然","link":"https:\/\/www.iamlm.com\/blog\/184.%E5%9B%9B%E5%B9%B4%E5%8D%9A%E5%AE%A2%E8%B7%AF%EF%BC%8C%E6%88%90%E9%95%BF%E4%B8%8E%E6%B7%A1%E7%84%B6\/","date":1735456500}],"expire":1770269485} \ No newline at end of file diff --git a/cache/usercard_rss_793cec81c1e4252d705c3acc2d269499.json b/cache/usercard_rss_793cec81c1e4252d705c3acc2d269499.json new file mode 100644 index 0000000..4f9e85b --- /dev/null +++ b/cache/usercard_rss_793cec81c1e4252d705c3acc2d269499.json @@ -0,0 +1 @@ +{"data":[{"title":"新年快乐🎇🎆","link":"https:\/\/zhongxiaojie.cn\/2026\/02\/476\/","date":1771257606},{"title":"500 miles 🚗🚌🚄✈️🎆🎇🎉","link":"https:\/\/zhongxiaojie.cn\/2026\/02\/450\/","date":1770881075},{"title":"小年","link":"https:\/\/zhongxiaojie.cn\/2026\/02\/424\/","date":1770707602},{"title":"WP RSS.Beauty 插件","link":"https:\/\/zhongxiaojie.cn\/2026\/02\/416\/","date":1770599177},{"title":"WP 访客信息插件 v16.06.99","link":"https:\/\/zhongxiaojie.cn\/2026\/02\/400\/","date":1770531627},{"title":"WP 访客信息插件 v16.03.55","link":"https:\/\/zhongxiaojie.cn\/2026\/02\/391\/","date":1770458240},{"title":"来自自恋狂的瞎折腾","link":"https:\/\/zhongxiaojie.cn\/2026\/02\/350\/","date":1770255687},{"title":"👗V👗","link":"https:\/\/zhongxiaojie.cn\/2026\/02\/344\/","date":1770172827},{"title":"👠高跟鞋👠","link":"https:\/\/zhongxiaojie.cn\/2026\/02\/322\/","date":1770017686},{"title":"死缠烂打","link":"https:\/\/zhongxiaojie.cn\/2026\/01\/284\/","date":1769586929}],"expire":1771734481} \ No newline at end of file diff --git a/cache/usercard_rss_89b3663668a5e92b3f14aa0810604239.json b/cache/usercard_rss_89b3663668a5e92b3f14aa0810604239.json new file mode 100644 index 0000000..b9607ec --- /dev/null +++ b/cache/usercard_rss_89b3663668a5e92b3f14aa0810604239.json @@ -0,0 +1 @@ +{"data":[{"title":"事发突然","link":"https:\/\/hjyl.org\/one-leave-two-stay\/","date":1770729461},{"title":"这两天两件事","link":"https:\/\/hjyl.org\/two-things-in-these-two-days\/","date":1770298519},{"title":"猛啊,大爷!","link":"https:\/\/hjyl.org\/nb-daye\/","date":1768478387},{"title":"换个工位","link":"https:\/\/hjyl.org\/move-to-another-office-cubicle\/","date":1768038579},{"title":"五黑酱油","link":"https:\/\/hjyl.org\/five-blacks-soy-sauce\/","date":1767976960},{"title":"2026·雪","link":"https:\/\/hjyl.org\/2026-snow\/","date":1767240814},{"title":"再见已是下一年","link":"https:\/\/hjyl.org\/bye-2025\/","date":1767083776},{"title":"连休三天","link":"https:\/\/hjyl.org\/three-days-off\/","date":1766669828},{"title":"换燃气表","link":"https:\/\/hjyl.org\/change-gas-meter\/","date":1766237767},{"title":"干的“漂亮”","link":"https:\/\/hjyl.org\/well-done-sb\/","date":1766064655}],"expire":1771222536} \ No newline at end of file diff --git a/cache/usercard_rss_be6990da569447c7d7208090fac12b39.json b/cache/usercard_rss_be6990da569447c7d7208090fac12b39.json new file mode 100644 index 0000000..5cefd9e --- /dev/null +++ b/cache/usercard_rss_be6990da569447c7d7208090fac12b39.json @@ -0,0 +1 @@ +{"data":[{"title":"已解毒!HHKB键盘!","link":"https:\/\/laozhang.org\/archives\/4021.html","date":1769609042},{"title":"盘点为了折腾NAS,入的一些收费软件","link":"https:\/\/laozhang.org\/archives\/4019.html","date":1768960665},{"title":"知识=金钱","link":"https:\/\/laozhang.org\/archives\/4016.html","date":1768289697},{"title":"两款moviepilot-v2插件,实现115网盘strm302播放","link":"https:\/\/laozhang.org\/archives\/4014.html","date":1767581906},{"title":"老张博客的2025","link":"https:\/\/laozhang.org\/archives\/4011.html","date":1766906241},{"title":"typecho插件-MemosSync,Memos 同步插件","link":"https:\/\/laozhang.org\/archives\/4008.html","date":1766411427},{"title":"限酒","link":"https:\/\/laozhang.org\/archives\/4005.html","date":1765807176},{"title":"typecho博客从宝塔面板搬到1panel面板踩的那些坑","link":"https:\/\/laozhang.org\/archives\/4001.html","date":1765249031},{"title":"酷鸭数据2026盼新活动来了!8核16G高性能配置,香港Colo数据中心,399续费同价","link":"https:\/\/laozhang.org\/archives\/3999.html","date":1765003952},{"title":"DIY人生第一台NAS-软件篇","link":"https:\/\/laozhang.org\/archives\/3997.html","date":1764598602}],"expire":1769740189} \ No newline at end of file diff --git a/cache/usercard_rss_bf7b4e27897662caa50d8dd3fbdd7bdb.json b/cache/usercard_rss_bf7b4e27897662caa50d8dd3fbdd7bdb.json new file mode 100644 index 0000000..69455a9 --- /dev/null +++ b/cache/usercard_rss_bf7b4e27897662caa50d8dd3fbdd7bdb.json @@ -0,0 +1 @@ +{"data":[{"title":"适马16-30mm镜头试拍","link":"https:\/\/www.leitao.cn\/9867.html","date":1770867128},{"title":"纪念币与法币","link":"https:\/\/www.leitao.cn\/9864.html","date":1770525529},{"title":"捉摸不定的心态","link":"https:\/\/www.leitao.cn\/9863.html","date":1770179936},{"title":"黄金和白银依然是硬通货","link":"https:\/\/www.leitao.cn\/9860.html","date":1769956494},{"title":"江西铜业我的小确幸","link":"https:\/\/www.leitao.cn\/9856.html","date":1769680400},{"title":"2026年如何正确使用AI","link":"https:\/\/www.leitao.cn\/9850.html","date":1768275928},{"title":"《大国竞争与世界秩序重构》读书笔记","link":"https:\/\/www.leitao.cn\/9847.html","date":1768272954},{"title":"斩杀线与立场","link":"https:\/\/www.leitao.cn\/9844.html","date":1767002788},{"title":"2025年小结","link":"https:\/\/www.leitao.cn\/9842.html","date":1766747514},{"title":"旧衣回收的公益与生意","link":"https:\/\/www.leitao.cn\/9838.html","date":1766386517}],"expire":1770922688} \ No newline at end of file diff --git a/cache/usercard_rss_d784852781a2b92ae796d60487b4aa19.json b/cache/usercard_rss_d784852781a2b92ae796d60487b4aa19.json new file mode 100644 index 0000000..9bb8de8 --- /dev/null +++ b/cache/usercard_rss_d784852781a2b92ae796d60487b4aa19.json @@ -0,0 +1 @@ +{"data":[{"title":"老派博主的博客体验笔记","link":"https:\/\/www.weisay.com\/blog\/old-bloggers-notes.html","date":1768379723},{"title":"新年豫园游记","link":"https:\/\/www.weisay.com\/blog\/new-year-trip-to-yuyuan.html","date":1767283159},{"title":"2025年终小记:18岁的威言威语,依然在路上","link":"https:\/\/www.weisay.com\/blog\/2025-year-end-summary.html","date":1767054098},{"title":"快来解锁你的年度互动报告","link":"https:\/\/www.weisay.com\/blog\/view-your-commenter-report.html","date":1766734657},{"title":"圣诞节的甜品手作小记","link":"https:\/\/www.weisay.com\/blog\/a-christmas-dessert-diary.html","date":1766659836},{"title":"阿里云ESA体验及缓存规则配置","link":"https:\/\/www.weisay.com\/blog\/experience-with-ali-esa.html","date":1765896168},{"title":"探秘上海自然博物馆","link":"https:\/\/www.weisay.com\/blog\/exploring-shanghai-natural-history-museum.html","date":1765275352},{"title":"浓缩的敦煌,千年的回响","link":"https:\/\/www.weisay.com\/blog\/the-great-art-of-dunhuang.html","date":1764845157},{"title":"老家南瓜,揉成香甜馒头","link":"https:\/\/www.weisay.com\/blog\/home-pumpkin-sweet-buns.html","date":1764082089},{"title":"让网站对 AI 更友好:一次关于 llms.txt 的探索与插件开发","link":"https:\/\/www.weisay.com\/blog\/exploring-llms-txt-and-building-a-plugin.html","date":1763105413}],"expire":1770893858} \ No newline at end of file diff --git a/cache/usercard_rss_db319d1bc187a10e0357e1d9fdada2b3.json b/cache/usercard_rss_db319d1bc187a10e0357e1d9fdada2b3.json new file mode 100644 index 0000000..b898bfa --- /dev/null +++ b/cache/usercard_rss_db319d1bc187a10e0357e1d9fdada2b3.json @@ -0,0 +1 @@ +{"data":[{"title":"松声|廿六年·二月中·迎新春","link":"https:\/\/xyzbz.cn\/archives\/1515\/","date":1771221240},{"title":"斐讯N1安装飞牛OS","link":"https:\/\/xyzbz.cn\/archives\/1513\/","date":1770845280},{"title":"松声|廿六年·一月暮·岁灯残","link":"https:\/\/xyzbz.cn\/archives\/1509\/","date":1769754720},{"title":"松声|廿六年·雪后早上","link":"https:\/\/xyzbz.cn\/archives\/1506\/","date":1769158137},{"title":"给兰空图床增加一个机器人登录提醒","link":"https:\/\/xyzbz.cn\/archives\/1504\/","date":1769073480},{"title":"松声|廿六年·一月初·雪叩窗","link":"https:\/\/xyzbz.cn\/archives\/1496\/","date":1768511855},{"title":"2025年终回顾","link":"https:\/\/xyzbz.cn\/archives\/1491\/","date":1767406500},{"title":"2026元旦初雪","link":"https:\/\/xyzbz.cn\/archives\/1489\/","date":1767223140},{"title":"乙巳蛇年-十二月末","link":"https:\/\/xyzbz.cn\/archives\/1488\/","date":1767042155},{"title":"Docker部署简单网页分析工具GoatCounter","link":"https:\/\/xyzbz.cn\/archives\/1485\/","date":1766467915}],"expire":1771825112} \ No newline at end of file diff --git a/cache/usercard_rss_eca84b343569d6d5cc9d6885a0011da0.json b/cache/usercard_rss_eca84b343569d6d5cc9d6885a0011da0.json new file mode 100644 index 0000000..f249495 --- /dev/null +++ b/cache/usercard_rss_eca84b343569d6d5cc9d6885a0011da0.json @@ -0,0 +1 @@ +{"data":[{"title":"丙火暖身,戊土稳心","link":"https:\/\/www.jeffer.xyz\/cid\/3284.html","date":1770214648},{"title":"博客年终总结 :2025 Ai贯穿工作生活","link":"https:\/\/www.jeffer.xyz\/cid\/3256.html","date":1764663511},{"title":"极简统计 支持本地部署PHP网站统计系统","link":"https:\/\/www.jeffer.xyz\/cid\/3221.html","date":1763457211},{"title":"爸爸厨房:简单版糖炒栗子","link":"https:\/\/www.jeffer.xyz\/cid\/3207.html","date":1762403493},{"title":"使用工具为博客做一个体检 看看可以得几分?","link":"https:\/\/www.jeffer.xyz\/cid\/3188.html","date":1761121263},{"title":"喜提浓密黑发 萎靡不振恢复好多","link":"https:\/\/www.jeffer.xyz\/cid\/3172.html","date":1760695605},{"title":"零后端搭建”博友圈”:用 FindBLOG.Net 的 rss.json 直接渲染友链时间线","link":"https:\/\/www.jeffer.xyz\/cid\/3169.html","date":1760692092},{"title":"艰难前进的痛苦","link":"https:\/\/www.jeffer.xyz\/cid\/3087.html","date":1754844957},{"title":"记录一次产品8n国际化的翻车事件","link":"https:\/\/www.jeffer.xyz\/cid\/3081.html","date":1754491719}],"expire":1770269480} \ No newline at end of file diff --git a/manage-users.php b/manage-users.php new file mode 100644 index 0000000..8fa0dff --- /dev/null +++ b/manage-users.php @@ -0,0 +1,781 @@ +hasLogin() || !$user->pass('administrator', true)) { + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => '无权限操作']); + exit; + } + + // 设置响应头为JSON + header('Content-Type: application/json; charset=utf-8'); + + if ($_POST['action'] == 'save_rss' && isset($_POST['uid'], $_POST['user_feed'])) { + $uid = intval($_POST['uid']); + $user_feed = trim($_POST['user_feed']); + $user_url = isset($_POST['user_url']) ? trim($_POST['user_url']) : ''; + + try { + $db = Typecho_Db::get(); + $db->query($db->update('table.users')->rows(array( + 'user_feed' => $user_feed, + 'url' => $user_url + ))->where('uid = ?', $uid)); + + // 清除该用户的RSS缓存 + $cacheKey = 'usercard_rss_' . md5($user_feed); + $cacheFile = dirname(__FILE__) . '/cache/' . $cacheKey . '.json'; + if (file_exists($cacheFile)) { + @unlink($cacheFile); + } + + echo json_encode(['success' => true, 'message' => '用户信息已保存!']); + exit; + + } catch (Exception $e) { + echo json_encode(['success' => false, 'message' => '保存失败:' . $e->getMessage()]); + exit; + } + + } elseif ($_POST['action'] == 'batch_save') { + // 批量保存 + try { + $db = Typecho_Db::get(); + foreach ($_POST['user_feed'] as $uid => $user_feed) { + $uid = intval($uid); + $user_feed = trim($user_feed); + $user_url = isset($_POST['user_url'][$uid]) ? trim($_POST['user_url'][$uid]) : ''; + + $db->query($db->update('table.users')->rows(array( + 'user_feed' => $user_feed, + 'url' => $user_url + ))->where('uid = ?', $uid)); + + // 清除该用户的RSS缓存 + if (!empty($user_feed)) { + $cacheKey = 'usercard_rss_' . md5($user_feed); + $cacheFile = dirname(__FILE__) . '/cache/' . $cacheKey . '.json'; + if (file_exists($cacheFile)) { + @unlink($cacheFile); + } + } + } + + echo json_encode(['success' => true, 'message' => '批量保存成功!']); + exit; + + } catch (Exception $e) { + echo json_encode(['success' => false, 'message' => '批量保存失败:' . $e->getMessage()]); + exit; + } + } + + // 如果不是上述两种action,返回错误 + echo json_encode(['success' => false, 'message' => '无效的操作']); + exit; +} + +// 正常页面加载(非AJAX请求) +include 'common.php'; +include 'header.php'; +include 'menu.php'; + +if (!defined('__TYPECHO_ROOT_DIR__')) exit; + +// 检查权限 +$user = Typecho_Widget::widget('Widget_User'); +if (!$user->hasLogin() || !$user->pass('administrator', true)) { + exit; +} + +// 获取所有用户 +$db = Typecho_Db::get(); +$users = $db->fetchAll($db->select('uid', 'name', 'screenName', 'url', 'user_feed') + ->from('table.users') + ->order('uid', Typecho_Db::SORT_ASC)); + +// 统计信息 +$totalUsers = count($users); +$withRss = 0; +$withoutRss = 0; +$withWebsite = 0; + +foreach ($users as $user) { + if (!empty($user['user_feed'])) { + $withRss++; + } else { + $withoutRss++; + } + if (!empty($user['url'])) { + $withWebsite++; + } +} + +// 获取用户头像首字母函数 +function getUserInitial($name) { + if (empty($name)) { + return 'U'; + } + + // 去除首尾空格 + $name = trim($name); + + // 如果是中文,获取第一个汉字 + if (preg_match('/^[\x{4e00}-\x{9fa5}]/u', $name)) { + // 获取第一个字符(支持中文字符) + return mb_substr($name, 0, 1, 'UTF-8'); + } else { + // 非中文,获取第一个字母或数字 + $firstChar = substr($name, 0, 1); + + // 如果是字母,转换为大写 + if (ctype_alpha($firstChar)) { + return strtoupper($firstChar); + } + + // 如果是数字,直接返回 + if (ctype_digit($firstChar)) { + return $firstChar; + } + + // 其他字符,返回第一个字符的大写形式 + return strtoupper($firstChar); + } +} +?> + +