Forum Moderators: phranque

Message Too Old, No Replies

mod_rewrite to remove filenames

/dir/file.php to /dir/

         

nitr0z

11:13 am on Jun 13, 2004 (gmt 0)

10+ Year Member



I'm not sure how complex this would be, as I'm not great with regular expression and have had no luck in my attempts. What I would like to do is change URL's

from:
www.domain.com/dir/file.php

to:
www.domain.com/dir/

However I only want this to happen if the filename (- extension) is the same as the firectory name. If the filename is different to the dirname then I would like URL's to change

from:
www.domain.com/dir/notdirname.php

to:
www.domain.com/dir/notdirname/

I don't know if this can be done in one rule or even at all. I know that It's not right to ask for code outright but I deleted all my attempts in anger about 10 minutes ago because It didnt work and I can't remember what I did.

Hope somebody can help me :).

jdMorgan

2:56 pm on Jun 13, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



nitr0z,

Welcome to WebmasterWorld [webmasterworld.com]!

Yes, this can be done, but it's tricky. We require that you post your best-effort code here for three simple reasons: First, it proves that the poster is conversant with the basic techniques and the language used to describe rewrites. Second, it often clarifies details which the poster has not included in his/her description of the problem and/or goal. And lastly, it acknowledges that the responsibility to learn this stuff rests with the poster, and that we are not a 'free code-writing service' -- Those who wish a quick-fix can post in Commercial Exchange to hire some help; our purpose [webmasterworld.com] here is to discuss Apache and related techniques.

That said, it's not obvious which path actually exists on your server. If you want a user to type-in or click on a link that says "www.example.com/dir/" and for your server to rewrite that to actually deliver content from "www.domain.com/dir/file.php", then that is different than if the situation is reversed. Before we get into the tricky part (which is matching the filename to the dirname), let's be clear on what the user types and what the server serves.

Refs:
Apache mod_rewrite documentation [httpd.apache.org]
Apache URL Rewriting Guide [httpd.apache.org]
Regular Expressions Tutorial [etext.lib.virginia.edu]
Thread showing a trick to do variable-to-variable compare in mod_rewrite [webmasterworld.com].

Jim

nitr0z

3:43 pm on Jun 13, 2004 (gmt 0)

10+ Year Member



To rewrite the URL then filename and dirname were the same ie.

from:
www.domain.com/dir/file.php

to:
www.domain.com/dir/

I was using:
RewriteRule /([0-9],[a-z],[A-Z]+)/([0-9],[a-z],[A-Z]+) $1/

But that doesnt work, not really sure how to send a value using () to the rewritten url.

jdMorgan

3:55 pm on Jun 13, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



nitr0z,

You have asked to rewrite from www.domain.com/dir/file.php to to www.domain.com/dir/

So if the user clicks on a link that goes to www.example.com/dir/file.php, you want to serve the index page at www.example.com/dir/, right? In other words, you want to throw away the "file.php" part? We need to get this clear, because the conditional part is complex, and I don't want to address it until the other details are nailed down.

"Sending" part of the "input" URL (the RewriteRule pattern) to the "output" URL (the RewriteRule substitution) is called a back-reference. Variables $1 through $9 back-reference the parenthesized subpatterns in the RewriteRule itself, while variables %1 through %9 back-reference the parenthesized subpatterns in the last-matched RewriteCond preceding the RewriteRule. This is described in the mod_rewrite documentation cited above.

Jim

nitr0z

4:30 pm on Jun 13, 2004 (gmt 0)

10+ Year Member



When the user types in or clicks on a link to www.domain.com/dir/ i would like it to display the page stored on the server under www.domain.com/dir/file-with-same-name-as-dir.php.

In the case of the filename and the dirname not matching I would like the clicked/typed link to look like www.domain.com/dir/file/ and for it to display the page stored on the server at www.domain.com/dir/file-with-different-name-then-dir.php

I'm sorry I was not as clear as I could have been.

jdMorgan

4:54 pm on Jun 13, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



> When the user types in or clicks on a link to www.domain.com/dir/ i would like it to display the page stored on the server under www.domain.com/dir/file-with-same-name-as-dir.php.

OK, that's the easy part:


RewriteRule ^/([^/]+)/$ /$1/$1.php [L]

(Assumes you're putting this code in httpd.conf, and not in .htaccess).

> In the case of the filename and the dirname not matching I would like the clicked/typed link to look like www.domain.com/dir/file/ and for it to display the page stored on the server at www.domain.com/dir/file-with-different-name-then-dir.php

How would this happen? The rule above creates the filename from the requested directory name, so they would always be the same. Again, the 'compare' code is complex, and will be hard to debug if it doesn't work, so I want to get this right first. Do you have existing links to /<dir>/something-other-than-<dir>.php that you need to rewrite? If so, how many subdirectory levels can there be -- Do you need to handle cases like /dir1/dir2/<dir>/something-other-than-<dir>.php as well?

Jim

nitr0z

5:33 pm on Jun 13, 2004 (gmt 0)

10+ Year Member



Ahh, I see what you mean. I am actually using .htaccess but don't worry about that, converting it is the least i can do.

I will explain exactly how what I am trying to implement should work. The site I am working on will have several 'base' directorys relating to the content. To clarify; files for sections 'photos' and 'about' will be stored in directories /photos/ and /about/ respectively, there will be no physical subdirectories within these directories.

The complications may come when some sections need categorising further, for this I will use more rewrite rules to make the URL look like www.domain.com/photos/cat1/photoname/ but actually be running www.domain.com/photos/photos.php?$cat=cat1&$photo=photoname

^-- hope you can understand that :).

With sections that do not require sub-categorising such as the about section all the files will be contained within /about/ and files not called "about.php" within this directory will be viewed from the URL www.domain.com/about/not-called-about/

Sorry if I'm not being as clear as I could be, basically it wont need to work for more then one directory deep but would need to be compatible with the other rewrites i have mentioned, hopefully I will be able to work out those ones myself :).

Thankyou for your continued patience. :P.

jdMorgan

6:00 pm on Jun 13, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Don't worry about the difficulty of communicating this stuff -- it's always hard. On average, the quality of answers is directly proportional to the depth of the problem description.

I'll be away for awhile, so here's the whole mess.

This .htaccess-specific code will only work for URLs of the form:
/dir/file_not_same_as_dir/
- and -
/dir/
as you specified. Other cases will not be handled. This makes the code 'safer' but less flexible.

 
# If URL-path in the form /dir/file/ then get dir into %1 and file into %2
RewriteCond %{REQUEST_URI} ^/([^/]+)/([^/]+)/$
# If filename not equal to dirname (this code compares dir<>file to dir<>dir)
RewriteCond %1<>%2 !^(.+)<>\1$
# Then rewrite /dir/file/ to /dir/file+dir.php and quit
RewriteRule ^([^/]+)/([^/]+)/$ /$1/$2$1.php [L]
#
# If the above Rule was not invoked, then dir is not equal to
# filename, so just rewrite /dir/ to /dir/dir.php and quit
RewriteRule ^([^/]+)/$ /$1/$1.php [L]

The "\1" reference in the second RewriteCond is not described in the mod_rewrite documentation anywhere. It is a local backreference as defined by standard regular expressions, and refers to the immediately-preceding parenthesized group. Therefore it "copies" the value just to its left, which is in turn a copy of the %1 variable from the first RewriteCond, and so is equal to the dir name. Thus, this code compares dir+file to dir+dir, and it will only match if dir is equal to file. (Logical basis: If A+B is equal to A+A, then it follows that A is equal to B.) The "!" then negates this logic.

The "<>" string is completely arbitrary; I use it to imply concatentation, but actually, it serves only to delimit the two variables in case they share certain characteristics. I.e., I use it to keep the dir and file names unambiguously separate here. You could use any string that has no special meaning in regular expressions and that you're sure won't appear in your URLs; I just liked "<>".

I hope there are no remaining typos!

Thanks again to member Andreas Friedrich for posting this technique here on WebmasterWorld.

Jim

nitr0z

8:01 pm on Jun 13, 2004 (gmt 0)

10+ Year Member



># Then rewrite /dir/file/ to /dir/file+dir.php and quit
>RewriteRule ^([^/]+)/([^/]+)/$ /$1/$2$1.php [L]

Can I just ask why you have concatented the file+dir.php together. The path to the file on the server will only be /dir/file.php. Perhaps I understand this wrong, but wouldnt the above code read the file /dir/filedir.php?

Other then that thankyou very much, you have not only solved a problem for me but I have learnt a lot about mod_rewriting as well, thankyou!

jdMorgan

9:06 pm on Jun 13, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Yes, I may have misunderstood this:

> In the case of the filename and the dirname not matching I would like the clicked/typed link to look like www.domain.com/dir/file/ and for it to display the page stored on the server at www.domain.com/dir/file-with-different-name-then-dir.php

Maybe you meant file-with-different-name-than-dir.php

Just leave that second $1 back-reference out as you surmised.

Jim

[added]... and thank Andreas if you ever meet him for showing us all this ingenious variable comparison trick! [/added]

nitr0z

9:16 pm on Jun 13, 2004 (gmt 0)

10+ Year Member



*embarrased*

I've got it all working, thanks again. Now I just have to re-work my filepath output script to work with my shiny new URL's :P.