Nginx 中正确区分同名 PHP 文件与目录的无扩展名路由配置

6次阅读

Nginx 中正确区分同名 PHP 文件与目录的无扩展名路由配置

本文详解如何在 nginx 中精准处理「同名 php 文件与子目录共存」场景(如 `service.php` 与 `service/`),避免因 `try_files` 的默认行为导致错误跳转,确保 `/service` 访问文件、`/service/` 访问目录。

在实际 Web 部署中,常遇到这样的结构:

/var/www/html/ ├── service.php └── service/     └── index.php

理想行为应为:

  • 请求 http://example/service → 解析为 service.php(无尾斜杠,匹配同名 PHP 文件)
  • 请求 http://example/service/ → 解析为 service/index.php(有尾斜杠,明确指向目录)

但你当前配置中,location / 内的 try_files $uri $uri/ @extensionless-php; 是问题根源。nginx 按顺序检查:

  1. $uri → /service:对应文件?否(若 service 是目录,Nginx 不会将其视为文件匹配);
  2. $uri/ → /service/:对应目录? → 立即内部重定向至 service/index.php,根本不会执行 @extensionless-php 重写逻辑

因此,/service 总被当作目录处理,永远无法命中 service.php。

立即学习PHP免费学习笔记(深入)”;

✅ 正确解决方案:调整 try_files 顺序与逻辑

核心原则:优先尝试同名 PHP 文件,再判断是否为目录,最后 fallback 到扩展名补全。修改 location / 块如下:

location / {     # ① 尝试 exact URI(如 /service)→ 若存在 service.php,则直接交由 PHP 处理     try_files $uri.php $uri/ @extensionless-php;     index index.html index.htm index.php; }

同时,确保 @extensionless-php 的 rewrite 逻辑安全且精准:

location @extensionless-php {     # 仅当 URI 不以 / 结尾时才补 .php,避免干扰目录访问     if ($uri !~ /$) {         rewrite ^(.+)$ $1.php last;     }     return 404; }

? 补充说明:$uri.php 会将 /service 映射为 /service.php,若该文件存在,Nginx 会继续查找匹配 .php$ 的 location(即你的 PHP 处理块),从而正确执行 service.php。而 /service/ 因以 / 结尾,跳过 $uri.php,进入 $uri/ 分支,成功定位到目录并加载 index.php。

⚠️ 注意事项与最佳实践

  • 不要移除 $uri/:它对 /service/ 这类显式目录请求仍必不可少;
  • 避免滥用 if:虽然此处 if ($uri !~ /$) 在 @extensionless-php 中属安全用法(见 Nginx if 官方说明),但应避免在 location 主上下文中使用 if 判断 $uri;
  • 验证文件存在性:try_files $uri.php 本身已隐含存在性检查,无需额外 =404;
  • PHP location 保持健壮:你当前的 location ~ .php$ 配置合理,但建议补充 fastcgi_intercept_errors on; 以便更好处理 PHP 错误。

✅ 最终精简版 server 配置(关键部分)

server {     listen 80 default_server;     listen [::]:80 default_server;     root /var/www/html;     index index.php index.html index.htm;     server_name _;      location / {         try_files $uri.php $uri/ @extensionless-php;     }      location ~ .php$ {         try_files $uri =404;  # 确保 PHP 文件真实存在         fastcgi_pass unix:/var/run/php/php-fpm.sock;         include fastcgi_params;         fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;     }      location @extensionless-php {         if ($uri !~ /$) {             rewrite ^(.+)$ $1.php last;         }         return 404;     }      location ~ /.ht {         deny all;     } }

重启 Nginx 后验证:

sudo nginx -t && sudo systemctl reload nginx

至此,/service 与 /service/ 将严格按语义分离,兼顾灵活性与确定性——这才是生产环境中可信赖的无扩展名 PHP 路由方案。

text=ZqhQzanResources