Forum Moderators: phranque

Message Too Old, No Replies

Unable to handle multiple variables dynamically

         

sirkris

11:05 pm on Apr 16, 2007 (gmt 0)

10+ Year Member



Hi,

I have a client who wants me to configure an Apache webserver to parse the GET variables in a script I wrote for them. Here's an example of what the URL looks like raw:

/citystate.php?city=Olympia&state=Washington&category=sunroom

The goal is to make it so you can type that URL as follows:

/citystate/city/Olympia/state/Washington/category/sunroom

Here is the rewrite rule I created to accomplish this goal:

Options +FollowSymLinks
RewriteEngine on
RewriteRule citystate/(.*)/(.*)/(.*)/(.*)/(.*)/(.*)/$/citystate.php?$1=$2&$3=$4&$5=$6

Now here's the problem. It directs to citystate.php just fine, but none of the GET variables seem to be getting passed! In other words, if I point the browser to "example.com/citystate/var1/val1/var2/val2/var3/val3/", it will take me to citystate.php just fine, but everything after the "citystate/" in the rewriterule seems to be completely ignored!

Here's the PHP code I'm using to verify this:

<?php

print_r( $_GET );
print "<br />";
print_r( $_SERVER );

Here's what it outputs to the browser for the example given above:

Array ( )
Array ( [COMSPEC] => C:\WINNT\system32\cmd.exe [DOCUMENT_ROOT] => c:/program files/apache/apache/htdocs [HTTP_ACCEPT] => text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 [HTTP_ACCEPT_CHARSET] => ISO-8859-1,utf-8;q=0.7,*;q=0.7 [HTTP_ACCEPT_ENCODING] => gzip,deflate [HTTP_ACCEPT_LANGUAGE] => en-us,en;q=0.5 [HTTP_CONNECTION] => keep-alive [HTTP_HOST] => kcwork.example.com [HTTP_KEEP_ALIVE] => 300 [HTTP_USER_AGENT] => Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6 [PATH] => C:\WINNT\system32;C:\WINNT;C:\WINNT\System32\Wbem;C:\PROGRA~1\ULTRAE~1;C:\Program Files\Common Files\Adobe\AGL;C:\Program Files\MySQL\MySQL Server 4.1\bin;C:\Program Files\ATI Technologies\ATI.ACE\ [REMOTE_ADDR] => 192.168.0.18 [REMOTE_PORT] => 3313 [SCRIPT_FILENAME] => c:/program files/apache/apache/htdocs/citystate.php [SERVER_ADDR] => 192.168.0.18 [SERVER_ADMIN] => krisc@example.net [SERVER_NAME] => kcwork.example.com [SERVER_PORT] => 80 [SERVER_SIGNATURE] =>
Apache/1.3.27 Server at kcwork.example.com Port 80
[SERVER_SOFTWARE] => Apache/1.3.27 (Win32) PHP/4.4.2 [SystemRoot] => C:\WINNT [WINDIR] => C:\WINNT [GATEWAY_INTERFACE] => CGI/1.1 [SERVER_PROTOCOL] => HTTP/1.1 [REQUEST_METHOD] => GET [QUERY_STRING] => [REQUEST_URI] => /citystate/var1/val1/var2/val2/var3/val3/ [SCRIPT_NAME] => /citystate [PATH_INFO] => /var1/val1/var2/val2/var3/val3/ [PATH_TRANSLATED] => c:\program files\apache\apache\htdocs\var1\val1\var2\val2\var3\val3\ [PHP_SELF] => /citystate/var1/val1/var2/val2/var3/val3/ )

Notice at the top, you see "Array()" all by itself? That represents a completely empty set of GET variables being passed to the PHP script by the webserver. Here's what it *should* look like:

Array ( [var1] => val1 [var2] => val2 [var3] => val3 )
Array ( [COMSPEC] => C:\WINNT\system32\cmd.exe [DOCUMENT_ROOT] => c:/program files/apache/apache/htdocs [HTTP_ACCEPT] => text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 [HTTP_ACCEPT_CHARSET] => ISO-8859-1,utf-8;q=0.7,*;q=0.7 [HTTP_ACCEPT_ENCODING] => gzip,deflate [HTTP_ACCEPT_LANGUAGE] => en-us,en;q=0.5 [HTTP_CONNECTION] => keep-alive [HTTP_HOST] => kcwork.example.com [HTTP_KEEP_ALIVE] => 300 [HTTP_USER_AGENT] => Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6 [PATH] => C:\WINNT\system32;C:\WINNT;C:\WINNT\System32\Wbem;C:\PROGRA~1\ULTRAE~1;C:\Program Files\Common Files\Adobe\AGL;C:\Program Files\MySQL\MySQL Server 4.1\bin;C:\Program Files\ATI Technologies\ATI.ACE\ [REMOTE_ADDR] => 192.168.0.18 [REMOTE_PORT] => 3313 [SCRIPT_FILENAME] => c:/program files/apache/apache/htdocs/citystate.php [SERVER_ADDR] => 192.168.0.18 [SERVER_ADMIN] => krisc@example.net [SERVER_NAME] => kcwork.example.com [SERVER_PORT] => 80 [SERVER_SIGNATURE] =>
Apache/1.3.27 Server at kcwork.example.com Port 80
[SERVER_SOFTWARE] => Apache/1.3.27 (Win32) PHP/4.4.2 [SystemRoot] => C:\WINNT [WINDIR] => C:\WINNT [GATEWAY_INTERFACE] => CGI/1.1 [SERVER_PROTOCOL] => HTTP/1.1 [REQUEST_METHOD] => GET [QUERY_STRING] => [REQUEST_URI] => /citystate/var1/val1/var2/val2/var3/val3/ [SCRIPT_NAME] => /citystate [PATH_INFO] => /var1/val1/var2/val2/var3/val3/ [PATH_TRANSLATED] => c:\program files\apache\apache\htdocs\var1\val1\var2\val2\var3\val3\ [PHP_SELF] => /citystate/var1/val1/var2/val2/var3/val3/ )

I can't figure out for the life of me what's wrong with my rewrite syntax! The client was very specific in his requirements, so the premise of what I'm trying to do cannot be changed (i.e. responses like "Why don't you just change the directory name to...." or etc won't be helpful).

I'm on a tight deadline as it is, and this could totally sink me if I don't get it figured out soon. Thank you so much for any help you can provide! =)

--Kris

[edited by: jdMorgan at 11:34 pm (utc) on April 16, 2007]
[edit reason] Example.com, please see TOS. [/edit]

jdMorgan

11:47 pm on Apr 16, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Nothing totally obvious here.

Do you have other rules which are similar but shorter - omitting some of the parameters?

If so, then the rule order and/or the greedy and promiscuous ".*" pattern may be your problem -- It is very inefficient, to say the least.

To solve the problem, use a specific pattern -- "([^/]+)/" -- That is, "Match one or more characters not equal to a slash, followed by a slash."

I also strongly suggest that you always use the [L] flag on every rule, unless you have a good reason not to.

Optimized rule for .htaccess:


RewriteRule ^citystate/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/$ /citystate.php?$1=$2&$3=$4&$5=$6 [L]

Also, we need to be sure that the "citystate/" URL-path-pattern and the "citystate.php" substitution-path in the posted rule are accurate examples. If not, it leaves me wondering if you may have allowed citystate.php to be rewritten to itself. This would also result in 'lost' variables.

Finally, it seems from your posted EnVar dumps that you may have AcceptPathInfo [httpd.apache.org] enabled, although this is in conflict with your reported server version. If this is the case, then the server may simply pass the request straight to the script without applying the RewriteRule. It's sort of an either-or thing: Either you rewrite the static URL to the dynamic form with query parameters (as you are trying to do), or you use AcceptPathInfo, with the only rewrite required being from "citystate/<anything>" to citystate.php. The citystate.php script would then get the variables from the PATH_INFO variable, instead of from a faked-up query string. Anyway, pick one method or the other, and if you choose to use the 'full' mod_rewrite-query-string method, AND if no other scripts depend on it, then disable AcceptPathInfo.

I should note that the rewrite-to-query-string method is an "older way" of doing things; Pre-Apache 2.x, it was the only way. Apache 2.x added the AcceptPathInfo method.

Jim

jd01

12:13 am on Apr 17, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I think this is similar to what jdMorgan is suggesting:

RewriteRule ^citystate/ /citystate.php [L]

<?php

$vars=explode("/",$_SERVER['REQUEST_URI']);
$$vars[1]=$vars[2];
$$vars[3]=$vars[4];
$$vars[5]=$vars[6];

?>

Should give you a variable variable "$vars" for variable naming, with the value of the named variable being "next" in the exploded array.

Justin

Added:
Welcome to WebmasterWorld!

sirkris

6:15 pm on Apr 17, 2007 (gmt 0)

10+ Year Member



Hey thanks guys! I figured out the problem.

I used jdMorgan's cleanup for starters, but by itself it didn't change anything. My Apache server is 1.3.x so the AcceptPathInfo directive doesn't apply here.

I'm not quite sure what you meant when you said "Also, we need to be sure that the "citystate/" URL-path-pattern and the "citystate.php" substitution-path in the posted rule are accurate examples. If not, it leaves me wondering if you may have allowed citystate.php to be rewritten to itself. This would also result in 'lost' variables."

But that did give me an idea! I changed the rewrite rule so that the directory name would be different than the script name. I.e. I changed it from "citystate/" to "contractors/", and that fixed it!

So apparently, the lesson here is that, if you create a rewrite rule to pass GET variables to a script, make sure the imaginary directory in the RewriteRule is of a different name! Even though the file had a ".php" extension and the rewrite rule didn't, apparently it was still close enough to throw it off.

Thanks again for the help! =)

--Kris

jdMorgan

6:52 pm on Apr 17, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



It's possible that Content-Negotiation may be involved here. If you don't use it, try adding

Options -MultiViews

to the beginning of your .htaccess file. That should allow you to have the directory and script name the same, as long as the script ends with ".php", of course.

Jim