Forum Moderators: phranque
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]
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]
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
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!
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