Laravel Herd自定义Valet驱动路径解析异常求助
问题背景
在原生PHP项目中使用Laravel Herd时,遇到以下路径解析问题:
- 系统仅识别
index.php文件,访问http://x.test/case-studies无法自动解析到case-studies.php,为此实现了自定义Valet驱动解决该问题。 - 访问
http://x.test/services/时,本该路由到services/index.php却出现404错误。
错误日志
错误1
2025/03/05 10:45:18 [error] 90478#1248117: *34 "Users/jack-brogan/Herd/x/html/services//index.html" is not found (2: No such file or directory), client: 127.0.0.1, server: , request: "GET /services/ HTTP/1.1", upstream: "fastcgi://unix:/Users/jack-brogan/Library/Application Support/Herd/herd.sock", host: "x.test", referrer: "
疑问:路径末尾出现双斜杠,且系统查找index.html而非index.php。
错误2
2025/03/05 10:45:18 [error] 90478#1248117: *34 FastCGI sent in stderr: "PHP message: Servers is truePHP message: Current site path: /Users/jack-brogan/Herd/x/htmlPHP message: Current URI: /favicon.icoPHP message: Raw URI: /favicon.icoPHP message: sitepath 1: /Users/jack-brogan/Herd/x/html/favicon.ico.phpPHP message: sitepath 2: /Users/jack-brogan/Herd/x/html/favicon.ico/index.php" while reading response header from upstream, client: 127.0.0.1, server: , request: "GET /favicon.ico HTTP/1.1", upstream: "fastcgi://unix:/Users/jack-brogan/Library/Application Support/Herd/herd.sock:", host: "x.test", referrer: "http://x.test/services/"
自定义驱动代码(原版本)
// namespace Valet\Drivers; use Valet\Drivers\ValetDriver; class LocalValetDriver extends ValetDriver { /** * Determine if the driver serves the request. */ public function serves(string $sitePath, string $siteName, string $uri): bool { if (file_exists($sitePath . '/index.php')) { return true; } return true; // return file_exists($sitePath . $uri . '.php'); } /** * Resolve the incoming request to a valid PHP script. */ public function isStaticFile($sitePath, $siteName, $uri) { if (file_exists($staticFilePath = $sitePath . $uri)) { return $staticFilePath; } return false; } /** * Directs Nginx to the correct file. */ public function frontControllerPath(string $sitePath, string $siteName, string $uri): string { error_log("Current site path: " . $sitePath); error_log("Current URI: " . $uri); error_log("Raw URI: " . $_SERVER['REQUEST_URI']); // Check if request is for a PHP file if (file_exists($sitePath . $uri . '.php')) { return $sitePath . $uri . '.php'; } // Default to index.php if no other match is found return $sitePath . $uri . '/index.php'; // Ensure correct path to index.php } }
问题定位与解决
核心问题分析
- 双斜杠问题:当访问
/services/时,$uri值为/services/,直接拼接$sitePath . $uri . '/index.php'会生成/.../services//index.php,导致路径出现双斜杠。 - index.html优先级问题:Nginx默认会优先查找静态
index.html文件,当前驱动未正确拦截目录请求,导致Nginx先尝试静态文件而非交给PHP处理。 - 静态文件误处理:
favicon.ico这类静态文件未被isStaticFile正确识别,进入了frontControllerPath方法,被错误拼接成.php文件路径。
修正后的驱动代码
use Valet\Drivers\ValetDriver; class LocalValetDriver extends ValetDriver { /** * 判断驱动是否处理当前请求 */ public function serves(string $sitePath, string $siteName, string $uri): bool { return file_exists($sitePath . '/index.php'); } /** * 识别静态文件,避免进入PHP处理流程 */ public function isStaticFile($sitePath, $siteName, $uri) { // 定义常见静态文件后缀 $staticExtensions = ['html', 'css', 'js', 'png', 'jpg', 'jpeg', 'gif', 'ico', 'svg']; $pathInfo = pathinfo($sitePath . $uri); // 检查是否为静态文件且存在 if (isset($pathInfo['extension']) && in_array(strtolower($pathInfo['extension']), $staticExtensions)) { $staticFilePath = $sitePath . $uri; if (file_exists($staticFilePath)) { return $staticFilePath; } } return false; } /** * 解析请求到对应的PHP文件 */ public function frontControllerPath(string $sitePath, string $siteName, string $uri): string { // 标准化URI:去除末尾斜杠,避免双斜杠 $uri = rtrim($uri, '/'); // 处理目录请求:检查目录下的index.php if ($uri !== '' && is_dir($sitePath . $uri)) { $indexPath = $sitePath . $uri . '/index.php'; if (file_exists($indexPath)) { return $indexPath; } } // 处理无后缀请求:映射到对应的.php文件 if (file_exists($sitePath . $uri . '.php')) { return $sitePath . $uri . '.php'; } // 默认返回根目录index.php(可根据项目需求调整) return $sitePath . '/index.php'; } }
关键修改说明
- isStaticFile方法:新增静态文件后缀判断,确保
favicon.ico、图片、CSS等静态文件被正确识别,不会进入PHP处理流程。 - frontControllerPath方法:
- 用
rtrim($uri, '/')去除URI末尾的斜杠,解决双斜杠拼接问题。 - 优先处理目录请求:先判断URI是否对应一个目录,若存在则返回目录下的
index.php,解决/services/路由到services/index.php的问题。 - 调整逻辑顺序:先处理目录,再处理无后缀文件,最后 fallback到根目录
index.php,符合常规请求解析逻辑。
- 用
- serves方法:简化逻辑,仅当项目根目录存在
index.php时才处理请求,避免不必要的判断。
内容的提问来源于stack exchange,提问作者jbrogan99

