Forum Moderators: phranque

Message Too Old, No Replies

/directory1/directory2 rewrite as /directory3

         

robertdjung

10:43 pm on Nov 29, 2006 (gmt 0)

10+ Year Member



Been banging my head against this forum for the last hour. I can't figure this out:

I have a directory that's two layers deep -- example.com/directory1/directory2

and I'd like it to be accessible instead as the more friendly, and shorter -- example.com/directory3

I would have thought this was straight-forward rewrite. Am I wrong?

Thank you so much in advance.

jdMorgan

11:19 pm on Nov 29, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Please post your best-effort code as a basis for discussion.

Jim

robertdjung

2:12 am on Nov 30, 2006 (gmt 0)

10+ Year Member



Thanks for the reply, Jim.

I'm trying to use

Options +FollowSymlinks
RewriteEngine On
RewriteRule ^/test(.*) /test2/$1 [R, L]

Which I figured was how to do it based on trying to reverse engineer your posts on
[webmasterworld.com...]

I've placed this htaccess file in the /test directory, and hoping that calls to /test will redir to /test2. Nothing seems to be happening.

jdMorgan

2:17 pm on Nov 30, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



In a per-directory .htaccess context, the URL-path seen by RewriteRule is localized to that directory. In other words, the path to the .htaccess file's directory is removed from the path examined by RewriteRule. This is so that the code in that .htaccess file need have no knowledge of the path above it (for example, a user in his own subdirectory might not even know this information, so the server takes care of it automagically.

Because of this, the leading slash in your RewriteRule pattern will never match.

You also stated in your first post that you wanted a two-level-deep subdirectory rewritten to a one-level-deep subdirectory. Your rule will rewrite all subdirectories one-level-deep and deeper, to a subdirectory level one less that the original. In other words, it tests and strips out only the top-level subdirectory, and keeps the rest.

It's possible that that is the behaviour you want. It's also possible that you're only looking to rewrite a specific two-level subdirectory, and no others -- I can't tell from your post. But it is equally important to consider what you don't want to rewrite as well as what you do want to rewrite.

The fix for your posted code is:


Options +FollowSymlinks
RewriteEngine on
RewriteRule [b]^te[/b]st(/.*)?$ /test2$1 [L]

And to rewrite the literal path you posted in this thread's description, you're looking for something like:

Options +FollowSymlinks
RewriteEngine on
RewriteRule ^directory1/directory2(/.*)?$ /directory3$1 [L]

Jim

robertdjung

10:30 pm on Nov 30, 2006 (gmt 0)

10+ Year Member



Thanks for the patient reply, Jim.

Sorry about the test thing. I was trying to make it easier to understand.

OK, I want /directory1/directory2 to look like /directory3. And anything below /directory1/directory2 to also do the same.

My use is that I have a script for a users bio, and I want them all to be accessible from /users/username instead of /directory1/directory2/username

From the code, it looks like this version of the htaccess should go in /directory1.

I've placed the htaccess file in /directory1 but the only thing that happens is that when I leave off the trailing slash "www.example.com/directory1/directory2" it redirects to "example.com/directory1/directory2/". Entering "www.example.com/directory1/directory2/" just pulls up the index page in the directory, no redirects.

Thank you so much for your help.

Also, when a user types in /directory3/username.html, how will the rewrite rule know that it should be pulling the data from /directory1/directory2/?

jdMorgan

10:43 pm on Nov 30, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I'm not proposing to write your code for you, since that's not in our charter. However, one of my examples can be easily modified for your users/username-type URLs.

For more information, see the documents cited in our forum charter [webmasterworld.com] and the tutorials in the Apache forum section of the WebmasterWorld library [webmasterworld.com].

As for "how it knows," it knows because you tell it to look for a certain URL-path in the incoming request by specifying a RewriteRule pattern, and to change the internal filepath associated with that URL to the one you give in the substitution. This is one of the major functions of mod_rewrite.

Jim

robertdjung

2:02 am on Dec 1, 2006 (gmt 0)

10+ Year Member



Thanks again. If you'd be so kind while I break down what I think I know:

RewriteRule ^directory1/directory2(/.*)?$ /directory3$1 [L]

"^directory1/directory2" --- string to match is "directory1/directory2" and we've left off the first "/" because apache doesn't return the first one like we've talked about.

"(/.*)" --- for the match, this requires there to be a "/", and then allows for any number of any characters after that to be matched, and this includes a second "/" if one existed.

"(/.*)?$" --- the "?" modifies the match so that it will match only if there is nothing trailing "directory2", or if there is one match trailing "directory2".

This is important because there's a chance that there will be nothing trailing "directory1/directory2", and if there's nothing, this still ensures a match.

Finally, the "$" signals the end of looking to match a pattern.

for the rewrite ---

/directory3$1 --- this rewrites the URL to "/directory3/SUBDIR-OR-FILE" and could theoretically return something like "/directory3/sub1/sub2/index.html"

You use the $1 because that's the first pattern matched. Curious what a $0 would do. And you don't need a "/" before the $1 because it's included in the match.

My only other question, and I think I understand it, is that we're not using a [R] redirect because that "tells on you" that you're redirecting, and we want this to be silent, eg, look normal.

Would there be some other reason that my server isn't liking this latest attempt. Maybe I should refine that and say "some common reason that's abundantly clear to experts and not to me", since I'm still learning. :)

Thanks again so much for the help -- it doesn't seem as hard once you get into it, it's just the help getting past that wall!

robertdjung

2:23 am on Dec 1, 2006 (gmt 0)

10+ Year Member



And now I believe i have it. I was under the impression that I needed the htaccess file in /directory1, whereas I needed it in root.

robertdjung

3:47 am on Dec 1, 2006 (gmt 0)

10+ Year Member



Well, I have it close.

Acessing /dir3 gives me the index from /dir1/dir2 and still reads "/dir3", which is the intent.

I figured that I could install a redirect so that when someone calls /dir1/dir2 they'll get /dir3, but when I tried I went into infinite loop. What's a good way to do this?

I guess this is where my limits on skipping rules shows.

I figured
RewriteRule ^directory3(/.*)?$ /directory1/directory2$1 [L S=1]
RewriteRule ^directory1/directory2(/.*)?$ /directory3$1 [R,L]

would skip the next rule if it was true, and therefore avoid an infinite loop.

Here's another thing I don't get...

RewriteRule ^directory3(/.*)?$ /directory1/directory2$1 [L]

If I type /directory3 without the trailing slash it dumps me to /directory1/directory2. If I include the trailing slash/and/or slash + a filename, the address bar stays at /directory3/ and reads from /directory1/directory2.

Why is that?

Thanks again.

jdMorgan

3:25 pm on Dec 1, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Your redirect "skip" won't work, because a redirect ends the current HTTP transaction, sends the redirect URL to the client, and the client then starts a completely-new HTTP request using the redirect URL.

The new HTTP request has no "memory" of the previous request, because HTTP is a stateless protocol.

You need to examine the actual client request header to prevent this problem, and apply the redirect only if the original client (browser or robot) request is for the 'hidden' directory, and not if the hidden directory URL is the result of the previous internal rewrite.


# Rewrite user account requests to user subdir
RewriteRule ^directory3(/.*)?$ /directory1/directory2$1 [L]
#
# Redirect direct client requests for user subdir back to user account URLs
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /directory1/directory2[^\ ]*\ HTTP/
RewriteRule ^directory1/directory2(/.*)?$ /directory3$1 [R=301,L]

The RewriteCond now looks at the client request header, which, if a direct request is made for the subdir, will look something like this:
GET /directry1/directory2/name HTTP/1.1

If you have any remaining odd behaviour with trailing slashes, etc., make sure that MultiViews are disabled by using


Options +FollowSymLinks -MultiViews

Jim