从父目录为index.php提供服务的htaccess重写规则

从父目录为index.php提供服务的htaccess重写规则,php,apache,.htaccess,mod-rewrite,url-rewriting,Php,Apache,.htaccess,Mod Rewrite,Url Rewriting,我正在寻找将映射以下内容的.htaccess重写规则 GET /a/ => a/index.php GET /a/b/ => a/b/index.php GET /a/b/c/ => a/b/index.php 基本上,如果某个目录中存在index.php文件,则应该提供该文件。如果没有,那么它应该在父目录中查找index.php并提供服务 我试图在PHP中获得干净的URL,而不必通过单个index.PHP文件路由所有内容。.htaccess Rewr

我正在寻找将映射以下内容的.htaccess重写规则

GET /a/       => a/index.php
GET /a/b/     => a/b/index.php
GET /a/b/c/   => a/b/index.php
基本上,如果某个目录中存在index.php文件,则应该提供该文件。如果没有,那么它应该在父目录中查找index.php并提供服务

我试图在PHP中获得干净的URL,而不必通过单个index.PHP文件路由所有内容。

.htaccess

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) ./index.php?__path__=$1&%{QUERY_STRING}
index.php

$path = '';
if (is_array($_GET) && array_key_exists('__path__', $_GET)) {
    $path = trim($_GET['__path__']);
}
$path = trim($path, '/');
//you can use $path, path can be "a", "a/b" or "a/b/c" for your samples

第一种解决方案假设请求映射到一个物理目录路径,例如,
/a/b/c/
格式的请求中的
a
b
c
都是文件系统上的目录

您不需要为此使用mod_rewrite(即
RewriteRule
)。您可以只指定相对
DirectoryIndex
文档。例如,要处理4层深的目录结构(即
/a/b/c/
):

如果没有找到目录索引文档,那么您将得到通常的403禁止(假设目录索引被禁用)

如果沿着文件系统路径删除了所有
index.php
文档,那么如果它试图获取文档根上的索引文档,则会收到400个错误请求


更新:然而,似乎真正需要的是一个多级前端控制器类型模式,因为请求的URL不一定作为物理文件系统路径存在。例如,给定一个形式为
/a/b/c/
的URL,那么可能只有
a
b
是物理目录,
c/
只是一个额外的URL路径,应该传递给位于
/a/b/index.php
/a/index.php
甚至
/index.php
的前端控制器,取决于先找到哪个

对于通用的任意目录级深度目录结构,可以执行以下操作:

RewriteEngine On

# Exception - Reached the document root then stop
# (Prevents rewrite loop if index.php is missing - 404 instead)
RewriteRule ^index\.php$ - [L]

# Exception - Any request for a valid file stop here
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]

# If already requesting "index.php" then step up a directory
RewriteRule ^(.*/)?[^/]+/index\.php$ /$1index.php [L]

# Otherwise try "index.php" in the current path segment
RewriteRule ^(.*/)?[^/]*$ /$1index.php [L]
正则表达式开头的可选
(.*/)?
模式允许钻取到文档根。如果这不是可选的(并且在捕获的模式中包含斜杠),那么它将停止文档根目录下的一个目录(即位于
/a/index.php


通过不特别检查请求是否映射到一个目录,当请求的目录中缺少前端控制器时,它可以调用父目录中的前端控制器。

经过一些修补,我找到了一个似乎有效的解决方案。我基本上是捕获已知的路径段,并使用捕获变量相对于文档根映射到文件系统。然而,最好有一个深入N层的正则表达式,它需要多个重写规则

RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# 3 levels deep
# GET /a/b/c-some-thing-here    
RewriteRule (.*)/(.*)/(.*) /$1/$2/index.php [L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# 4 levels deep
# GET /a/b/c/d-some-thing-here
RewriteRule (.*)/(.*)/(.*)/(.*) /$1/$2/$3/index.php [L]

默认情况下,与PHP开发服务器的路由也是这样工作的。这是什么“PHP开发服务器”?这种方法的问题在于,您可能会创建重复的内容(为相同内容提供多个URL)。。。e、 例如,从命令行运行
php-S localhost:5000
,我不担心有重复的内容。在我的例子中,index.php将最后一个“目录”视为脚本的参数。。问题中的示例中的“c”仍然通过PHP文件路由所有内容。我想跳过任何PHP逻辑并将所有内容强制放到index.PHP文件中。好吧,我误解了:(您可以使用angular style hashtags domain.com/#!这对我不起作用。它只是404s。还有什么需要启用的吗?
DirectoryIndex
是mod_dir的一部分,默认情况下启用。不需要任何其他内容。您可能需要先重置
DirectoryIndex
(尽管不太可能)您的
.htaccess
文件中是否有其他指令?是否有其他
.htaccess
文件?My.htaccess位于文档根目录中,子文件夹中没有其他.htaccess文件。在.htaccess文件中唯一的内容是您发布的一行代码段。啊,那么,您真的是在追求多前端控制器类型的模式,其中URL路径可以映射到真实的目录路径,也可以完全是虚拟的?我必须对此进行另一种思考。效果很好。谢谢!我已经包含了此模式的更通用(N级深度)版本。
RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# 3 levels deep
# GET /a/b/c-some-thing-here    
RewriteRule (.*)/(.*)/(.*) /$1/$2/index.php [L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# 4 levels deep
# GET /a/b/c/d-some-thing-here
RewriteRule (.*)/(.*)/(.*)/(.*) /$1/$2/$3/index.php [L]