Files
SimpleNav/README.md
T
laoyang 273074218c chore: 清除仓库中的开发者个人信息
面向公开仓库做一次脱敏,去掉与开发者个人绑定的域名、内网入口与环境路径。

- db.php:默认数据里的个人地址全部换成通用示例(原先是开发者的私有基础设施:
  带路径令牌的面板地址、若干内网服务入口,以及暴露学校身份的校内系统如教务 / BB / VPN / 财务)。
  分组结构(2 个网格板块 + 3 个合集板块)与条目数量保持不变,新装仍是一份可用的示例导航。
- README.md:去掉「复刻某站风格」的表述与示例路径里的个人域名;部署步骤改为通用写法
  (不再指向仓库外的私有脚本目录),并补上 Nginx 的 /data/ 拦截规则。
  顺带修正一处与实际不符的描述:原文档称「页面缓存插件无需任何特殊配置」,实测该插件读不到
  FastCGI 的 Cache-Control,实际是靠根 .htaccess 在请求侧注入 X_CACHE=1 才旁路掉的。
- .htaccess / config.php / functions.php / assets/css/style.css:注释里的个人域名改为通用表述。
- .gitignore:去掉开发者本机目录约定。
- LICENSE:版权署名由个人昵称改为 The SimpleNav Authors。

默认数据只在空库时写入,线上现有数据不受影响;本次无运行期行为变更。

验证:本地 php -l 全过;e2e 93/93;部署(双版本 php -l + 静态断言 + 文件哈希逐字节一致 +
HTTP 冒烟 + 缓存旁路自检 + Web 身份诊断)全绿,退出码 0。
2026-09-28 18:34:44 +08:00

121 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SimpleNav · 简航
简航(SimpleNav),一个面向个人的**轻量级网站导航系统**。PHP + SQLite,零外部依赖、无需 Composer,上传即用。
## 特点
- **轻量**:纯 PHP + SQLite,不依赖 MySQL / 框架 / Composer;前端无 Bootstrap / jQuery,原生 CSS + JS。
- **个人向**:单管理员,页面就是「你自己常用网站的起始页」。
- **搜索引擎可切换 + 联想下拉**:后台勾选喜欢的搜索引擎即可显示在顶部;输入时下拉建议词由服务端代理(规避跨域)。默认**联想词统一取百度、搜索走各自引擎**,并带自动兜底,任何引擎都保证有下拉词(详见下节实测表)。后台的「显示/隐藏」按钮点一下**原地生效、不跳页**,且无 JS 时也能正常提交。
- **添加即补全**:填网址后先访问该网址拿到标题,再按「高清优先」的顺序去网上找相关图标(`manifest` 512 → `apple-touch-icon` → `<link rel=icon>` → 第三方聚合服务),下载后统一规范化为 **128×128 PNG** 存到服务器本地。
- **图标可自定义,且自定义后不再被覆盖**:可为任一网站上传图标或直接填图标地址;一旦自定义,该网站的图标会被标记保护,「一键全部更新」只刷新它的名称、跳过图标。图标按**整条网址**分别存档,所以同一域名下的不同路径(如 `/calendar` 与 `/`)各自独立、互不影响。
- **显示简称**:每个网站有「名称(自动)」和「简称(手动)」两个字段,页面展示你自定义的简称。
- **自定义排序**:网站 / 板块 / 搜索引擎都可上移下移排序。
- **一键全部更新**:批量刷新所有网站的图标与名称,**不会改动你自定义的简称,也不会覆盖你自定义的图标**。
- **合集区可「标签页折叠」或「全部平铺」**:底部「合集」区有两种展示方式,后台「设置 → 合集显示方式」一键切换。条目不多时选**全部平铺**(每个合集各占一块,一眼看全、不用点);合集多或条目杂时选**标签页折叠**(默认只展开当前那一个)。
- **前后台永远一致**:所有动态页面都发 `Cache-Control: no-store, no-cache`,静态资源走「长缓存 + 版本号」(文件名不变、URL 带 `?v=mtime-size`)。
## 页面结构
1. 顶部:搜索引擎切换 + 搜索框(带联想下拉)
2. 中部:网格板块(如「常用」「工具」)——「展示方式」选「普通网格板块」的板块都在这里
3. 下部:「合集」区 ——「展示方式」选「合集标签页」的板块收集到这里,再按后台的
「合集显示方式」决定是**标签页折叠**(默认)还是**全部平铺**(每组各占一块)
## 目录结构
```
SimpleNav/
├─ index.php 前台首页
├─ suggest.php 搜索联想代理(多引擎,服务端请求)
├─ login.php / logout.php 管理员登录 / 首次初始化
├─ db.php 数据库初始化(建表 + 默认数据 + 幂等列迁移)
├─ config.php 基础配置
├─ functions.php 公共函数(抓取元信息、下载图标、资源版本号、不缓存响应头)
├─ .htaccess 根目录安全规则(禁止访问 data/ 与 .git/)
├─ admin/ 后台(网站 / 板块 / 搜索引擎 / 设置)
│ ├─ index.php 后台页面
│ ├─ actions.php 增删改 / 排序处理(支持 AJAX 原地切换)
│ ├─ fetch_meta.php 添加网站时自动抓取名称与图标
│ └─ update_all.php 一键“全部更新”(分批)
├─ assets/ CSS / JS / 图标 / logo
│ └─ .htaccess 静态资源长缓存(配合 ?v= 版本号)
├─ uploads/icons/ 抓取到的网站图标(需可写)
└─ data/ SQLite 数据库(需可写,禁止 Web 访问)
```
## 部署
1. 上传全部文件到站点目录(如 `/var/www/html`,或虚拟主机常见的 `/www/wwwroot/example.com`)。
2. 确保 web 用户对 `data/` 与 `uploads/icons/` 有写权限。
(`data/` 不入库——它是运行时生成的 SQLite 数据库,首次部署请自行创建该目录。)
3. 服务器需开启 PHP 的 **GD 扩展**(图标规范化要用)与 `curl`。
4. 浏览器打开站点 → 首次访问进入「初始化管理员」,创建账号后即可在后台管理。
5. 阻止外部访问数据库目录:
- **Apache**:根目录 `.htaccess` 里已含 `RewriteRule ^data/ - [F,L]`,无需改 vhost;
- **Nginx**:在 `server{}` 里自行加一条规则:
```nginx
location ^~ /data/ { deny all; }
```
若用独立的低权限账号(而非 root)上传,只需保证它对该站点目录有写权限即可——
推荐用 POSIX ACL 授权,**不要把站点文件属主改成它**。
> 关于页面缓存插件的坑:宝塔面板的「网站加速」(Apache + memcached 整页缓存)**读不到**
> FastCGI 后端返回的 `Cache-Control`,会出现「后台改完、前台刷新还是旧的」。
> 仓库自带的根目录 `.htaccess` 已在**请求侧**注入旁路标记(`Cookie: X_CACHE=1`)绕过它,
> 无需额外配置;若你用的是别的缓存层,请确认它是否尊重后端的 `Cache-Control`。
## 搜索联想(建议词)说明
联想接口必须由**服务端代理**(浏览器直接调用会跨域)。下面是 2026-09-28 在各家接口上实测的可用性(测试机位于中国大陆):
| 引擎 | 联想接口 | 实测 | 结论 |
|---|---|---|---|
| 百度 | `www.baidu.com/sugrec?prod=pc&wd={q}` | 200 / 0.12s | ✅ 最快最稳 |
| 360 | `sug.so.360.cn/suggest?...&word={q}` | 200 / 0.20s | ✅ |
| 必应 | `api.bing.com/osjson.aspx?query={q}` | 200 / 0.5~1.6s | ✅ 可用但明显慢 |
| 搜狗 | `www.sogou.com/suggnew/ajajjson?...` | 200 / **0 字节** | ❌ 已失效(联想域名不再解析) |
| 谷歌 | `suggestqueries.google.com/complete/search?...` | 连接超时 | ❌ 国内不可达 |
| DuckDuckGo | `duckduckgo.com/ac/?...` | 连接超时 | ❌ 国内不可达 |
因此默认策略是——**联想词统一取百度,搜索仍走各自引擎**:点哪个引擎就用哪个引擎去搜,
只是输入框下面的建议来自百度,这样切到任何引擎都有下拉词。
后台「设置 → 联想词来源」可切换:`百度`(默认)/ `必应` / `360` / `各搜索引擎自己的接口`。
任何情况下都带**自动兜底链**:首选来源取不到词(接口挂了、超时、返回空)就依次回退
`百度 → 必应 → 360`,所以下拉框不会因为某家接口失效而变空。
> 想在某个引擎上恢复「用自己的联想接口」,把来源改成「各搜索引擎自己的接口」,
> 再在该引擎的「联想接口 / 联想解析类型」里填好地址即可(解析类型见下)。
内置的解析类型(`suggest_type`):
| 类型 | 说明 | 返回形态 |
|---|---|---|
| `baidu_sugrec` | 百度 | `{"g":[{"q":"…"}]}` |
| `so360` | 360 | `{"result":[{"word":"…"}]}` |
| `bing_osjson` | 必应 | `["q",["s1","s2"]]` |
| `google_firefox` | 谷歌 | `["q",["s1","s2"]]` |
| `sogou_ajaj` | 搜狗 | `{"items":[…]}`(GBK,已自动转码) |
| `ddg` | DuckDuckGo | `[{"phrase":"…"}]` |
## 图标文件的命名规则
`uploads/icons/` 下的文件名 = `md5(icon_key(网址))` + 真实扩展名(`.png` / `.svg`)。
`icon_key()` **按整条网址**算,只做极少的归一化:协议与主机名转小写、空路径补成 `/`,
查询串与锚点(`#/calendar` 这类 SPA 路由)**原样保留**。
也就是说:**不同网址 → 不同图标文件**。同域名下的不同路径是两个独立的网站条目,例如
`https://nas.example.com/calendar` 与 `https://nas.example.com/` 各自拥有独立图标,
改一个不会影响另一个;`https://a.com` 与 `https://a.com/` 则视为同一个网址,共用一张图标。
> 早期版本曾用 `md5(域名)` 命名,导致同域名不同路径的两条记录指向同一个文件,
> 改其中一条的自定义图标会把另一条一起改掉、甚至把对方的文件删成破图。
## 许可
Apache License 2.0