Forum Moderators: phranque

Message Too Old, No Replies

.htaccess newbie needs help

friendly urls with .htaccess

         

whiffin

11:46 am on Jun 22, 2007 (gmt 0)

10+ Year Member



Moving a site over to a new server: We need URLs like

www.mysite.com/page.php/var1/foo/var2/baa

Rather than

www.mysite.com/page.php?var1=foo&var2=baa

On the old server apache called page.php, but on my new server it doesn't, it gives a 404. Therefore I can use PHP to change URLs (got a nifty little script)

QUESTION ONE: Is there a way in .htaccess to say "call page.php rather than 404"?

Anyway, assuming no, I've decide to try and write a rewriterule to make things work. Please bear in mind that page.php may change to page2.php or foo.php etc and there may be 1, 2, 3 ... 20 arguements passed.

Anyway, I started with this

RewriteRule ^([^.]+)\.php/([^.]+)?/([^.]+)?$ pagename.php\?$2=$3

The first problem is that if we pass open somepage.php/id/5 (for example) it works. But if we call pagename.php/id/5 it doesn't, it gives a 404. I assume it's thinking it'll be stuck in a loop or something? What I really wanted to do was:

RewriteRule ^([^.]+)\.php/([^.]+)?/([^.]+)?$ $1\?$2=$3

QUESTION 2 - how do I stop it giving me a 404 whenever I call it using the same page name as where it redirects to (if that makes sense)

QUESTION 3 - easy one. I can make ([^.]+) optional by writing ([^.]+)? ... but how do I make the / optional as well? I've tried (/)?

Any help appreciated

Thanks

jdMorgan

1:57 pm on Jun 22, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



The first, --and possibly most-important-- problem is that you cannot examine a query string using RewriteRule. You must use RewriteCond %{QUERY_STRING} <pattern> to test and/or create back-references to client-requested query strings. Based on your description, it is possible that all other problems are a result of this fundamental one.

This old thread [webmasterworld.com] may be of assistance to you.

Jim

whiffin

2:13 pm on Jun 22, 2007 (gmt 0)

10+ Year Member



Thanks JD, but I don't see why I need a condition?

Surely my example is like this one in the given file:

RewriteRule ^product/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ /index.php?product=$1&color=$2&size=$3&texture=$4&maker=$5 [L]

My difference is I'm trying to do for all files generically, not just for product

What I have now looks like this:

RewriteRule ^([^.]+)\.html/([^.]+)/([^.]+)?$ $1\.php\?$2=$3

Basically, it works:

www.mysite.com/page.html/id/123 -> www.mysite.com/page.php?id=123

But if I change rule to

RewriteRule ^([^.]+)\.html/([^.]+)/([^.]+)?$ $1\.php\?$2=$3

And call

www.mysite.com/page.php/id/123 -> Error 404

Still think it's what you say?

Thanks for replt

whiffin

2:17 pm on Jun 22, 2007 (gmt 0)

10+ Year Member



Ahhhh, think I have it - I need a leading slash on my output

RewriteRule ^([^.]+)\.php/([^.]+)/([^.]+)?$ /$1\.php\?$2=$3

will report back if not - thanks jd

whiffin

2:52 pm on Jun 22, 2007 (gmt 0)

10+ Year Member



Yes, got it working - thanks anyway.

For others, this is what I have done - bit clunky ... but don't know how to loop. Oh, plus it'll put?&=&=&=&= at the end if we have less than the maximum arguements

ANyway:

Options +FollowSymLinks
RewriteEngine on

# This rule will convert:
# pagename.php/ to pagename.php
# pagename.php/a/b/ccc/dd/ to pagename.php?a=b&ccc=dd
# Up to 2 arguement pairs (can be missing)
# RewriteRule ^([A-Za-z0-9_-]+)\.php/([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?$ /$1\.php\?$2=$3&$4=$5

# Now rewrite it for 20 arguement pairs instead
RewriteRule ^([A-Za-z0-9_-]+)\.php/([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?
['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?
['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?
['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?['/']?([^/]+)?
['/']?([^/]+)?['/']?$ /$1\.php\?$2=$3&$4=$5&6=$7&8=$9&10=$11&12=$13&14=$15&16=$17&18=$19&20=$21&22=$23&24=$25&26=$27&28=$29&30=$31&
32=$33&34=$35&36=$37&38=$39&40=$41

[edited by: jdMorgan at 2:58 pm (utc) on June 22, 2007]
[edit reason] Fixed side-scroll [/edit]

jdMorgan

3:03 pm on Jun 22, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



mod_rewrite can handle only nine back-references to RewriteCond pattern matches, designated %1 through %9, and nine back-references to RewriteRule pattern matches, designated $1 through $9, so the approach demonstrated by that last rule isn't going to work.

The usual way to handle variable numbers of query-string name/value pairs is to write a rule for each case; Mod_rewrite is not a full-on scripting language, and it has limitations.

Jim

whiffin

3:10 pm on Jun 22, 2007 (gmt 0)

10+ Year Member



Really? Bugger

That means only 4 variable pairs

OKay, I'll go into that ... now

Thanks

jdMorgan

10:32 pm on Jun 23, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



> That means only 4 variable pairs

No it doesn't! -- I could be arguing in my spare time...

That means 4 variable pairs, plus one "pre-condensed" string passed from a previous chained rule.

Look into RewriteRule chaining if you need to handle a large number of name/val pairs.

Jim

whiffin

8:59 am on Jun 25, 2007 (gmt 0)

10+ Year Member



Gotcha

But I think, relooking at my code, I only need 4 pairs anyway

Hey, that'll do for now

Thanks for your help

jdMorgan

3:07 pm on Jun 25, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Another point I should make is that your query string will be passed through the rule unchanged unless you explicitly clear it or replace it. This may render the above comment moot.

The structure of your rewriterule above is --to put it mildly-- non-optimal. What you're probably looking for si something like this:


RewriteRule ^([a-z0-9_-]+)\.php/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ /$1.php?$2=$3&$4=$5&$6=$7&$8=$9 [NC,L]
RewriteRule ^([a-z0-9_-]+)\.php/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ /$1.php?$2=$3&$4=$5&$6=$7 [NC,L]
RewriteRule ^([a-z0-9_-]+)\.php/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ /$1.php?$2=$3&$4=$5 [NC,L]
RewriteRule ^([a-z0-9_-]+)\.php/([^/]+)/([^/]+)/?$ /$1.php?$2=$3 [NC,L]

Put these rules in order from most-used URL-form to least-used URL-form for best performance. IOW, if most requests are for the short URLs, then put their rules first to save a lot of time wasted parsing the longer patterns.

And as stated previously, you can chain rules if more parameters need to be passed.

Jim

[edited by: jdMorgan at 3:15 pm (utc) on June 25, 2007]