1

What I'd like to do is make a directory act as root for a particular application. So resources linked as "/style.css" would actually load from "website.com/forum/style.css".

I have rewrite rules in htaccess so a web address of "forum/thread/12345" points to "forum/thread.php?id=12345"

RewriteRule ^thread/([0-9]+)/?([0-9]+)?$ thread.php?t=$1&p=$2 [NC,QSA]

Because of the rules, relative paths don't look in the directory of where the actual file is located (as I initially thought) so whereas thread.php is located inside "forum" directory, if I attempt to load "style.css" it looks for "thread/style.css" because of the rewrite structure.

I want to avoid absolute paths so the forum directory can be renamed or moved easily if need be. My initial solution was simply to use the base tag:

<base href="/forum/">

While this technically hardcodes a path into each page, changing that once on each page is better than maintaining all the resource links. Plus, I could set php variable to handle this from one spot.

But then I ran into another problem, anchors. Anchor tags no longer respect the current address and look at the base url. So "forum/thread/12345#thing" instead becomes "forum/#thing". I understand the easiest fix is probably to just prefix the link with the full page path but I'd like to see if that's avoidable. Ideally I'd like to avoid using base too if possible.

I'm probably way overthinking this and missing the obvious. So if anyone understands what I tried to explain can ya point me in the right direction?

1 Answer 1

1

resources linked as "/style.css"

/style.css (with a slash prefix) is a root-relative URL-path. If you were consistently using root-relative URLs like this, with "files" in the document root, then the problem would be easier to resolve. However, you later state you are using "relative paths" which results in "thread/style.css", which means you are referencing style.css only (no slash prefix). This is harder to resolve and causes additional problems.

Ideally, you should be using root-relative (or even absolute) URLs throughout (for static assets and internal links). eg. /forum/style.css. If the root directory is variable, then build this into your application and construct the URLs dynamically.

RewriteRule ^thread/([0-9]+)/?([0-9]+)?$ thread.php?t=$1&p=$2 [NC,QSA]

This rule suggests you could request /forum/thread/12345 or /forum/thread/12345/67890 (or even /forum/thread/12345/ - potentially a duplicate content issue as this would presumably serve the same content as the URL without the trailing slash). If you are using just relative URLs like style.css only then this will resolve to /forum/thread/style.css and /forum/thread/12345/style.css respectively. And obviously 12345 is variable, so we have many potential variations we need to "correct" with rules in .htaccess. If you have other URLs at differing path-depths then more rules could be required in .htaccess to correct these as well. This can get messy very quickly... difficult to maintain and more prone to error. Not to mention issues with canonicalisation and caching, since you potentially have an infinite number of URLs that all serve the same cacheable resource. (To resolve these issues, it would need to be an external redirect - but that would cause other problems for users and your server... performance and load.)

So, this comes back to using root-relative URLs as mentioned above. ie. /forum/style.css in your example.

Aside: Unless the above rule is the only rule in your .htaccess file then you should include the L (or END) flag to prevent other directives that follow being processed. The use of the NC flag also creates potential duplicate content issues since /thread/12345 and /THREAD/12345 (two different URLs) will return the same content. (Presumably you are using the canonical meta tag in the page to help resolve this?)

As an academic exercise only:

If you are consistently using a root-relative URL of the form /style.css (starting with a slash and no other path information) and this needs to be rewritten to /forum/style.css then you could implement a rule in the root .htaccess file as follows. (I note from your rule above that you are using a .htaccess file located in the /forum/ subdirectory, not the root.)

For example:

# /.htaccess - ROOT .htaccess file

RewriteEngine On

# Rewrite "/file.ext" to "/forum/file.ext" if "/file.ext" does not exist,
# ...but "/forum/file.ext" does exist
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/forum/$0 -f
RewriteRule ^[\w-]+\.\w{2,4}$ forum/$0 [L]

Note, it is necessary to hardcode the /forum/ directory in the above rule.

However, if you are using relative URLs of the form style.css then to "correct" just the examples stated above you could do something like the following in the /forum/.htaccess file, before your existing rewrites (the order could be important).

# /<dir>/.haccess (ie. "/forum/.htaccess")

RewriteEngine On

# Calculate the value of "<dir>" - the parent directory - when requesting what looks-like a file
# This is stored in the environment variable "DIR"
RewriteCond %{REQUEST_URI} ^/([^/]+)
RewriteRule .\w{2,4}$ - [E=DIR:%1]

# Rewrite "/<dir>/thread/file.ext" (or "/<dir>/thread/<number>/file.ext") to "/forum/file.ext"
RewriteCond %{DOCUMENT_ROOT}/%{ENV:DIR}/$1 -f
RewriteRule ^thread/(?:\d+/)?([\w-]+\.\w{2,4})$ $1 [L]

The above could be simplified if you blindly rewrite requests to /forum/ without first testing for the file, but you will end up with a lot of unnecessary rewrites and a poluted access log.

This also does not resolve the canonicalisation/caching issues mentioned above.

(This also assumes you don't have a physical directory called /forum/thread/.)

Sign up to request clarification or add additional context in comments.

1 Comment

The rule is accurate in what I want, the 2nd possible number pertains to a page number. Omitted, it assumes page 1. I'm aware of the NC flag, that is intentional. And I do have additional rules in the htaccess. The idea is to have everything self contained, so that I could drop this into any directory and not rely on it being in "/root/forum". Ideally, so I could simply move it to "/root/apps/chat" or whatever and not have to worry about changing resource paths. If I could make all the scripts see a specified path as root that would be good. Using relative paths break due to the rules

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.