Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Absolute URL from base folder with rewrite

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:

  1. Would I have this problem if I had virtual hosts?
  2. What is the best way to solve this problem?
  3. Is is best to just have the full absolute URL?
  4. Why do HTML's src and href attributes not share this behavior?
like image 579
kgongonowdoe Avatar asked May 02 '16 09:05

kgongonowdoe


2 Answers

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/
like image 74
mister martin Avatar answered Sep 30 '22 14:09

mister martin


To answer your questions:

  1. It depends on how your virtual hosts would be configured.
  2. You could simply generate your BASE_URL dynamically: $baseUrl = dirname($_SERVER['SCRIPT_NAME']);. This way you won't have to change any code if your folder or domain changes.
  3. You don't need the domain part.
  4. The html src and href are interpreted by your browser which takes into account the page's <base> tag. All paths on a page with a <base> tag get changed accordingly by your browser.

The HTTP headers you send from your server (for redirect) have nothing to do with the html page you send and are therefore not updated.

like image 36
Andreas Scheibleger Avatar answered Sep 30 '22 14:09

Andreas Scheibleger