0

I am attempting to redirect a URL in a very common method, however, I can not figure this out. I have read article after article and can not make any progress. I am simply trying to have a URL such as 'domain.com/xx/xxxxxxxxxx' redirect in php to '/index.php?first=xx&last=xxxxxxxxxx'. I have attempted several apache mod_rewrites and can get the URL to remain as desired in the browser, but when I look at $_SERVER['REQUEST_URI'] in index.php, it is not showing up as desired. Instead it is showing the URI that was entered instead of the rewrite. It is also always adding the 'xx' portion of the URL. So for example:

URL: domain.com/ab/1234567890
PHP: ab/1234567890
     ab/include/file.css
     ab/include/another.css

Getting: $_SERVER['REQUEST_URI'] = domain.com/ab/1234567890
Desired: $_SERVER['REQUEST_URI'] = domain.com/index.php?first=ab&last=1234567890

There is no 'ab' directory, and it should be looking for files like 'include/file.css', etc.

Here are some of the redirects I've tried:

 RewriteRule ^([a-zA-Z0-9/]+)$ index.php?first=$1

 RewriteCond %{QUERY_STRING} /([a-z][a-z])/([a-zA-Z0-9]+)
 RewriteRule ^/([a-z][a-z])/([a-zA-Z0-9]+)$ index.php?first=$1&last=$2 [L]

 RewriteCond   %{QUERY_STRING}           ^[a-z][a-z]/[a-zA-Z0-9]$
 RewriteRule   ^[a-z][a-z]/[a-zA-Z0-9]+$         index.php      [L,R=301]

I have tried many others and nothing I try seems to work. Perhaps it is because I am just unfamiliar with apache redirects and how this interacts with PHP. I am good at PHP, just not apache, therefore it may be a situation where I just don't know the terms to look for...

Any help would greatly be appreacited!

UPDATE

My current apache config is:

RewriteEngine On
RewriteRule ^[a-z][a-z]/([a-z/]+.css)$ $1   [L]
RewriteRule ([a-z][a-z])/([a-zA-Z0-9]+) index.php?first=$1&second=$2    [L]

I have tried switching orders, but that doesn't seem to make any difference. If I check the $_SERVER['QUERY_STRING'] variable value in PHP, it is indeed formatting it correctly for the original URL in the browser:

Browser: domain.com/ab/0123456789
$_SERVER['QUERY_STRING']: first=ab&second=0123456789

However, for all the external files that the page is requesting, those are not being redirected correctly and the PHP script is outputting the wrong values:

Browser: domain.com/ab/include/style.css
$_SERVER['QUERY_STRING']: first=ab&second=include

This should be reporting as:

$_SERVER['QUERY_STRING']: include/style.css

It appears that the first RewriteRule is not getting selected for some reason for the css files. This is also happening with js files (obviously because no rule has been set for them yet).

It also makes no difference if I use relative paths or hard paths...

RESOLUTION

After continued effort getting the apache redirects working, I had to add a specific line for each external source location (no clue why the original RegEx statement from 'Dont Panic' didn't work). Here is what my .htaccess file looks like now:

# these are for the external file requests
RewriteRule [a-z][a-z]/images/([a-zA-Z0-9_\.]+)$ /images/$1 [L]
RewriteRule [a-z][a-z]/styles/([a-zA-Z0-9_\.]+)$ /styles/$1 [L]

# these are for the main request for the bootstrap php file
RewriteBase /  
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ([a-z][a-z])/([a-zA-Z0-9]+) index.php?first=$1&second=$2 [L]

Also of note: if you have any external files that are not created in this example (e.g. styles/non_existent.css), the last 'RewriteRule' above will execute and basically run the index.php file causing errors for your site. So make sure that you create (or remove references to) external files - even if they are blank!!!

Thanks for all your help 'Dont Panic'!

user1646428
  • 179
  • 2
  • 12
  • Does this answer your question? [Reference: mod\_rewrite, URL rewriting and "pretty links" explained](https://stackoverflow.com/questions/20563772/reference-mod-rewrite-url-rewriting-and-pretty-links-explained) – ArSeN Dec 20 '20 at 02:38
  • Looks like you've modified the first rewrite rule I provided, and it will now also match your CSS, which is potentially a problem. Not clear why you've modified it, `1234567890` does not include upper or lower case letters so there's no need for them in the regex? RE: `Browser: domain.com/ab/include/style.css` - what does this mean? You are typing that value in to the address bar? `$_SERVER['QUERY_STRING']: first=ab&second=include` - how are you seeing `$_SERVER` values for a request to a CSS file? – Don't Panic Dec 21 '20 at 18:46
  • The 0123456789 is just an example value. In real life the value can be a-zA-Z0-9 as I've implemented. It is just a regex match. It does not match the '/' character meaning it will not match subdirectories, and is the second rule making it the last one to compare against. It also does not match the '.' character meaning it will not match files because they will have a file extension which includes a '.'. The 'Browser:' request you are asking about is what file the browser is requesting. – user1646428 Dec 21 '20 at 19:52
  • To see what files are being requested by the server, the index.php file is just outputting the $_SERVER['REQUEST_URI'] and the $_SERVER['QUERY_STRING'] values to a text file. That way I can see what requests are coming in. Every additional request besides the original is all the external files that are being requested via the HTML. – user1646428 Dec 21 '20 at 19:55
  • It has been hard to read between the lines about what you are trying to do, and what you are actually doing, and it is not getting easier :-) It sounds like you have now modified the CSS redirect I suggested to actually be handled by `index.php`, so that you can see `$_SERVER` variables? I am not sure the purpose of that, but I would suggest forgetting about `$_SERVER` for now. Look at the requests your browser is making in dev tools. The rules in my answer work in a clean Apache 2 container, and match what I understood from your question, though it is not at all clear I understood correctly. – Don't Panic Dec 22 '20 at 09:38
  • No reason to read between the lines. :) The OP was clear as to what I am trying to accomplish. You solved the first issue by pointing me to the QUERY_STRING variable instead of the REQUEST_URI. The only issue I have remaining from the OP is the redirection of the external files (e.g. *.css and *.js) that are part of the site itself. I have tried the apache redirects given, but they are not working. I am still tinkering and think I have resolved all issues. I will update the post and select your answer as correct (since it helped me get the actual answer) in a few. Thanks for your help though! – user1646428 Dec 22 '20 at 17:07

2 Answers2

1

As I understand it, these are your requirements:

  • You want to leave the originally requested URL in the browser, ie not an external, visible-to-the-visitor 301-type redirect. In other words, map the URL in the browser to something else on the filesystem, transparently.

  • The incoming request includes 2 segments which can be matched with regular expressions;

  • You want to be able to access those 2 directory elements of the request as PHP parameters;

An Apache internal redirect will do this. The first example on the mod_rewrite examples page in the Apache docs describes this (though you probably don't need the [PT] flag used there, which allows further handling of the mapped URI). I think the following should do what you need:

RewriteEngine on
RewriteRule ([a-z][a-z])/([0-9]+) index.php?first=$1&last=$2 [L]

This will handle an incoming request like domain.com/ab/1234567890, and map it - transparently, invisibly - to index.php?first=ab&last=1234567890. The visitor does not see any redirect, only the original URL in their browser. You can still access the different elements of both the external request and the internal handling of it through $_SERVER:

...
[QUERY_STRING] => first=ab&last=1234567890
[REQUEST_URI] => /ab/1234567890
[SCRIPT_NAME] => /index.php
[PHP_SELF] => /index.php
...
[argv] => Array
    (
        [0] => first=ab&last=1234567890
    )

So for example you can use $_GET['first'] in your code to find ab.

UPDATE

To answer extra questions added in the comments - to reference your CSS/JS from index.php, the simplest and most efficient option would be to use absolute references:

<link href="/css/some.css" rel="stylesheet">

If you can't do that, and instead want relative links to work, you could try another internal remap. Note that an external redirect (like you've shown in the comments) with [R=301] will be slower, as it is really is a whole new request and response.

Assuming you have CSS files like include/file.css, where the include/ directory is in the same directory as index.php, then a relative CSS reference in index.php like:

<link href="include/some.css" rel="stylesheet">

will - with the first redirect rule above in place - actually generate a request for ab/include/some.css. To remap that to your real file, the following internal redirect rule works:

RewriteRule ^[a-z][a-z]/([a-z/]+.css)$ $1 [L]

Note that you need to be careful now that the rules don't overlap or interfere with each other, so I've added [L] to both, and also added some anchors to the CSS regex.

Don't Panic
  • 13,965
  • 5
  • 32
  • 51
  • So it looks like I was using the wrong variable in PHP ('QUERY_STRING' instead of 'REQUEST_URI') - the latter still shows the original request. But the subsequent file requests for things like external css files and js files is still being prefixed with the 'ab' (in your example above) instead of the root. How do I fix that? – user1646428 Dec 20 '20 at 17:17
  • Sounds like you are using relative references? So use absolute, like ``? – Don't Panic Dec 20 '20 at 17:48
  • I am using relative references. There is no way to perform this task in apache? I tried using "RewriteRule [a-z][a-z]/([a-zA-Z0-9]+\.[a-zA-Z0-9]+)$ $1 [R=301]", but that didn't fix anything. – user1646428 Dec 21 '20 at 00:58
  • So I have tried using the absolute links in the HTML as well as the additional redirect (with and without the absolute links) and the site does not work at all. The external js and css files are not loading. I will update my OP to reflect changes... – user1646428 Dec 21 '20 at 16:35
  • Sounds like something else is in play in your config. The rules I've provided work - I set them up in a fresh Apache 2 Docker container, and tested them extensively. I'd suggest commenting everything out and iteratively testing things. If absolute links to your real files (which don't match your redirect rules) aren't working, clearly there's either something wrong, or something else is involved, like another `.htaccess` or redirect or Apache alias or .... – Don't Panic Dec 21 '20 at 18:52
  • Apache will only read one .htaccess file in the served directory. There are no other rules in that file aside from the two I've posted. I've tried changing their order - which has had no effect. I do agree that something is wrong. I just can't figure out what it is... – user1646428 Dec 21 '20 at 19:58
  • Just as a test, I changed the RewriteRule to be "RewriteRule ^[a-z][a-z]/([a-z/]+.css)$ index2.php/$1" and created a symlink to index.php. I never see the 'index1.php' come up in any $_SERVER values. It does not appear that the rule is being executed. – user1646428 Dec 21 '20 at 20:09
  • It almost looks like it is sending the requests for the external files (e.g. style.css) to the index.php script for processing... – user1646428 Dec 21 '20 at 20:39
-1

Url will always change once page changes. Ways to circumvent this is by using javascript and load url content in a div or using iframe in html to display the target page.

brown.cn
  • 151
  • 1
  • 9
  • An [Apache internal redirect](https://httpd.apache.org/docs/2.4/rewrite/remapping.html) will remap an incoming request to a different request, without changing the URL. – Don't Panic Dec 20 '20 at 09:03