
本文介绍如何使用 PHP 扫描指定目录,提取文件名中的数字日期(如 01-02-22),将其转换为可读的英文月日格式(如 January 2),并生成带正确 href 的 HTML 链接。
本文介绍如何使用 php 扫描指定目录,提取文件名中的数字日期(如 `01-02-22`),将其转换为可读的英文月日格式(如 `january 2`),并生成带正确 href 的链接。
在实际网站管理中,常需将按日期命名的公告文件(如 01-02-22 BULLETIN.pdf)自动渲染为用户友好的链接列表。核心挑战在于:解析文件名中的日期、安全转换为标准时间对象、格式化输出,并确保 HTML 属性引号正确转义。以下是一个健壮、可直接部署的解决方案。
✅ 完整实现代码(含错误防护与日期解析)
<?php
$dir = "bulletins/2022/";
// 检查目录是否存在且可读
if (!is_dir($dir) || !is_readable($dir)) {
echo "<p>⚠️ 目录不可访问:{$dir}</p>";
exit;
}
$files = [];
$readdir = opendir($dir);
if ($readdir === false) {
echo "<p>❌ 无法打开目录:{$dir}</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill2138" title="PHP"><img
src="https://img.php.cn/upload/skill/000/000/081/178884013267959.jpg" alt="PHP" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill2138" title="PHP">PHP</a>
<p>编写健壮的PHP代码,规避类型转换陷阱、数组怪癖及常见安全漏洞。</p>
</div>
<a href="/xiazai/skill2138" title="PHP" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div>";
exit;
}
// 收集有效文件(排除 .、..、.htaccess 等)
while (($file = readdir($readdir)) !== false) {
$path = $dir . $file;
if (is_file($path) && $file !== '.' && $file !== '..' && $file !== '.htaccess') {
$files[] = $file;
}
}
closedir($readdir);
// 按文件名自然排序(如 01-02-22, 01-15-22, 12-25-22 → 正确时序)
usort($files, function($a, $b) {
// 提取文件名中首个形如 MM-DD-YY 的部分(支持空格或下划线分隔)
$pattern = '/^(\d{2})-(\d{2})-(\d{2})/';
preg_match($pattern, $a, $matchA);
preg_match($pattern, $b, $matchB);
if (!empty($matchA[0]) && !empty($matchB[0])) {
// 转为 YYYY-MM-DD 格式用于比较(避免 22 年 vs 2022 年歧义)
$dateA = '20' . $matchA[3] . '-' . $matchA[1] . '-' . $matchA[2];
$dateB = '20' . $matchB[3] . '-' . $matchB[1] . '-' . $matchB[2];
return strcmp($dateB, $dateA); // 降序:最新在前
}
return strcmp($b, $a);
});
// 渲染链接列表
echo "<ul class=\"bulletin-list\">\n";
foreach ($files as $file) {
// 提取日期部分:匹配开头的 "MM-DD-YY"
if (preg_match('/^(\d{2})-(\d{2})-(\d{2})/', $file, $matches)) {
$monthNum = (int)$matches[1];
$dayNum = (int)$matches[2];
$yearTwo = $matches[3];
$yearFour = '20' . $yearTwo; // 假设均为 20xx 年;如需兼容 19xx,可扩展逻辑
// 使用 DateTime 构造并格式化(安全可靠,避免 format() 调用错误)
$dateObj = DateTime::createFromFormat('m-d-y', "{$monthNum}-{$dayNum}-{$yearTwo}");
if ($dateObj && $dateObj->format('m-d-y') === "{$monthNum}-{$dayNum}-{$yearTwo}") {
$formattedDate = $dateObj->format('F j'); // → "January 2"(注意:j 不带前导零)
$href = htmlspecialchars("{$dir}{$file}", ENT_QUOTES, 'UTF-8');
echo " <li><a href=\"{$href}\">{$formattedDate}</a></li>\n";
} else {
// 解析失败时回退显示原始日期片段
echo " <li><a href=\"{$href}\">{$matches[0]}</a>(日期格式异常)</li>\n";
}
} else {
// 文件名不含标准日期前缀,跳过格式化,仅显示原名(可选)
$href = htmlspecialchars("{$dir}{$file}", ENT_QUOTES, 'UTF-8');
echo " <li><a href=\"{$href}\">{$file}</a>(未识别日期)</li>\n";
}
}
echo "</ul>\n";
?>? 关键要点说明
-
引号必须转义:PHP 中双引号字符串内嵌 HTML 属性时,
"必须用\"转义,否则会导致语法错误或 XSS 风险;更推荐使用htmlspecialchars()对 URL 和文本进行安全编码。 -
避免
format()错误:原问题中报错Call to a member function format(),通常因DateTime::createFromFormat()返回false(解析失败)后直接调用format()。本方案增加有效性校验,杜绝此类致命错误。 -
日期解析鲁棒性:使用正则
/^(\d{2})-(\d{2})-(\d{2})/精准捕获文件名开头的日期段,不依赖空格分割(避免explode(" ", $file)在无空格时崩溃)。 -
排序逻辑增强:
usort()结合DateTime::createFromFormat()实现真实时间顺序排序,而非简单字典序(否则12-xx会排在01-xx前)。 -
安全第一:所有输出均经
htmlspecialchars()处理,防止恶意文件名注入 HTML 或 JS。
? 注意事项
- 若文件年份跨 19xx/20xx(如
12-25-99应为 1999),需根据业务规则调整$yearFour推导逻辑(例如判断$yearTwo > 24则视为 19xx)。 - 确保 Web 服务器对
bulletins/2022/目录有读取权限,且.htaccess已配置禁止目录遍历(推荐添加Options -Indexes)。 - 如需支持更多日期格式(如
20220102、2022-01-02),可扩展正则与DateTime::createFromFormat()的模板。
此方案兼顾初学者易懂性与生产环境可靠性,一次部署即可长期自动维护公告链接列表。
立即学习“PHP免费学习笔记(深入)”;


















