I have a project running local on WampServer. It's an MVC-like structure; it rewrites the URL to index.php?url=$1
. Full .htaccess
:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
When I want to send the user to another page using PHP location: <location>
it doesn't do this properly because of the rewriting (all-though I am technically always in index.php
).
For example if I am on http://localhost/project_name/controller/method/
and this controller's constructor or method tries to send me to:
header('location: another_controller/method');
sends me to
http://localhost/project_name/controller/method/another_controller/method/
header('location: /another_controller/method');
sends me to
http://localhost/another_controller/method/
But I want it to send me like this:
header('location: /another_controller/method');
sends me to
http://localhost/project_name/another_controller/method/
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. I could also create a method in my BaseController
that creates absolute URLs, but this method would basically just prepend BASE_URL
too.
Note: The same problem doesn't arise with HTML's src
and href
attributes, which can use relative paths (without project_name
folder in path). I don't understand why however. Because if the header location
causes the browser to append the the relative-URL to the current location, why doesn't it have the same behavior when looking for .css
or .js
files.
So... this raises a couple of questions for me:
src
and href
attributes not share this behavior?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.
You shouldn't need to change the defined constant. These values can be found dynamically.
Example:
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);
Additionally, rather than worrying about whether to specify an absolute URL or a path, you can wrap the redirect into a function which can handle both:
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;
}
Finally, as @HarshSanghani mentioned in the comments, the base path in your .htaccess
file should match the base path in your code. So if BASE_PATH
(based on the example above) outputs /project_name/
, then your .htaccess
should accommodate it:
RewriteBase /project_name/