Forum Moderators: phranque

Message Too Old, No Replies

Rewrite with query string AND folder variables

         

tommyb

1:01 am on Dec 7, 2011 (gmt 0)

10+ Year Member



Hi,

I am trying to get a url that comes from my site to redirect. The source URL can be one of two patterns:

http://example.com/en/category/123/widgets

or

http://example.com/en/category/123/widgets?page=2


I want this to then redirect to:

http://example.com/index.php?event=page.category&languageid=en&categoryid=123&urlAlias=widgets

or

http://example.com/index.php?event=page.category&languageid=en&categoryid=123&urlAlias=widgets&pageNumber=2

I have tried this (for the second type of URL) but it doesn't seem to work:

RewriteCond %{QUERY_STRING} page=(.*)
RewriteRule ^(.*)/category/([0-9]+)/(.+)$ index.php?event=page.category&languageid=$1&categoryid=$2&urlAlias=$3&pageNumber=%1 [NE,R=301,L]


Can anyone point me in the right direction?

Many thanks,
Tom

g1smd

1:24 am on Dec 7, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



(.*) is the wrong pattern to use. Use a more specific pattern.

Are you sure you want to redirect a "simple" URL to a more complicated one? Don't you instead want to rewrite the request and serve the content at the "simple" URL?

"Doesn't work" is of no help whatsoever in working out what went wrong. What was it supposed to do? What did it actually do?

tommyb

12:32 pm on Dec 7, 2011 (gmt 0)

10+ Year Member



Hi,

OK, sorry for not going into enough detail. It was a bit late in the evening.

Basically, I need to redirect the simple URL to the more complicated one which is then itself rewritten back to a simple URL.

Is that possible?

So the simple URL is being passed to the underlying "complicated" URL that my development framework requires to work, and then that in turn is rewritten into a simple URL for the end user to see. I don't want the end user to have to see the "complicated" url as I wish to mask the underlying framework/server technology as much as possible.

I am currently on a testing box and when I make the redirect it comes back with this error:

You don't have permission to access /C:/dev/example/wwwroot/index.cfm on this server.

and url address bar does appear to have done some sort of redirect as it looks like this:

http://example.com/C:/dev/example/wwwroot/index.cfm?event=page.category&languageid=en&categoryid=123&urlAlias=widgets&pageNumber=2

If I could eliminate the /C:/dev/example/wwwroot/ bit of the URL it might work as intended.

Best regards,
Tom

g1smd

2:08 pm on Dec 7, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Basically, I need to redirect the simple URL to the more complicated one which is then itself rewritten back to a simple URL.

Approximately 90% of the people arriving at this forum don't fully understand the difference between a redirect and a rewrite and/or get the explanation of how a rewrite works exactly backwards. (This estimated figure arrived at from lurking here for the last five years).

Are you sure that you want what you asked for above? Usual operation is:

I need to rewrite requests for the simple URL to fetch content from the complex internal path. For users still requesting the complex URL I need to redirect them to the simple URL.


URLs are used "out there" on the web. Filepaths are used "here" inside the server. URLs and filepaths are not at all the same thing; they are merely associated by the action of the server software. The site should link to the simple URL. It is links that define URLs. Mod_rewrite springs into action only after the link is clicked. Mod_Rewrite cannot change a URL, nor can it change the links on the pages.

tommyb

2:35 pm on Dec 7, 2011 (gmt 0)

10+ Year Member



OK, sorry, my inaccuracy. In that case I meant rewrite the URL, not redirect.

The links on the site are going to be in the form:

http://example.com/en/category/123/widgets

or

http://example.com/en/category/123/widgets?page=2

I need to find a way to rewrite these urls into the form:

http://example.com/index.php?event=page.category&languageid=en&categoryid=123&urlAlias=widgets

for the purpose of the server to do the processing that it needs to.

This will then be rewritten (or redirected?) back again to the original link that was clicked.

ie the user will only see the address in this format in their address bar:-

http://example.com/en/category/123/widgets

or

http://example.com/en/category/123/widgets?page=2

g1smd

2:45 pm on Dec 7, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Yep. That's the way it should be done.

It's a topic that comes up every day here, so there are more than 10 000 previous threads with sample code.

You'll need two sets of rules. Both will use a RewriteRule. The redirect will also have a RewriteCond that tests the THE_REQUEST to prevent an infinite redirect-rewrite loop.

The RewriteRule RegEx pattern will match only the requested path (NOT the domain name or query string).

The target of the redirect is a URL with domain name. The target of the rewrite is an INTERNAL PATH, so will NOT specify any domain name.

Escape literal periods in patterns.

As per the forum charter, let's see your code.

tommyb

3:00 pm on Dec 7, 2011 (gmt 0)

10+ Year Member



The original code which I have been trying (which I did post in my first message, although I have appended to it here) is this:

RewriteCond %{QUERY_STRING} ^event=page\.category&languageid=(.*)&categoryid=(.*)&urlAlias=(.*)$ [NC]
RewriteRule ^index\.php$ /%1/category/%2/%3? [NE,R=301,L]

RewriteCond %{QUERY_STRING} ^event=page\.category&languageid=(.*)&categoryid=(.*)&urlAlias=(.*)&pageNumber=([0-9]+)$ [NC]
RewriteRule ^index\.php$ /%1/category/%2/%3?page=%4 [NE,R=301,L]

RewriteRule ^(.*)/category/([0-9]+)/(.+) index.php?event=page.category&languageid=$1&categoryid=$2&urlAlias=$3
RewriteCond %{QUERY_STRING} page=(.*)
RewriteRule ^(.*)/category/([0-9]+)/(.+)$ index.php?event=page.category&languageid=$1&categoryid=$2&urlAlias=$3&pageNumber=%1 [NE,R=301,L]

However, this works fine for the urls/links with no query string (ie http://example.com/en/category/123/widgets) but throws the following error if a query string is present:

You don't have permission to access /C:/dev/example/wwwroot/index.php on this server.

However, as I stated above the rewrite is partly occurring because the url in the address bar is changing to:

http://example.com/C:/dev/example/wwwroot/index.php?event=page.category&languageid=en&categoryid=123&urlAlias=widgets&pageNumber=2

Obviously this is going to make an error and it is this part that I am stuck on.

tommyb

5:45 pm on Dec 7, 2011 (gmt 0)

10+ Year Member



OK, thanks for your pointers, g1smd. I will persevere.

Bets regards,
Tom

g1smd

6:11 pm on Dec 7, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



For a rewrite, the address bar should NOT change. That's the whole point. You ask for "simple URL" and the server fetches content from "complex filepath" without revealing what that location is. URLs and filepaths are not at all the same thing. URLs are used only "out there" on the web. Filepaths are used only "here" inside the server.

The redirects should include the domain name in the target.

Rewrites must NOT include the domain name.

The R flag makes the rule into a redirect. You'll also need the L flag.

If you need a rewrite, use only the [L] flag.

Don't use (.*) at the beginning of a pattern or in the middle. There are literally thousands of posts about that here.

lucy24

10:54 pm on Dec 7, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



this works fine for the urls/links with no query string (ie http://example.com/en/category/123/widgets) but throws the following error if a query string is present:

You don't have permission to access /C:/dev/example/wwwroot/index.php on this server.

Based on your example, the only Rule that will execute if you don't have a query string is also the only one that has no flag and is not a redirect. It's easy to overlook this detail if you don't include an empty line after each Rule.

All the others seem to be confused about whether you are testing this stuff on the actual site or on your personal HD (the C:/ element). You can only test htaccess locally if you've got a pseudo-server (MAMP, WAMP etc.) installed.

mememax

11:44 am on Dec 8, 2011 (gmt 0)

10+ Year Member



What can we use instead of (.*) or (.+) at the beginning of a redirect? Can you put a link to one of those threads please? I can't find them due to the * being a wildcard.

lucy24

12:48 pm on Dec 8, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Always constrain your search as narrowly as possible. For example to pull up one directory name:

[a-zA-Z0-9_-]+
(listing all characters that can occur in a name)

or even better
[^/]+
This form is optimal in mod_rewrite because / is the one character than can never, ever occur within a name. The code itself of course takes up less room (5 bytes vs. 14) and the server knows exactly what it is and isn't looking for.

Two directories:
([^/]+/[^/]+)
and similarly any time you know exactly how many directories will be in your pattern.

But in your original post you weren't looking at any old text, you had the specific case of
en/category/123/widgets

If any part of that is a literal string-- that is, the directory name really is "category"-- use it in your pattern. If there is only a small number of possibilities, use them:
^([a-z][a-z])/category/([0-9]+)/(widgets|foobars|gizmos)

The underlying idea is to let the server find out as soon as possible if the request does not match the pattern, so it can stop right then and there and proceed to the next Rule without even bothering with the Condition.

If the first directory name is not exactly two letters: Stop.

If the second name is not the exact word "category": Stop.

If the third name is not a group of numbers: Stop.

If the fourth name is not one of the listed exact words: Stop.

Only if you have gotten this far do you even spend the extra nanoseconds to evaluate the Condition.

If the Condition involves looking at one specific item in the query string, same principle. Most generically,

itemname=([^&]+)
again excluding the one character that cannot occur within a query.

If you know what kind of value to look for, then it's
itemname=([0-9])

or
itemname=(ab[0-9]{1,3}pdq)
or whatever the pattern is.

mememax

3:06 pm on Dec 8, 2011 (gmt 0)

10+ Year Member



Great this was really good material... The most specific the best. Thanks both lucy & g1smd!

tommyb

3:30 pm on Dec 8, 2011 (gmt 0)

10+ Year Member



Yes, thanks to you both for your help here.

Regarding my problem I am going to have to put aside a day and really try to get stuck into it.

Best regards,

Tom