views:

279

answers:

5

I have successfully created rewrite rules to handle URLs like

http://example.com/xyz

http://example.com/xyz/

http://example.com/xyz/abc

http://example.com/xyz/abc/

Here is the mod rewrite & regex:

Options +FollowSymlinks
RewriteEngine On
RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^/?([0-9]+)(?:\/)?$ /index.php?p=$1 [L]
RewriteRule ^/?([-a-zA-Z0-9_+]+)(?:\/)?$ /index.php?n=$1 [L]
RewriteRule ^/?([-a-zA-Z0-9_+]+)/([-a-zA-Z0-9_+]+)(?:\/)?$ /index.php?n=$2 [L]

This works great, but the problem is that when I go to http://example.com/xyz/abc, my script gets the correct input (n=abc) but the paths are messed up, so all relative URLs in my code are broken, as they are now relative to xyz instead of the root.

Is there a way around this at all? As you can see above I have tried to redirect to /index.php to force the path to be correct. My brain is fried after a long day of regex and code, so I hope it's not something disastrously trivial.

+2  A: 

Edit: I assume you are talking about URLs in your HTML code, e.g. to images and stylesheets, that are broken.

Nope, as far as I know there is no way around it, because the browser sees a path, and requests resources relative to it. It has nothing to do with the server, and there is nothing you can do.

You will either have to resort to a different splitter that is not interpreted as a directory splitter (e.g. underscores), or use absolute paths, or use the <base> tag. I have never used the base tag myself, however, and it is not very well regarded wherever you look. The best thing would probably be to switch to absolute paths.

Pekka
thanks for your input... I kind of hope there is a way around it. Please let me know if you have reading that positively identifies this as the case and I will accept this answer.
Antony Carthy
Note that changing the base URI will affect *every* relative URI and not just those that start with the URI path.
Gumbo
@Antony: I'm quite sure you won't get around it if you continue using slashes - a path is a path. Have you considered using a different character for your virtual paths? That doesn't look as nice but does the job. I have seen commas used, which to my eye looks quite ok even though it's not entirely legal.
Pekka
@pekka I unfortunately need to use this URL structure due to project requirements, but I do agree a different delimiter would be more appropriate.
Antony Carthy
@Pekka Gaiser: Using other characters instead of the segment separator `/` has a complete different meaning for the URL as the segments normally represent a hierarchy.
Gumbo
@Gumbo: I'm totally with you, but if there really is no other choice, who cares what my URL looks like? Either way, it's a valid path to a resource. Not that I'm in favour of that solution. I prefer proper, absolute paths as well. :)
Pekka
+1  A: 

modify your last RewriteRule to include the path. you have the path in the regular expression.

RewriteRule ^/?([-a-zA-Z0-9_+]+)/([-a-zA-Z0-9_+]+)(?:\/)?$ $1/index.php?n=$2 [L]

or alternatively (depending on what you are trying to achieve):

RewriteRule ^/?([-a-zA-Z0-9_+]+)/([-a-zA-Z0-9_+]+)(?:\/)?$ /index.php?n=$1/$2 [L]
Adrien Plisson
thats kind of the reverse of what I want - it needs to be using the root.
Antony Carthy
+4  A: 

Use the HTML base element to force all relative URLs to use a different path than the one the browser displays.

<base href="http://www.example.com/"/&gt;
...
<a href="relative/url">link</a>

The relative URL will use "http://www.example.com" as its base, even if the browser thinks it's looking at the page "http://www.example.com/xyz/". So the link goes to "http://www.example.com/relative/url" instead of "http://www.example.com/xyz/relative/url"

And there's the Stack Overflow way of doing it, in which every URL is either an absolute path (to resources like images) or paths including the root (i.e. "/feeds/questions/123"), which avoid the relative path issues.

Welbog
Note that changing the base URI will affect *every* relative URI and not just those that start with the URI path.
Gumbo
A: 

I tried using the BASE element in my pages as a shortcut instead of changing all urls. Add the base element as follows:

<base href="/">

And here are the results:

This:    <link type="text/css" rel="stylesheet" href="my.css">
Becomes: <link type="text/css" rel="stylesheet" href="/my.css">

This:    <script type="text/javascript" language="javascript" src="include/my.js"></script>
Becomes: <script type="text/javascript" language="javascript" src="/include/my.js"></script>

This:    <a href="foo.html">
Becomes: <a href="/foo.html">

This:    <a href="foo/bar.html">
Becomes: <a href="/foo/bar.html">

You can always override the base tag where necessary:

This:    <a href="/foo">
Remains: <a href="/foo">

This:    <a href="/foo/bar/">
Remains: <a href="/foo/bar/">
Salman A
Note that changing the base URI will affect *every* relative URI and not just those that start with the URI path.
Gumbo
+2  A: 

The three options are:

1) Use a base tag (this will affect every relative URI on your page, including links, images, scripts, stylesheets and so on)

<base href="http://yoursite/"&gt;

2) Change all of your links to fully qualified URIs

<a href="http://yoursite/yourpage.html"&gt;

3) Use the "/" prefix to show that the path is relative to the root on each URI.

<a href="/yourpage.html">

I have personally used the base-tag option the most, which does get some bad press (from people that have used it without really understanding it). When it comes to mod_rewrite, the base tag is perfect as you probably DO want all your paths to be relative to the root, including all your images, css, scripts and links.

Sohnee
You and Welbog both had nice answers. Gave the accepted one to you as the underdog points wise. Thanks.
Antony Carthy