# LcMurmur **Repository Path**: lczld/LcMurmur ## Basic Information - **Project Name**: LcMurmur - **Description**: Typecho 轻量级微语/说说插件 - **Primary Language**: PHP - **License**: MIT - **Default Branch**: master - **Homepage**: https://www.lczld.cn/murmur/ - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-19 - **Last Updated**: 2026-10-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # LcMurmur —— Typecho 轻量级微语/说说插件 支持文字、图片(1–9 张自动网格)、音乐、视频在线播放,带微信助理、点赞、评论回复、置顶、游客发帖与管理员审核。 - 作者:就是老陈 · 主页: · 版本:1.0.7 - 环境:Typecho 1.3.0+,PHP 7.4+(已在 PHP 8.3 实测) --- ## 一、安装 1. 解压得到 `LcMurmur` 目录,整个上传到站点的 `usr/plugins/` 下,最终路径为 `usr/plugins/LcMurmur/Plugin.php`。 2. 后台 → 控制台 → 插件,启用 **LcMurmur**(自动建表、注册路由与后台菜单、写入默认配置)。 3. 点「设置」按需调整,访问 `https://你的站点/index.php/murmur/`。 4. 以后升级不用再传压缩包:在 **微语墙** 面板顶部点「检查更新」「立即更新」即可。 | 地址 | 说明 | | --- | --- | | `/index.php/murmur/` | 微语墙首页 | | `/index.php/murmur/type/text/` | 按类型筛选,可选 `text` / `image` / `music` / `video` | | `/index.php/murmur/page/2/` | 分页 | | `/index.php/murmur/?m=12` | 定位到某条微语 | | `/index.php/murmur-api/` | 前台接口(发布、点赞、评论、加载更多、微信回调) | 后台菜单「微语」下两个面板:**微语墙**(筛选、批量通过/驳回/删除/置顶)与 **待审核**(待审微语 + 待审评论)。 --- ## 二、前台 **发布**:点顶栏相机图标,底部滑出编辑层。文字里 `#话题` 会高亮,点一下就是按这个词筛选;图片每行一个地址、最多 9 张,也能本地上传;音乐填歌名/歌手/封面/音频;视频填 MP4 地址。表情是 😊 弹出的 99 个微信表情,图打包在插件里,不联网也能用,正文与评论里的 `[名称]` 自动显示成表情小图。 **互动**:点赞(同一浏览器只记一次,再点取消)、评论与回复、阅读数。管理员可置顶,置顶的排在最前并带一枚「置顶」小标;博主在微语页就能直接驳回或删除自己的微语。 **版式**:顶部一块底图,可以是视频或封面,留空则用站点绿;下面「全部/文字/图集/音乐/视频」分类行吸附在顶栏下,翻到哪儿都能随时换;图片自动排成 1/2/3 列,点开是灯箱。视频在列表里一律缩成半行宽的一格,横屏竖屏都锁同一个比例(裁中间,完整画面点开才看),两条摆在一起一样大、播放键都在格子正中。没封面的会自己取一帧真画面顶着,不会缩成一小块黑。点播放键或画面会浮到全屏,按原始比例播完整画面,点空白处(或 Esc)退回列表。 **评论**:表单是一张白卡,压在评论列表的灰底上,「别人说过的」和「你要写的」一眼分开;游客的昵称/网址/邮箱并排一行。整条评论就是回复入口,点正文直接 @ 这位;管理员的通过/删除图标平时收着,指针落到那条评论才露出来。 **分享卡片**:纯文字微语里带外链,发布时抓一次标题、摘要、封面,生成一张可点击的卡片,正文里那行裸地址不再摆第二遍。老微语可在后台「微语墙」勾选补抓。 **加载与搜索**:滚到快见底自动接下一页,末尾先出「加载中」再落新内容;后台也可改用数字分页。顶栏放大镜开一个整屏搜索页,回车走普通跳转,不装 JS 也能用。 **夜景**:宽屏右下角两枚圆钮,上面切深色/浅色模式、下面回到顶部;手机上夜景键留在顶栏。没手动切过的访客跟随系统深色设置。 辅助文字的对比度、小按钮的点按热区、时间的时区排版都按移动端标准核过。想整体换个风格,改 `style.css` 里 `:root` 的三档圆角变量即可,不用逐条找。 --- ## 三、配置项 配置页分六个标签页:**页面显示 / 功能开关 / 容量频率 / 媒体顶图 / 底部备案 / 微信助理**。 标签条用 Typecho 后台自带样式,没引外部样式表;所有字段始终在同一个表单里,任意标签下保存都会把六组一起存进去。 ### 1. 页面显示 | 字段 | 默认 | 说明 | | --- | --- | --- | | 页面标题 | 微语 | 顶栏左侧,同时作为浏览器标题 | | 页面描述 | 记录当下的碎碎念 | SEO description,也是封面下面那行右对齐的签名 | | 每页微语条数 perPage | 20 | 1–100 | | 列表翻页方式 listPaging | 加载更多 | 加载更多贴合手机信息流;数字分页可直接跳页 | | 点赞列表最多显示人数 likeListLimit | 30 | 1–200 | | 话题前缀 topicPrefix | `#` | 置空则话题不高亮、不生成搜索链接 | | 时间格式 dateFormat | `Y-m-d H:i` | 一小时内的记录自动显示「xx 分钟前」 | | 自定义头像 avatarMap | 空 | 每行一条「邮箱=图片地址」,给取不到头像的账号兜底 | | 在线字体名称 fontName | 空 | 插件用它生成 `@font-face` | | 字体地址 fontUrl | 空 | 字体文件或字体 CSS 地址;**两项一起填才加载** | **插件不带任何字体文件**。默认字体栈是 `HarmonyOS Sans SC → 系统默认`,设备没装过鸿蒙字体就一直是回落状态;想让访客也看到,得自己配一个在线字体。 「字体地址」认两种:结尾是 `.woff2`/`.woff`/`.ttf`/`.otf` 的按字体文件处理,生成带 `font-display:swap` 的 `@font-face`(跨域要求服务端回 `Access-Control-Allow-Origin`);其他结尾原样外链成样式表,适合用按 `unicode-range` 分包好的地址。保存时非 http(s) 会被清空并提示,文件名空格自动转 `%20`,字体名只保留字母数字下划线、空格、点、连字符。 ### 2. 功能开关(勾选即开启) | 键 | 名称 | 默认 | 含义 | | --- | --- | --- | --- | | allowGuest | 允许游客发布微语 | 关 | 关则必须登录才能发,顶栏左侧显示登录图标 | | guestNeedMail | 游客发布需填写邮箱 | 关 | 开启后游客发帖必须填合法邮箱(用于头像,不公开) | | needReview | 非管理员发布需审核 | **开** | 管理员/博主发布永远免审 | | allowComment | 开启评论与回复 | 开 | 关则隐藏评论区,每条下面的评论图标也一并去掉 | | guestComment | 允许游客评论 | 开 | 关则仅登录用户可评论 | | commentReview | 游客评论需审核 | 开 | 通过后显示在评论区并同步文章评论数 | | commentNeedMail | 游客评论需填写邮箱 | 开 | 关闭时评论框不再要求邮箱 | | allowLike | 开启点赞(同一指纹仅一次) | 开 | 再点一次为取消 | | allowUpload | 允许本地上传图片/音乐/视频 | 开 | 关则只能用外链地址 | | showViews | 显示阅读数 | 开 | 每条微语的浏览计数 | | showEdited | 显示已编辑 | 开 | 关掉后前台不再给改过的微语标「已编辑」,修改时间照旧记录 | | ajaxLoad | 列表无刷新加载 | **开** | 关掉后换分类、翻页都整页重载;`?m=12` 本来就是整页,不受影响 | | showInFooter | 在文章页脚显示微语入口 | 关 | 通过 `Widget_Archive:footer` 钩子注入 | | videoMuted | 视频默认静音 | 开 | 移动端内联自动播放必需 | | videoInline | 强制内联播放 | 开 | 输出 `playsinline` / X5 参数 | | allowShare | 正文链接自动生成分享卡片 | 开 | 取第一个外链抓标题/摘要/封面;卡片出来后那行裸地址不再显示 | | weixin | 开启微信助理 | 关 | 见第五节 | | notifyOnPublish | 新微语推送 WebHook 通知 | 关 | 配合下方 notifyUrl | | autoUpdate | 后台自动检查新版本 | 关 | 每天一次静默比对仓库版本,**只提示不替换文件** | | purgeOnDeactivate | 停用时一并删除数据表 | 关 | 开启后「停用插件」会 DROP 三张表 | > 勾上「停用时一并删除数据表」前请先在 **设置 → 备份数据** 导出; > 上传目录 `usr/uploads/LcMurmur/` 不会被自动删除,需手动清理。 ### 3. 容量与频率 | 字段 | 默认 | 说明 | | --- | --- | --- | | maxImages | 9 | 单条最多图片数,1–9 | | maxTextLength | 2000 | 正文最大字数 | | maxCommentLength | 1000 | 评论最大字数 | | postInterval | 30 | 游客发布间隔(秒),0 不限;微信助理不受限 | | commentInterval | 15 | 游客评论间隔(秒),0 不限 | | maxImageMb / maxAudioMb / maxVideoMb | 8 / 32 / 64 | 上传上限,实际还受 PHP `upload_max_filesize`、`post_max_size` 限制 | | imageOpt | webp | `off` 关闭 / `compress` 只压缩 / `webp` 压缩并转 WebP。GIF 一律不动(重编码只剩一帧),PNG 转 WebP 保留透明;压不动或内存不够时存原图 | | imageMaxEdge | 1600 | 最长边像素,超了等比缩小;填 0 只重编码不缩放 | | imageQuality | 82 | 重编码质量,1–100 | 数值超范围时保存会被自动夹到合法区间,并在页面顶部提示修正结果。 ### 4. 媒体顶图 | 字段 | 说明 | | --- | --- | | 顶部 MP4 视频地址 topVideo | 填写后顶部以该视频作底图,静音循环、不出播放条;留空改用封面头部。两种都锁 16:9 | | 顶部封面图地址 topCover | 没有顶部视频时用作背景,留空则用绿渐变;跟视频同一档比例(铺不满时裁边) | | 顶图封面地址 topPoster | 可选,首帧加载前显示 | | 播放模式 videoPlayMode | `点击播放` / `刷新自动播放`(自动播放需静音,已默认静音);只管正文里的视频 | | 播放结束画面 videoEndFrame | `第一帧` / `最后一帧`(顶部视频循环播放,不受影响) | 上传文件保存在 `usr/uploads/LcMurmur/年/月/`,文件名 `YmdHis-随机串.扩展名`。 扩展名白名单:图片 `jpg jpeg png gif webp bmp`,视频 `mp4 m4v mov webm`,音频 `mp3 m4a wav ogg flac aac`。 ### 5. 底部备案 | 字段 | 说明 | | --- | --- | | ICP 备案号 icp | 填了才在底部显示,点击跳工信部备案查询站 | | 公安备案号 policeIcp | 填了才显示,排在 ICP 后面,点击跳全国互联网安全管理服务平台 | ### 6. 微信助理 | 字段 | 说明 | | --- | --- | | wxToken | 与公众平台「服务器配置 → Token」一致 | | wxAppid / wxSecret | 用于下载微信临时素材(发图/发视频时必需),可留空 | | wxAllowUsers | 授权微信号 OpenID,逗号分隔(中文逗号、顿号、换行都认);**留空表示不限制** | | notifyUrl | 可选 WebHook,新微语以 JSON POST 推送 | ### 7. 当前版本 只读一页,没有可填的字段:当前版本、仓库最新、更新源、上次检查、备份情况,以及最近一次在线更新的记录。 更新源写死在 `Update.php` 里(`https://gitee.com/lczld/LcMurmur` 的 `master` 分支),不在后台开放修改。 「检查更新」「立即更新」两个按钮在 **微语 → 微语墙** 页面顶部。 --- ## 四、审核与数据 - 待审内容在 **后台 → 微语 → 待审核**,可单条操作,也可勾选后用「选中项」批量通过/驳回/删除/置顶;下半部分为待审评论,支持通过、退回待审、删除(连带清理其下回复)。 - **编辑**:微语墙每行都有「编辑」(编辑及以上可见),正文、图片、音乐、视频都能改,带哪一块就在表单上摆哪一块,没有的不画。图片勾「删除」即摘掉,新传的排在后面;音乐改歌名/歌手/封面/音频地址,视频改 MP4 地址、封面,以及这一条自己的「播放方式/结束画面」(不动「功能开关」里的全局设置)。想摘掉音乐或视频,把它的地址清空再保存,磁盘上的文件不动。开了「允许本地上传」,两块地址旁边各有一颗「上传并填入」按钮。状态、作者、点赞评论一概不动,改过的前台在时间旁标一枚「已编辑」,悬停显示修改时间;这枚记号可用「功能开关 → 显示已编辑」关掉(修改时间照旧记录)。 - 前台列表只展示 `approved`,驳回为 `hidden`(数据保留,可在「微语墙」按状态筛出后恢复)。 - 评论通过后同步写回所属微语的评论数。 - 数据表(前缀随站点):`typecho_LcMurmur` 微语主表(置顶时间存 `top`,0 为未置顶;老库第一次读列表自动补这一列)、`typecho_LcMurmurLikes` 点赞(按指纹唯一)、`typecho_LcMurmurComments` 评论与回复。 主题里加导航链接: ```php 微语 ``` --- ## 五、微信助理 ### 1. 公众平台侧配置 1. 后台开启「开启微信助理」,填好 **wxToken**(自己起一串字母数字即可),保存一次。 2. 公众平台 → 设置与开发 → 基本配置 → 服务器配置: - URL:`https://你的站点/index.php/murmur-api/weixin`(站点根已含 `index.php` 时可写成 `/murmur-api/weixin`) - Token:与 wxToken 完全一致 - 消息加解密方式:**明文模式** 3. 提交后插件校验签名并回显 `echostr`,通过即接入成功。 4. 要直接发微信里的图片/视频(临时素材)需同时填 **wxAppid / wxSecret**;只发文字、语音、外链可留空。 签名校验对 GET 与 POST 均生效,未通过签名的请求一律 403。 ### 2. 谁能发 `wxAllowUsers` 填 OpenID,多个逗号分隔;**留空 = 不限制**。白名单内成员同时拥有审核权限(可执行「通过/驳回」)。 这一栏只挑 OpenID 那串字符,怎么填都算数:中文逗号、顿号、分号、换行、不间断空格都能分隔,连微信回的整句「该微信号未获授权 (OpenID: xxx)」粘进去也能挑出来。一个 OpenID 都挑不出来时按「拒绝所有人」处理,不会悄悄退化成不限制。 拿自己的 OpenID:**给公众号发一句 `我的open`**,这条不受白名单限制,没被授权照样能问。被挡在外面时回复里也会带上对方 OpenID,单独占一行,方便完整复制。 ### 3. 指令表 | 发送内容 | 效果 | | --- | --- | | 任意文字(不以指令开头) | 直接发布一条文字动态 | | 图片 / 视频 | 发布对应动态,微信临时素材自动转存为外链 | | 语音 | 取识别结果发布文字动态;识别失败则提示改发文字 | | `音乐 歌名\|歌手\|音频链接` | 发布音乐动态,可再加封面:`歌名\|歌手\|封面\|音频链接` | | `视频 封面图\|MP4链接` | 用外链发布视频动态,顺序不限,可只发 MP4 | | `帮助` / `help` | 查看指令说明 | | `待审` / `pending` | 列出最多 10 条待审微语及编号 | | `通过 12` / `approve 12` | 通过第 12 条(并触发 WebHook 通知) | | `驳回 12` / `deny 12` | 驳回第 12 条 | | `列表` / `list` | 最新 5 条已发布微语 | | `我的open` / `我是谁` | 回复本微信号 OpenID(**未被授权时也能问**) | 通过微信发布的动态作者显示为「微信助理」,来源标记 `weixin`,签名校验通过的回调免审核直接上墙。 它没有博主那套邮箱,头像用插件自带的一枚双气泡图标(`static/weixin.svg`),想换成自己的直接覆盖这个文件。 注意:`wxAllowUsers` 留空时任何人都能发,但**审核指令仍需后台管理员或白名单成员**。 ### 4. WebHook 通知 勾选「新微语推送 WebHook 通知」并填 `notifyUrl`,每次发布或通过审核会 POST 一段 JSON: ```json { "action": "lc_murmur_new", "id": 14, "author": "微信助理", "text": "正文前 200 字", "url": "https://你的站点/index.php/murmur/?m=14" } ``` `Content-Type: application/json`,超时 5 秒,失败静默(不影响发布)。 --- ## 六、安全 - 后台面板与批量操作走 Typecho 原生 `Widget\Security::protect()`,需登录且具备 contributor/editor 权限(微语墙 contributor、待审核 editor)。 - 前台写接口带一次性令牌 `_` 与来源 `from`,令牌由站点 secret 派生;「删除/驳回微语」「评论审核」仅管理员可用。 - 「检查更新 / 立即更新」走同一个 action,链接带 `Widget\Security` 的令牌且服务端再验一次 `administrator`,面板上不出现这两个按钮的角色即便拼出地址也拿不到执行权。更新源是写死在代码里的常量,后台没有可填写的仓库地址,也就没有「填个地址让服务端去抓」这条攻击面;下载来的压缩包在解压前逐条校验条目名,`..`、绝对路径、反斜杠一律拒绝;替换用的临时目录建在 `usr/uploads/LcMurmur/_update/` 下而不是 `usr/plugins/`,避免 Typecho 把 `*.old` 当成第二个插件加载导致类名冲突。 - 正文入库前经 `Typecho\Common::removeXSS()`,输出时再次转义;外链只接受 http/https 且扩展名在白名单内。 - 分享卡片的目标地址在抓取前过一遍地址校验:只放公网 http(s),内网、本机、解析到私有网段的域名与本站地址一律拒绝,不做服务端请求转发。 - 页面底部那段 `window.LcMurmur={...}` 带着地址栏传来的搜索词,`json_encode` 除 `JSON_UNESCAPED_UNICODE|SLASHES` 外**必须带 `JSON_HEX_TAG|JSON_HEX_AMP`**,否则 `?mq=<…>` 能把这段脚本提前关掉;JS 侧用 `JSON.parse` 读回,转义不影响原词。 - 游客邮箱只用于取头像,不在前台展示。数字 QQ 邮箱(含 @vip.qq.com、@foxmail.com)走腾讯 `q1.qlogo.cn`,其余按 Gravatar 哈希走 `weavatar.com` 镜像;取不到时由 `onerror` 换成插件自带的 `static/avatar.svg`。占位图底色是**半透明**绿(`rgba(7,193,96,.12)`)——它挂在 `` 上,SVG 里的 `prefers-color-scheme` 认不得顶栏那枚手动切的夜景开关,写死会在夜景下留一块亮绿。英文名 QQ 邮箱腾讯不提供反查,可在「自定义头像」里指定图片地址。 --- ## 七、卸载 1. 后台 → 插件 → LcMurmur → 「停用」。默认**保留数据表**,便于再次启用。 2. 确认不再使用:勾选「停用时一并删除数据表」后再停用(会 DROP 三张表),或停用后手动删除 `usr/plugins/LcMurmur/` 与 `usr/uploads/LcMurmur/`(后者含上传文件和在线更新的备份)。 3. 停用会同时移除路由、后台菜单与面板,不残留链接。 --- ## 八、常见问题 **Q:保存配置后设置页打不开(500)?** A:1.0.0 已对落库字段做白名单过滤,不再出现该问题;若从旧版手工写入过额外字段,重新「停用 → 启用」一次即可自动清理。 **Q:升级后新加的功能开关是空的?** A:开关只记「勾了哪些」,老库里没有新键,所以新版自带的开关在旧站第一次是未勾选状态。到 功能开关 勾上保存即可,新装站点不受影响。 **Q:游客发了但前台看不到?** A:多半开启了「非管理员发布需审核」,请到 后台 → 微语 → 待审核 处理。 **Q:视频在手机上点开变成全屏播放器 / 不自动播放?** A:保持「视频默认静音」「强制内联播放」开启;「刷新自动播放」也依赖静音才生效。 **Q:上传图片提示 413 / 上传失败?** A:PHP 的 `upload_max_filesize`、`post_max_size` 小于配置里的上限,调大即可,或改用外链图片。 **Q:微信接入一直提示「微信助理未开启」?** A:先保存一次配置(开关才会写入数据库),并确认公众平台使用明文模式、Token 与 wxToken 一致。 **Q:微信回「该微信号未获授权」?** A:签名过了、服务器也认出了你的微信号,只是后台那一栏的 OpenID 没对上。清空那一栏保存 → 发一句 `我的open` → 把回的那串原样填回去。 **Q:点「立即更新」提示「下载到的不是 zip 安装包(HTTP 200,开头是「