
本文介绍如何将 sql 查询结果按日期分组,并以结构化、可读性强的格式(如“2022-02-15 -----”后跟带项目符号的条目)导出为纯文本文件,避免简单拼接,提升数据可读性与实用性。
要实现按日期归类、层次化排版的文本导出(例如:2022-02-15 ----- 下列出所有该日的 - 内容),关键在于在 PHP 中对查询结果进行逻辑分组处理,而非直接逐行写入原始字段。原代码使用 foreach 遍历关联数组并简单拼接,无法识别日期变化;而优化后的方案采用 while 循环配合状态变量 $timestamp 动态判断日期是否切换,从而构建清晰的分段结构。
以下是推荐的完整实现(已增强安全性、健壮性与可维护性):
for_db($_POST['user'] ?? '');
$date = $_POST['date'] ?? '';
if (empty($user) || empty($date) || !preg_match('/^\d{4}-\d{2}$/', $date)) {
$error[] = "Invalid input: user or date format is incorrect.";
exit;
}
// 2. 使用参数化 WHERE 子句(更安全且高效)
// 注意:'YYYY-MM-%' 可精准匹配当月全部日期,避免 YEAR()/MONTH() 函数导致索引失效
$sql = "SELECT `date`, `data` FROM `table_name`
WHERE `user` = ? AND `date` LIKE ?
ORDER BY `date` DESC";
$stmt = $database->prepare($sql);
$stmt->bind_param('ss', $user, $date . '-%');
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows === 0) {
$error[] = "No data found for the specified user and period.";
} else {
$file = 'path/to/' . basename($user) . '.txt'; // 防止路径遍历
$fh = fopen($file, 'a');
if (!$fh) {
$error[] = "Failed to open output file.";
} else {
$current_date = null;
while ($row = $result->fetch_assoc()) {
$date_str = $row['date']; // 假设 date 字段为 'Y-m-d' 格式字符串
$data_content = trim((string)$row['data']);
// 检测日期变更:触发新日期标题
if ($date_str !== $current_date) {
if ($current_date !== null) {
fwrite($fh, "\n"); // 上一组结束后空一行
}
// 写入格式化日期标题(如 "February 15, 2022 -----")
$formatted_date = date('F j, Y', strtotime($date_str));
fwrite($fh, $formatted_date . " -----\n");
$current_date = $date_str;
}
// 写入带项目符号的内容行
fwrite($fh, "- {$data_content}\n");
}
fclose($fh);
$success[] = "Data exported successfully to {$file}.";
}
}
?>✅ 关键改进说明:
- 安全性强化:改用 mysqli_prepare() + bind_param() 防止 SQL 注入,替代拼接 SQL 字符串;对 $user 和 $date 做基础校验与过滤。
- 性能优化:使用 date LIKE '2022-02-%' 替代 YEAR(date)=... AND MONTH(date)=...,使数据库能利用 date 字段上的索引。
- 格式可控:通过 $current_date 状态变量精准控制分组逻辑,确保同日数据连续输出,不同日期间插入分隔标题与空行。
- 鲁棒性提升:检查文件打开失败、空结果集、非法输入等边界情况,并给出明确反馈。
- 可读性保障:输出严格遵循目标格式(日期标题 + 换行 + 项目符号列表),支持后续人工查阅或简单解析。
⚠️ 注意事项:
- 确保数据库中 date 字段为 DATE 或标准 Y-m-d 格式字符串,否则 strtotime() 可能解析失败;建议统一使用 DATE 类型并建立索引。
- 若数据量极大(如万级记录),应考虑流式写入或分批次处理,避免内存溢出;本例适用于常规导出场景(百至千条)。
- 实际部署时,建议将导出文件存入受权限保护的目录,并设置合理 HTTP 头供用户下载,而非直接暴露文件路径。
通过以上结构化处理,你不仅能获得高度定制化的文本输出,还能为未来扩展(如导出 CSV/JSON/PDF)打下清晰的数据组织基础。










