views:

172

answers:

4

I've been wondering this for a while now, but what is the best way to ensure that in a web app (RoR, Sinatra, PHP, anything) that when you are creating links (either generating with a method, or writing in by hand) that they go to the proper place whether you are on the root of a domain or not: http://www.example.com/ or http://www.example.com/this/is/where/the/app/is/

My thoughts are get the end-user to specify a document root somewhere in the config of your app, and use that, however I'm trying to think of a nice way to do it without the end-user having to configure anything.

Edit: By end-user, I mean the person setting up the application on a server.

Edit: I can use the beginning '/' to always get the link relative to the domain, but the problem is what if the app itself is not at the root, but some place like http://www.example.com/this/is/where/the/app/is/ so i want to say gen_link('/') and have it return /this/is/where/the/app/is/ or gen_link('/some/thing') and return /this/is/where/the/app/is/some/thing

A: 

You can determine everything you need yourself, no need for configs.

Here’s a PHP example (let’s say index.php is your script name):

<?
  $folder_on_server = substr ($_SERVER['PHP_SELF'], 0, strpos ($_SERVER['PHP_SELF'], '/index.php'));
  $server_name = $_SERVER['SERVER_NAME'];
  if (80 != $_SERVER['SERVER_PORT']) {
    $server_name .= ':'. $_SERVER['SERVER_PORT'];
  }
  $full_site_url = 'http://'. $server_name . $folder_on_server;
?>

Now, you can always make a link like this:

<a href="<?= $full_site_url ?>/some/thing/">Something</a>

See also discussion in comments.

Ilya Birman
For that though, if your app is on http://www.example.com/foo/bar/ and you are handling a request for http://www.example.com/foo/bar/baz/biz/ the $folder_on_server will end up being '/foo/bar/baz/biz' correct? I want it to end up as '/foo/bar' which is the root of the app.
Daniel Huckstep
My practice is to handle all requests whatsoever through index.php in app’s root folder. So, $folder_on_server will always be /foo/bar no matter what request you are handling. I call (include) what I like from index.php, but it’s my entry point to everything :-)
Ilya Birman
SERVER_NAME is inconsistent. http://shiflett.org/blog/2006/mar/server-name-versus-http-host. It's totally useless if your app server is behind a load balancer or proxy (as is HTTP_HOST for that matter). You would need HTTP_X_FORWARDED_HOST if available.
Crescent Fresh
Note: sometimes PHP_SELF is unavailable (php cgi I think) and you have to fallback on inspecting ORIG_SCRIPT_NAME. It may be easier to just reference SCRIPT_NAME.
Crescent Fresh
A: 

ilya's answer is a good one, but I think a simpler way to do this is just to precede all your links with a leading "/". This will ensure that they are always relative to the root of the domain:

<a href="/some/thing">Something</a> <!-- Always links to www.domain.com/some/thing -->
<a href="some/thing">Something</a> <!-- Acutal destination depends current path -->
Eric Petroelje
+1  A: 

First of all you need to route all your urls through some kind of url re-writer function.

So you no longer do:

<a href="some/path/">Foo</a>

But instead something like:

<a href="<%= url_for('some/path') %>">Foo</a>

All the web frameworks out there have a function like this. While they usually do all kinds of magic in there (to do with MVC controller paths and views and what not), at the end of the function (conceptually) they all prepend your url with a "root" (eg "/this/is/where/the/app/is/"), so as to allow you to create urls in your application that are independent of a hard-coded base path.

RoR uses a configuration directive called "relative_url_root".

Symfony (php) uses a configuration directive also called "relative_url_root".

CakePHP uses a configuration directive called "WEBROOT_DIR".

In cases where these frameworks are running on Apache, this value is often calculated dynamically (if you haven't set it explicitly). On other webservers the environment variables are often not available or are incorrect so this value cannot be determined consistently.

Crescent Fresh
+2  A: 

How about trying to set the base element in the head of you html layout?
First, get the URL, eg. in a way Ilya suggests (if PHP is OK for you). After that you can use the base tag as follows:

<base href="<?= $full_site_url ?>" />

That will set the default URL for all the links and the browser will prepend it to every relative link on the page.

Milan Novota
I used this before but forgot about it. This will do the trick.
Daniel Huckstep