2026-10-03 08:18:05 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 前端控制器(路由表)—— 只给 **PHP 内置服务器** 用(php -S ... router.php)。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 为什么要它:
|
|
|
|
|
|
* · 线上是 Apache,`/dav/3.ics/` 这种没有对应文件的 URL 靠 .htaccess 重写到 dav.php;
|
|
|
|
|
|
* · 本地 `php -S` **不读 .htaccess**,所以同一个地址会被当成"文件不存在"直接 404,
|
|
|
|
|
|
* 于是「CalDAV 在本地测不了、只能上线验证」——这正是最容易上线才发现问题的写法。
|
|
|
|
|
|
* 这个文件把那几条重写规则用 PHP 重述一遍,本地与线上一模一样的路径行为。
|
2026-10-06 17:33:48 +08:00
|
|
|
|
* (v24 第 22 批加了 CardDAV,同样两条:/dav/ 与 /carddav/。)
|
2026-10-03 08:18:05 +08:00
|
|
|
|
*
|
|
|
|
|
|
* ⚠️ 里面**不写任何业务**:只决定"交给哪个脚本",所有业务仍在 index.php / dav.php / media.php。
|
|
|
|
|
|
* 线上部署不该带它(Apache 走 .htaccess),但带着也无害 —— 它不会被执行。
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
$path = (string)parse_url((string)($_SERVER['REQUEST_URI'] ?? '/'), PHP_URL_PATH);
|
|
|
|
|
|
|
2026-10-09 08:45:22 +08:00
|
|
|
|
// 🔴 v33:站点根的 DAV 请求(PROPFIND / REPORT / OPTIONS)→ dav.php。
|
|
|
|
|
|
// 为什么需要:RFC 6764 允许客户端从**域名根**开始发现 DAV 服务
|
|
|
|
|
|
// (`PROPFIND /` 问 current-user-principal),Thunderbird 就会走这条。
|
|
|
|
|
|
// Apache 把 `/` 交给 index.php(→ 302 登录页),客户端判定"这里没有日历"。
|
|
|
|
|
|
// ⇒ 只对 **DAV 方法**转发,`GET /` 仍是站点首页(绝不能把首页吞掉)。
|
|
|
|
|
|
// ⚠️ 线上等价物在 `.htaccess` 里(RewriteCond 判 REQUEST_METHOD)。
|
|
|
|
|
|
$method = strtoupper((string)($_SERVER['REQUEST_METHOD'] ?? 'GET'));
|
|
|
|
|
|
if (($path === '/' || $path === '') && in_array($method, ['PROPFIND', 'REPORT', 'OPTIONS'], true)) {
|
|
|
|
|
|
require __DIR__ . '/dav.php';
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-08 20:05:01 +08:00
|
|
|
|
// 🔴 v31:`/.well-known/caldav` 与 `/.well-known/carddav`(RFC 6764)。
|
|
|
|
|
|
// 标准客户端(DAVx⁵ / iOS / Evolution)添加账号时**第一句**就试这里 ——
|
|
|
|
|
|
// 原来没有这条路由,于是落到 index.php、被 302 去登录页,
|
|
|
|
|
|
// 客户端判定"域名下没有 DAV 服务",连口令框都不弹。
|
|
|
|
|
|
// 症状正是用户报的「同步不出任何数据」(账号根本建不起来)。
|
|
|
|
|
|
// ⚠️ 必须排在下面 dav/carddav 通配两条**之前**?不需要(前缀互不包含),
|
|
|
|
|
|
// 但**必须**排在后面"真实文件"判断之前 —— 这个目录线上并不存在。
|
|
|
|
|
|
if ($path === '/.well-known/caldav') {
|
|
|
|
|
|
require __DIR__ . '/dav.php';
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($path === '/.well-known/carddav') {
|
|
|
|
|
|
require __DIR__ . '/carddav.php';
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-03 08:18:05 +08:00
|
|
|
|
// CalDAV:/dav/ 及其子路径(/dav/、/dav/3.ics/、/dav/3.ics/12.ics)
|
|
|
|
|
|
if (preg_match('#^/dav(/.*)?$#', $path)) {
|
|
|
|
|
|
require __DIR__ . '/dav.php';
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-06 17:33:48 +08:00
|
|
|
|
// CardDAV:/carddav/ 及其子路径(v24 第 22 批)
|
|
|
|
|
|
// ⚠️ 这条必须在下面那条"真实文件"判断**之前**:carddav.php 本身是个真文件,
|
|
|
|
|
|
// 但我们要的是把 /carddav/1.vcf/ 这种**不存在的路径**交给它处理;
|
|
|
|
|
|
// 顺序反了的话 /carddav/ 会去要一个不存在的目录 → 404。
|
|
|
|
|
|
if (preg_match('#^/carddav(/.*)?$#', $path)) {
|
|
|
|
|
|
require __DIR__ . '/carddav.php';
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-12 15:31:03 +08:00
|
|
|
|
// 🔴 v44(用户 2026-10-12 第 6 条):移动端 API —— `/api/v1/...` 交给 api.php。
|
|
|
|
|
|
// ⚠️ 必须排在下面"真实文件"判断**之前**:`/api/v1/tasks` 不是真文件,
|
|
|
|
|
|
// 落到 index.php 会被当成未知路由(302 到登录页),App 端只会看到一坨 HTML。
|
|
|
|
|
|
// 线上等价物在 `.htaccess` 里(同样一条 RewriteRule)。
|
|
|
|
|
|
if (preg_match('#^/api(/|$)#', $path)) {
|
|
|
|
|
|
require __DIR__ . '/api.php';
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-07 05:52:40 +08:00
|
|
|
|
// 导航**展示页**(v24 第 24 批 用户第 4 条):`/nav/?<短语>` —— 全站唯一免登录页面。
|
|
|
|
|
|
// ⚠️ 三条顺序**不能换**:
|
|
|
|
|
|
// ① `/nav/suggest.php` 是联想接口(免登录,但凭短语门禁放行);
|
|
|
|
|
|
// ② `/nav/` 恰好是展示页;
|
|
|
|
|
|
// ③ 两者都必须排在下面"真实文件"判断**之前** —— 否则 `/nav/` 会去找一个
|
|
|
|
|
|
// 不存在的目录 → 404(与上面 carddav 那条同一个坑)。
|
|
|
|
|
|
if ($path === '/nav/suggest.php') {
|
|
|
|
|
|
require __DIR__ . '/nav_suggest.php';
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (preg_match('#^/nav/?$#', $path)) {
|
|
|
|
|
|
require __DIR__ . '/nav_show.php';
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-03 08:18:05 +08:00
|
|
|
|
// 真实存在的文件(静态资源、media.php 等)→ 交给内置服务器自己处理
|
|
|
|
|
|
$file = __DIR__ . $path;
|
|
|
|
|
|
if ($path !== '/' && is_file($file)) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 其余交给主路由
|
|
|
|
|
|
require __DIR__ . '/index.php';
|
|
|
|
|
|
return true;
|