重写基础文件夹中的绝对 URL
Absolute URL from base folder with rewrite
我在 WampServer 上有一个本地项目 运行。这是一个 MVC-like 结构;它将 URL 重写为 index.php?url=
。完整 .htaccess
:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url= [QSA,L]
当我想使用 PHP location: <location>
将用户发送到另一个页面时,由于重写(all-though 技术上我总是在 index.php
).
例如,如果我在 http://localhost/project_name/controller/method/
并且此控制器的构造函数或方法试图将我发送到:
header('location: another_controller/method');
送我到
http://localhost/project_name/controller/method/another_controller/method/
header('location: /another_controller/method');
送我到
http://localhost/another_controller/method/
但我希望它像这样发送给我:
header('location: /another_controller/method');
送我到
http://localhost/project_name/another_controller/method/
现在我找到的唯一解决方案是:
define('BASE_URL','http://localhost/project_name');
header('location: '.BASE_URL.'/another_controller/method/');
但这也不完美,因为每当域名或文件夹名称更改时,我都必须更改这个定义的常量 BASE_URL
。我也可以在我的 BaseController
中创建一个创建绝对 URLs 的方法,但是这个方法基本上也只是在前面加上 BASE_URL
。
注意:HTML的src
和href
属性不会出现同样的问题,可以使用相对路径(路径中没有 project_name
文件夹)。但是我不明白为什么。因为如果 header location
导致浏览器将 relative-URL 附加到当前位置,为什么在查找 .css
或 [= 时它没有相同的行为32=] 个文件。
所以... 这对我提出了几个问题:
- 如果我有虚拟主机,我会遇到这个问题吗?
- 解决这个问题的最佳方法是什么?
- 是否最好只拥有完整的绝对值URL?
- 为什么 HTML 的
src
和 href
属性不共享此行为?
回答您的问题:
- 这取决于您的虚拟主机的配置方式。
- 您可以简单地动态生成 BASE_URL:
$baseUrl = dirname($_SERVER['SCRIPT_NAME']);
。这样,如果您的文件夹或域发生变化,您就不必更改任何代码。
- 您不需要域部分。
- html
src
和 href
由您的浏览器解释,其中考虑了页面的 <base>
标记。带有 <base>
标签的页面上的所有路径都会被您的浏览器相应地更改。
您从服务器发送的 HTTP headers(用于重定向)与您发送的 html 页面无关,因此不会更新。
Now the only solution I have found is:
define('BASE_URL','http://localhost/project_name');
header('location: '.BASE_URL.'/another_controller/method/');
But this isn't perfect either because it causes me to have to change
this defined constant BASE_URL whenever the domain or folder name
changes.
您不需要更改定义的常量。这些值可以动态找到。
示例:
if ($_SERVER['DOCUMENT_ROOT'] == dirname($_SERVER['SCRIPT_FILENAME'])) {
define('BASE_PATH', '/');
} else {
define('BASE_PATH', dirname($_SERVER['SCRIPT_NAME']) . '/');
}
$protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
define('BASE_URL', $protocol . $_SERVER['SERVER_NAME'] . BASE_PATH);
此外,不必担心是指定绝对 URL 还是路径,您可以将重定向包装到一个可以处理两者的函数中:
function redirect($path = null) {
if (isset($path)) {
if (filter_var($path, FILTER_VALIDATE_URL)) {
header('Location: ' . $path);
} else {
header('Location: ' . BASE_URL . $path);
}
} else {
header('Location: ' . BASE_URL);
}
exit;
}
最后,正如@HarshSanghani 在评论中提到的,.htaccess
文件中的基本路径 应该 与代码中的基本路径相匹配。因此,如果 BASE_PATH
(基于上面的示例)输出 /project_name/
,那么您的 .htaccess
应该容纳它:
RewriteBase /project_name/
- 如果您将项目设置在子目录中,就会遇到这个问题。如果您想将虚拟主机设置为 project_name.localhost.
,则使用虚拟主机将是解决问题的一种方法
- 在我的项目中,我使用环境变量为开发、暂存或生产加载不同的配置文件。在这里我设置了一个
$baseUri
不知何故。
- 最佳做法是使用绝对 URL(包括域)来解决此问题和 SEO。在功能方面,您不需要域部分。
- src 和 href 标签通常以相同的方式工作,但正如 Andreas 提到的,它们可能会受到 base 标签的影响。
您应该在 htaccess 文件中指定 RewriteBase。在你的链接中使用相对路径,你不需要更多。
RewriteBase /project_name/
RewriteEngine on
RewriteCond !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url= [QSA,L]
我在 WampServer 上有一个本地项目 运行。这是一个 MVC-like 结构;它将 URL 重写为 index.php?url=
。完整 .htaccess
:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url= [QSA,L]
当我想使用 PHP location: <location>
将用户发送到另一个页面时,由于重写(all-though 技术上我总是在 index.php
).
例如,如果我在 http://localhost/project_name/controller/method/
并且此控制器的构造函数或方法试图将我发送到:
header('location: another_controller/method');
送我到http://localhost/project_name/controller/method/another_controller/method/
header('location: /another_controller/method');
送我到http://localhost/another_controller/method/
但我希望它像这样发送给我:
header('location: /another_controller/method');
送我到http://localhost/project_name/another_controller/method/
现在我找到的唯一解决方案是:
define('BASE_URL','http://localhost/project_name');
header('location: '.BASE_URL.'/another_controller/method/');
但这也不完美,因为每当域名或文件夹名称更改时,我都必须更改这个定义的常量 BASE_URL
。我也可以在我的 BaseController
中创建一个创建绝对 URLs 的方法,但是这个方法基本上也只是在前面加上 BASE_URL
。
注意:HTML的src
和href
属性不会出现同样的问题,可以使用相对路径(路径中没有 project_name
文件夹)。但是我不明白为什么。因为如果 header location
导致浏览器将 relative-URL 附加到当前位置,为什么在查找 .css
或 [= 时它没有相同的行为32=] 个文件。
所以... 这对我提出了几个问题:
- 如果我有虚拟主机,我会遇到这个问题吗?
- 解决这个问题的最佳方法是什么?
- 是否最好只拥有完整的绝对值URL?
- 为什么 HTML 的
src
和href
属性不共享此行为?
回答您的问题:
- 这取决于您的虚拟主机的配置方式。
- 您可以简单地动态生成 BASE_URL:
$baseUrl = dirname($_SERVER['SCRIPT_NAME']);
。这样,如果您的文件夹或域发生变化,您就不必更改任何代码。 - 您不需要域部分。
- html
src
和href
由您的浏览器解释,其中考虑了页面的<base>
标记。带有<base>
标签的页面上的所有路径都会被您的浏览器相应地更改。
您从服务器发送的 HTTP headers(用于重定向)与您发送的 html 页面无关,因此不会更新。
Now the only solution I have found is:
define('BASE_URL','http://localhost/project_name'); header('location: '.BASE_URL.'/another_controller/method/');
But this isn't perfect either because it causes me to have to change this defined constant BASE_URL whenever the domain or folder name changes.
您不需要更改定义的常量。这些值可以动态找到。
示例:
if ($_SERVER['DOCUMENT_ROOT'] == dirname($_SERVER['SCRIPT_FILENAME'])) {
define('BASE_PATH', '/');
} else {
define('BASE_PATH', dirname($_SERVER['SCRIPT_NAME']) . '/');
}
$protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
define('BASE_URL', $protocol . $_SERVER['SERVER_NAME'] . BASE_PATH);
此外,不必担心是指定绝对 URL 还是路径,您可以将重定向包装到一个可以处理两者的函数中:
function redirect($path = null) {
if (isset($path)) {
if (filter_var($path, FILTER_VALIDATE_URL)) {
header('Location: ' . $path);
} else {
header('Location: ' . BASE_URL . $path);
}
} else {
header('Location: ' . BASE_URL);
}
exit;
}
最后,正如@HarshSanghani 在评论中提到的,.htaccess
文件中的基本路径 应该 与代码中的基本路径相匹配。因此,如果 BASE_PATH
(基于上面的示例)输出 /project_name/
,那么您的 .htaccess
应该容纳它:
RewriteBase /project_name/
- 如果您将项目设置在子目录中,就会遇到这个问题。如果您想将虚拟主机设置为 project_name.localhost. ,则使用虚拟主机将是解决问题的一种方法
- 在我的项目中,我使用环境变量为开发、暂存或生产加载不同的配置文件。在这里我设置了一个
$baseUri
不知何故。 - 最佳做法是使用绝对 URL(包括域)来解决此问题和 SEO。在功能方面,您不需要域部分。
- src 和 href 标签通常以相同的方式工作,但正如 Andreas 提到的,它们可能会受到 base 标签的影响。
您应该在 htaccess 文件中指定 RewriteBase。在你的链接中使用相对路径,你不需要更多。
RewriteBase /project_name/
RewriteEngine on
RewriteCond !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url= [QSA,L]