Files
ny-exam-platform/docs/guide/export-print.md
T
nxxy335 a3be81b261 fix(security): 修复上传名单文件可被 URL 直连访问(nginx 下可 getshell)
严重漏洞:roster_import 使用 $_FILES 的原始扩展名拼 roster_YYYYMMDD_HHMMSS.<ext>
落在 Web 根目录内的 data/uploads/,既无扩展名白名单(可上传 .php),文件名又
可按秒枚举;而 bootstrap 只写了 data/.htaccess,nginx 不读 .htaccess,
生产环境(nginx + PHP-FPM)下可直接远程代码执行。

修复(api.php roster_import 四层防护):
- 扩展名白名单:仅 xlsx / xlsm / csv / txt
- 随机文件名:bin2hex(random_bytes(16)),杜绝枚举
- 解析完成后 @unlink 立即删除,Web 目录下不留存任何上传文件
- 20MB 大小限制 + UPLOAD_ERR 检查

加固(bootstrap.php):data 及 cache/uploads/snapshots 每个目录都写
.htaccess(Deny from all)+ index.html 占位;README 与文档补充 nginx
location ^~ /data/ { deny all; return 404; } 规则。

测试:新增 e2e tools/test-upload-guard.js(11 断言,覆盖 .php/.phtml 被拒、
无残留、合法 csv 导入成功且即删、无可枚举文件名),并入 tests/run-all.sh。
全套 90 项通过。

docs: 新增 VitePress 文档站(18 页)
- 使用指南 12 页:简介/部署/快速上手/系统设置/名单管理/统计口径/试卷设置/
  快照趋势异常/导出打印/数据看板/随机抽取/常见问题
- 安全 2 页:安全总览(含本次漏洞复盘)与部署加固清单(P0-P2)
- 开发 4 页:架构与目录/接口一览/SQLite 存储/测试
- 配图迁移至 docs/public/images/;.gitignore 忽略文档构建产物
2026-09-10 22:42:13 +08:00

73 lines
2.3 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.
# 导出与打印
## 导出成绩明细
工具栏 **导出成绩**,生成 `.xlsx`(零依赖,仓库内自行实现 XLSX 写入,不需要 `zip` 扩展也能用)。
### 三种可选模式
| 选项 | 效果 |
| --- | --- |
| 导出排序 | `按提交时间` / `按学号` / `按成绩降序` / `按成绩升序` |
| 按最新成绩 | 每人**只导一行**:最近一次成绩 + 最高分 + 考试次数 |
| 按班级分表 | 一个班级一个工作表(xlsx 多工作表) |
### 列
默认列(全部记录模式):
`学号 / 姓名 / 班级 / 组别 / 成绩 / 考试次数 / 第几次 / 提交时间 / 考试时长 / 考试时长(秒)`
按最新成绩模式:
`学号 / 姓名 / 班级 / 组别 / 最新成绩 / 最高分 / 考试次数 / 最近提交时间 / 考试时长 / 考试时长(秒)`
> 学号等长数字列统一按**文本格式**写入,不会被 Excel 转成科学计数法,也不会被当作公式执行。
### 文件名
```
成绩明细_<试卷名>[_<班级>][_<组别>][_最新成绩]_<YYYYMMDD_HHMMSS>.xlsx
```
### 跟随筛选
导出**完全跟随页面当前的班级 / 组别筛选**,缺考口径也与页面一致
(筛选后名单 − 筛选后已提交,按学号匹配),不会出现"页面上 30 人、导出 50 人"的情况。
## 导出缺考名单
工具栏 **导出缺考**,列为 `学号 / 姓名 / 班级 / 组别`,按学号升序。
## 打印成绩明细
成绩明细面板右上角 **打印**:
- 默认按**成绩降序**;
- 可选「按班级 / 组别分组对比」,每组段首给出小计;
- 走浏览器打印通道,可直接另存为 PDF。
缺考名单面板右上角 **打印** 同理。
## 直接调用导出接口
需要对接其它系统时,可以带参数直接 GET(需已登录):
```
api.php?action=export&projectId=xxx&cls=1&grp=A&mode=latest&split=cls&sort=score_desc&cols=sid,name,score
```
| 参数 | 取值 | 说明 |
| --- | --- | --- |
| `projectId` | 试卷 ID | 必填 |
| `cls` / `grp` | 班级 / 组别 | 与页面筛选一致 |
| `mode` | `latest` | 每人一行最新成绩;缺省导出全部记录 |
| `split` | `cls` | 按班级拆分多工作表 |
| `sort` | `time` / `sid` / `score_desc` / `score_asc` | 排序 |
| `cols` | 逗号分隔列名 | 从默认列中挑选 |
## 相关
- [成绩明细与统计口径](./scores.md)
- [接口一览](../dev/api.md)