Basj
Basj

Reputation: 46463

How to use RewriteRule such that $_SERVER['REQUEST_URI'] is modified too for PHP?

With this .htaccess:

RewriteEngine On
RewriteRule foo/(.*) /foo-$1         # here I tried [L], [PT], [C], etc.
RewriteRule . index.php [L]

I've tried all possible flags for the first RewriteRule, but always, this PHP code:

<?php echo $_SERVER['REQUEST_URI']; ?>

always echoes /foo/bar instead of /foo-bar, when accessing http://example.com/foo/bar. Why?

How to have Apache's RewriteEngine also modify the REQUEST_URI that will be seen by PHP?

Note: I don't want [R] because a redirection would generate a new browser request, and change the URL displayed in the URL bar, which I don't want.

See also RewriteRule when the substitution string is not a file path but an URL which should be processed by next rules.

Upvotes: 4

Views: 2025

Answers (3)

JMP
JMP

Reputation: 4467

PHP's $_SERVER['REQUEST_URI'] returns the Apache original-uri and not current-uri.

CGIVar Directive

With this .htaccess file:

CGIVar REQUEST_URI current-uri
RewriteRule (.*) index.php [L]

then a request to example.com/hello/world will give:

$_SERVER["REQUEST_URI"]  "/index.php"
$_SERVER["REDIRECT_URL"] "/hello/world" 

Without the CGIVar line, it would give "/hello/world" for both REQUEST_URI and REDIRECT_URL.

Upvotes: 1

Solonl
Solonl

Reputation: 2512

I think what you try to do is impossible without some work around. I have provided 2 solutions in this post, one using auto_prepend_file and one using mod_proxy.

Solution 1: using auto_prepend_file

Please look at the script below, this does not directly set the REQUEST_URI global, but instead it overwrites it in PHP, with the following code:

.htaccess

php_value auto_prepend_file "before.php" 

RewriteEngine On
RewriteRule foo/(.*) /foo-$1
RewriteRule . index.php [L]

Make sure to add this line:

php_value auto_prepend_file "before.php" 

before.php

In this script you can replace the REQUEST_URI:

Like:

$_SERVER['REQUEST_URI'] = "/" . str_replace('/', '-', ltrim($_SERVER['REQUEST_URI'], "/"));

You can further improve this script, but I think the concept is clear.

index.php

Index.php is unaffected but contains the rewritten rule:

var_dump($_SERVER['REQUEST_URI']); //string(7) "/foo-bar"

A request to http://localhost/foo/bar?test is now: string(13) "/foo-bar?test"

Update

When using [L], you can obtain the rewritten url by:

var_dump($_SERVER['REDIRECT_URL']); # /foo-bar

So the .htaccess becomes:

php_value auto_prepend_file "before.php" 

RewriteEngine On
RewriteRule foo/(.*) /foo-$1 [L] # please note [L] here
RewriteRule . index.php [L]

Thus the before.php can be replaced by:

$_SERVER['REQUEST_URI'] = $_SERVER['REDIRECT_URL'];

Update solution 2; using mod_proxy

Found out you can also use mod proxy:

I had to enable the following modules:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so

Now your .htaccess is changed to (notice the [P] flag):

RewriteEngine On
RewriteRule ^foo/(.+)$ /foo-$1 [L,P]
RewriteRule . index.php 

This will proxy all foo/bar requests to /foo-bar and change the $_SERVER['REQUEST_URI'] accordingly.

var_dump($_SERVER['REQUEST_URI']); //output: string(8) "/foo-bar"

I think using the PHP prepend file is a more efficient way though.

Upvotes: 3

Basj
Basj

Reputation: 46463

After further research, it seems that PHP will always see the original URL in $_SERVER['REQUEST_URI'] and not the target of the RewriteRule. (authoritative source needed here).

By the way, the target of a RewriteRule is usually a file that will process the request, except if we use a [R] redirection flag, then in this case the browser will do a new request to the new URL (and the browser URL bar changes).

Upvotes: 0

Related Questions