Forum Moderators: phranque

Message Too Old, No Replies

mod_rewrite with 3 backreferences?

Is this possible to do?

         

Trisha

8:47 pm on Jul 16, 2004 (gmt 0)

10+ Year Member



I've been wanting to post this question for a while now, and even had it all written up once, but chickened out because I didn't think I was explaining what I was trying to do very well. I'm still not sure if this is very clear, but here goes:

I know how to do a basic mod-rewrite like this:


RewriteRule ^(.*)shp/stuff/detail-nm(.*)$ $1shp/stuff/detail-nm.php?thing=$2

to make:
ttp://www.mydomain.com/shp/stuff/detail-nm.php?thing=$var1[abc]

into:

ttp://www.mydomain.com/shp/stuff/detail-nm/$var1[abc]


but can it be done with 3 back references and two variables in the original url?

In other words can I change:


ttp://www.mydomain.com/shp/stuff/detail-nm.php?name=$simplifiedname&thing=$var1[abc]

into:
ttp://www.mydomain.com/shp/stuff/$simplifiedname/$var1[abc]


I'd like to have both $simplifiedname and $var1[abc] in the url, and if possible to get rid of detail-nm.

I tried to figure it out following this outline:

RewriteRule currentURL rewrittenURL

I have no idea how to do the currentURL part with the asterisks, I've only previously done modrewrite with 2 back references and 1 variable in the original url, like my first example above.

The best I can come up with for the rewritten url is:

$1shp/stuff/$2$simplifiedname&thing=/$3

but I don't really think that is right either, I especially don't know where to work in the last / that should come between the variable $simplifiedname and $var1[abc]

My best guess at the whole thing (but not correct)

RewriteRule ^(.*)shp/stuff/(.*)$ $1shp/stuff/$2$simplifiedname&thing=/$3If

Any ideas? Or would this require a really complex rewrite rule?

jdMorgan

9:09 pm on Jul 16, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Trisha,

You can use up to nine RewriteRule pattern back-references, and an additional nine back references to the pattern in a preceding RewriteCond.

However, you'll need to define the value for the $3 back-reference. $1 "copies" the value of the expression that matches in the first set of parentheses in the requested URL, $2 copies the value in the second set of parentheses, and $3 will take the value of the third set of parentheses -- but there isn't a third set in your pattern.

To simplify this problem, break it into two pieces: First, the rewriting problem, of using pieces of the original URL to build the new one, and second, the pattern-matching problem using regular expressions.

Apache mod_rewrite documentation [httpd.apache.org]
Apache URL Rewriting Guide [httpd.apache.org]
Regular Expressions Tutorial [etext.lib.virginia.edu]

It isn't clear which pieces of your URL are fixed and which are variable, so I can't presently help any further in rewriting them to the correct script call. However, your problem appears to be easily-solvable.

Jim

Trisha

9:47 pm on Jul 16, 2004 (gmt 0)

10+ Year Member



Is it as simple as:

RewriteRule ^(.*)shp/stuff/(.*)/(.*)$ $1shp/stuff/detail-nm.php?name=$2&thing=/$3

Do I really need to use any regular expressions? (They're still a bit beyond me) Or does the second (.*) need to be replaced by some regular expression to indicate any characters?

As far as what is fixed and what isn't:

shp and stuff are directories, and are fixed
detail-nm.php is a file which is fixed

$var1[abc] is a php variable that I'll need to send to the next page (detail-nm.php)to use to further pull stuff out of the database.

$simplifiedname is a variable that will be defined on the page before detail-nm.php. Since I don't need to use it for anything again - I just want it to use in the url for seo purposes - I wonder now if I really need the 'name=' part?

Couldn't I just write it as:

RewriteRule ^(.*)shp/stuff/(.*)/(.*)$ $1shp/stuff/detail-nm.php?$2&thing=/$3

Where the original url would instead be:
ttp://www.mydomain.com/shp/stuff/detail-nm.php?$simplifiedname&thing=$var1[abc]

jdMorgan

10:42 pm on Jul 16, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



> Do I really need to use any regular expressions? (They're still a bit beyond me) Or does the second (.*) need to be replaced by some regular expression to indicate any characters?

".*" is a regular expression, and means, "match any number of any characters." You should avoid using it, because it is a "greedy" operator. That is, it will match as many characters as possible, causing inefficient operation, and occasionally, unexpected results.

> I wonder now if I really need the 'name=' part?

That's really dependent upon your php code.

As far as I can tell, you only have two variables in the requested "simplified" URL. Taking that into account, and using more-efficient regular-expressions patterns yields:


RewriteRule ^shp/stuff/([^/]+)/([^/]+)/?$ /shp/stuff/detail-nm.php?name=$1&thing=$2

The first pattern "[^/]+" will match one or more characters, up to but not including the first slash. Whatever characters match that pattern will be saved as back-reference $1.
The second pattern "[^/]+", will match one or more characters following that first slash, up to, but not including, another slash. We save that result as $2.
Finally, the user, the user's browser, or the server may append a trailing slash, so provisions are made to allow for it, "/?" but not require it.

You haven't stated whether this is for use in .htaccess or in httpd.conf. For use in httpd.conf, you'll need to add a leading slash to the RewwriteRule Pattern:


RewriteRule [b]^/s[/b]hp/stuff/([^/]+)/([^/]+)/?$ /shp/stuff/detail-nm.php?name=$1&thing=$2

If the code is to be used in .htaccess, then you can improve your site's efficiency by moving this code into .htaccess in the /shp/stuff subdirectory, and changing the code to:

RewriteRule [b]^([/b][^/]+)/([^/]+)/?$ /shp/stuff/detail-nm.php?name=$1&thing=$2

That way, the code will only be executed when requests are made to the /shp/stuff subdirectory, and not for other directories on your site.

Don't hide from regular expressions -- You can't write or debug mod_rewrite code without them. I suggest you analyze the code above, making reference to the tutorial link I posted, and use your familiarity with your own project as leverage to understand what regular expressions are for and how they work. Regular expressions are a powerful pattern-matching "language" used in php, perl, ssi, mod_rewrite, and other Apache modules. Some time spent getting comfortable with them will pay big dividends in your ability to administrate your site.

Have fun!

Jim

Trisha

11:03 pm on Jul 16, 2004 (gmt 0)

10+ Year Member



Thanks! I think I learned a few new things here!

([^/]+) does sound much better!

I didn't know or at least never thought of moving the .htaccess file into a subdirectory. So then I don't need the $1 out in front?

I know I shouldn't hide from regular expressions! I guess I have a sort of regular expression phobia!

I'm going to keep working on this tonight - for as long as I can, and hopefully will be able to figure it out!

jdMorgan

11:21 pm on Jul 16, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



> So then I don't need the $1 out in front?

I don't think so; There is nothing there to copy into the substitution URL. The part of the URL "visible" to a RewriteRule is only the local URL-path. So if a browser requests "www.example.com/foo.html", only "foo.html" is available to a RewriteRule in .htaccess. If you place a RewriteRule into .htaccess in a subdirectory, then the name of that subdirectory gets stripped off, and is no longer available to the RewriteRule. That's why I removed in in the code intended for use in /shp/stuff.

You can put that code into the subdirectory for better execution efficiency, or keep it in your Web root directory for easier central administration -- It's a trade-off. If your site gets 10,000 hits a day, put the code in the subdirectory. If not, it's a matter of preference.

Jim

Trisha

7:49 pm on Jul 19, 2004 (gmt 0)

10+ Year Member



I had to work on some php to get the variables set up right before I could really test the rewrite.

Turns out I did need one extra variable than I had originally thought.

What I need to do is change:

shp/stuff/detail-nm.php?$vara&varb&thing=$var1[abc]

into:

shp/stuff/vara/varb/$var1[abc]

I tried both with $1 in front and not:

^(.*)/shp/stuff/([^/]+)/([^/]+)/([^/]+)/?$ $1shp/stuff/detail-nm.php?$2&$3&thing=$4

I get 404 errors. I have a gut feeling that at this point there is something minor I am missing and I'm not seeing it since my eyes are all glazed over after working on the php part.

jdMorgan

8:18 pm on Jul 19, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



There is a one-to-one correspondence between the parentheses on the left, and the $numbers on the right, so I don't know why you want to start the pattern with "^(.*)"

Try this, and if you get a 404 error, look at your server error logs and see where it goes wrong.
Rewrite shp/stuff/vara/varb/$var1[abc] --> shp/stuff/detail-nm.php?$vara&varb&thing=$var1[abc] :


RewriteRule ^shp/stuff/([^/]+)/([^/]+)/(.+)/?$ /shp/stuff/detail-nm.php?$1&$2&thing=$3 [L]

This code, placed in your Web root directory in .htaccess will do exactly what you asked for. Do not modify it at all. However, there are any number of minor details that can cause problems. Maybe not errors, but situations that can occur that are not handled because you did not describe them. Reviewing the error log will show you what went wrong.

Breaking it down, $1 will contain vara, $2 will contain varb, and $3 will contain var1[abc] if and only if all three are present in the requested URL, are preceded by "shp/stuff/", and are separated by slashes. A trailing slash is allowed, but will be ignored if present.

If it doesn't work and you cannot review the error logs, then turn this rewrite (temporarily) into an external redirect. That way, you will see the "wrong" rewritten URL in your browser address bar:


RewriteRule ^shp/stuff/([^/]+)/([^/]+)/(.+)/?$ [b]http:[/b][b]//www.example.com[/b]/shp/stuff/detail-nm.php?$1&$2&thing=$3 [[b]R=301,[/b]L]

You don't want to use this external redirect version for the long term, because it defeats your purpose, but it is a good debugging aid to help you get all the hats, slashes, and dollars (^/$) right.

Jim

Trisha

3:10 am on Jul 20, 2004 (gmt 0)

10+ Year Member



Thanks Jim! I finally got it working! It took a little while though, because I had made a couple stupid mistakes that it took me a while to catch.

I will spend some time reading more about regular expressions and mod-rewrite though, I'm sure anything I learn will be useful someday.