Avatar of Vipin Kumar
Vipin Kumar
Flag for India asked on

Redirect and Rewrite URL using .htaccess

Hi,

I want to redirect and then rewrite my URL (internal forwarding) so that it doesn't show the php extension as well it doesn't show the ?, = and & in the URL.

This is the example of what I want to achieve, my actual URL passed to header is http://localhost/portal/error.php?error=runtime-error which I want to show in the address bar http://localhost/portal/error.php/error/runtime-error and internally this URL is forwarded to the actual URL http://localhost/portal/error.php?error=runtime-error.

Also, what I want to achieve is here is single redirect and single rewrite rule(for internal forwarding) which applies to all the scripts instead of adding individual redirect and rewrite rules for each script page.

Below is the code that is present in my .htaccess file.
ErrorDocument 404 /portal/error.php
ErrorDocument 500 /portal/error.php

RewriteEngine On
RewriteBase /
RewriteRule ^include/(.*)$ /portal/error.php [L,R=404]

Open in new window


Kindly let me know if any more information is required.

Thanks in advance
PHPApache Web ServerHTTP Protocol

Avatar of undefined
Last Comment
Vipin Kumar

8/22/2022 - Mon
gr8gonzo

Haven't tested this, but it'd probably be something like:

RewriteRule ^(.*error.php)\?error=(.*)$ $1/error/$2 [R=301,L]
Vipin Kumar

ASKER
@gr8gonzo,

That is not working. As far as my knowledge I would be requiring two rewrite rules one for redirecting so that the browser address bar shows the clean URL i.e. http://localhost/portal/error.php/error/runtime-error and other rule to rewrite the clean URL and it becomes  http://localhost/portal/error.php?error=runtime-error
Terry Woods

Hmm, perhaps this would work. I'm assuming the "portal" and "runtime-error" parts of the URL are variable.

RewriteCond %{QUERY_STRING} error=([^&]+)
RewriteRule ^(.*/error.php)$ $1/error/%1? [R=302,L]  # test with a 302 to avoid caching until it's confirmed as working
RewriteRule ^(.*/error.php)/error/(.*) $1?error=$2 [R=404,L]

Open in new window

I started with Experts Exchange in 2004 and it's been a mainstay of my professional computing life since. It helped me launch a career as a programmer / Oracle data analyst
William Peck
Vipin Kumar

ASKER
@Terry,

Its not working. The redirection itself is not happening.
gr8gonzo

Hi Vipin,

Sorry, I have been away from my computer and didn't have a way to really test anything. Try these 2 lines instead of the one I sent you:

RewriteCond %{QUERY_STRING} ^error=(.*)$ [NC]
RewriteRule ^.*/error.php /portal/error.php/error/%1 [L,R=301,QSD]
Terry Woods

Vipin, the code you're asking for is reasonably complex and unique. It's a normal part of developing such code to work through multiple suggestions/attempts and track down problems in order to get it working. It's hard for us to do that without access to your server, but you can do it yourself (depending on your level or knowledge), or work with us to do it.

For example, the first part of my suggested code needs to be working before the 2nd part will work (though you could still test the 2nd part by navigating to a URL that matches the pattern it targets), so let's look at the first part:

RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} error=([^&]+) [NC]
RewriteRule ^(.*/error\.php)$ $1/error/%1? [NC,R=302,L]  # test with a 302 to avoid caching until it's confirmed as working

Open in new window


I've added the [NC] flag as done by gr8gonzo to allow mixed case. I also have added a backslash to the literal . character we're wanting to match, otherwise it gets treated as a wildcard (that wouldn't have stopped it working though).

I believe you also still need to use the rewriteengine on and rewritebase directives, in case you hadn't included those.

Can you confirm my assumptions that "portal" and "runtime-error" parts of the URL are variable?

To track down problems, you can simplify the pattern and see if the redirect works. eg this adjusted version should target any url with a query parameter of error=something:

RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} error=([^&]+) [NC]
RewriteRule ^(.*) $1/error/%1? [NC,R=302,L]  # test with a 302 to avoid caching until it's confirmed as working

Open in new window

⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Vipin Kumar

ASKER
@Terry,

I completely agree with you that my request is quite unique, so it may take a bit of time to get an exact solution. It was just that my project is stuck on this and cant proceed ahead until I resolve this.

For your question - Can you confirm my assumptions that "portal" and "runtime-error" parts of the URL are variable? The "portal" is not variable as it is the root directory which contains all my scripts of my project, so you can be sure that "http://localhost/portal/" will always be in the URL on the other hand "runtime-error" is variable as different pages will be displayed on different values of "error=".

Let me give you a brief idea of my code based on which I am testing the htaccess. This is just a small part of my code, but majority of my project will be designed on this principal.

I have a "index.php" which includes a main configuration file (this file is the main file which contains information regarding the starting the session, setting server timezone establishing DB connection etc. This file will be included in all the script files that I create for my project). Below is the code that I use to check the whether the main file exits or not.

So as per my code below, when I access http://localhost/portal/ it checks for main file and currently it doesnot exist so it redirects my page to http://localhost/portal/error.php?error=runtime-error

if(!file_exists('bootstrap.php')){
		header('Location:error.php?error=runtime-error');
		die();
}

Open in new window


I tried you adjusted code, it is displaying the URL in the browser http://localhost/error.php/error/runtime-error which is not the correct, as it is missing the "portal" after the localhost.

I also tried to access the clean URL i.e. http://localhost/portal/error.php/error/runtime-error it gets to the error.php script but doesn't understand the value of the GET variable "error" and doesn't display the appropriate page.

Kindly let me know if any more information is required.

Thanks in advance.
Terry Woods

Tested and working for me. To prevent an infinite loop, an additional query parameter is added by the second rule, and checked for non-existence by the first.

RewriteEngine On
RewriteBase /

RewriteCond %{QUERY_STRING} error=([^&]+) [NC]
RewriteCond %{QUERY_STRING} !redirect=done [NC]
RewriteRule ^(portal/error\.php)$ $1/error/%1? [NC,R=302,L]  # test with a 302 to avoid caching until it's confirmed as working

RewriteRule ^portal/error\.php/error/(.*) /portal/error.php?error=$1&redirect=done [NC,L]

Open in new window

Vipin Kumar

ASKER
@Terry,

I tried it, it is not working, i.e. now it is not even redirecting like it was doing earlier. Also if I access the URL http://localhost/portal/error.php/error/runtime-error it is still not able to understand the value of GET variable "error".

Thanks.
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
gr8gonzo

1. My script gives you the URL you're asking for.

2. If you end up at localhost/potral/error.php/error/runtime-error, then you are not going to get the parameters in your $_GET array because it's no longer a valid query string. You have to write code to parse out the URL at that point. There is no way to avoid that.
Terry Woods

@gr8gonzo, your point 2 is incorrect, and my testing proved so when I ran it. A rewrite rule without a R flag loads a different URL (and in this case with different query params) to the one requested, but without doing a redirect.

With my code, that means the URL localhost/potral/error.php/error/runtime-error actually loads localhost/potral/error.php?error=runtime-error&redirect=done but doesn't show that in the browser as the user hasn't been redirected.
Vipin Kumar

ASKER
@Terry,

Any solution you have for this query of mine.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Terry Woods

Sorry, didn't see your earlier post. Strange, it worked exactly at my end.

To narrow down the problem, I'd suggest commenting out the 2nd rewriterule, and simplifying the pattern for the first rule to try to get a match. eg target all .php requests (only try this if it won't affect anything else for the duration of the test), then try to access http://localhost/portal/error.php?error=runtime-error (it should redirect to http://localhost/portal/error.php/error/runtime-error which will fail to load the page)

RewriteEngine On
RewriteBase /

RewriteCond %{QUERY_STRING} error=([^&]+) [NC]
RewriteCond %{QUERY_STRING} !redirect=done [NC]
RewriteRule (.*\.php)$ $1/error/%1? [NC,R=302,L]  # test with a 302 to avoid caching until it's confirmed as working

#RewriteRule ^portal/error\.php/error/(.*) /portal/error.php?error=$1&redirect=done [NC,L]

Open in new window


If it still doesn't redirect, try commenting out the 2 rewritecond lines too and try again. We need to narrow down the problem.
Vipin Kumar

ASKER
@Terry,

I have tried the code, it works fine and it is redirecting. The error.php script is executing but the script is not able to get the $_GET variable "error" value which is "runtime-error" in current scenario.

Thanks
Terry Woods

Are you able to edit the php script?

If you temporarily insert this as the first line of the file it should cause the script to output what's passed as query parameters and then exit:
<?php die("<pre>".print_r($_GET, true)); ?>

That may help us understand what's happening with the parameters.
Your help has saved me hundreds of hours of internet surfing.
fblack61
Vipin Kumar

ASKER
@Terry,

When I add the <?php die("<pre>".print_r($_GET, true)); ?> line, i get this as output "Array()" that means $_GET variable value is empty.

Thanks
Terry Woods

You did copy and paste the code, right?

The round brackets on this line:
RewriteCond %{QUERY_STRING} error=([^&]+) [NC]

Open in new window

capture the value of the "error" parameter and are then put back into the URL as %1 in the rewriterule. Can you please double check both those things are in place correctly?
Vipin Kumar

ASKER
@Terry,

I confirm I copied the code correctly and I even placed the php code on the top of the error.php script so that it executes first.

I also confirm that the RewriteCond is same as mentioned by you above in the htaccess file.

Thanks
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Terry Woods

Can you provide an actual value of one of the error messages you're using? That way I can re-run my test with what's essentially real data. If there's any unexpected handling of special characters, maybe that could explain the behaviour.
Vipin Kumar

ASKER
@Terry,

I m using the below code as of now to check if $_GET variable value is being passed..

if($_GET['error']=='runtime-error'){
	echo '4565';
}else{
	echo '123';
}

Open in new window


Thanks
Terry Woods

Can you provide an actual value of one of the error messages you're using?
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
Terry Woods

Do you have anything else in your .htaccess that could be losing the query parameter?

What happens if you call the error.php directly like this:
localhost/portal/error.php?error=houdini-disappearing-query-param&redirect=done
Because I've manually added the redirect=done parameter to that URL, it should prevent the first rewriterule from redirecting, and doesn't match the second rule. That means it should just pass the query parameter directly to error.php.

If you were using my code at the top of error.php:
<?php die("<pre>".print_r($_GET, true)); ?>

Open in new window

then the output should be this (which is what I get):
Array
(
    [error] => houdini-disappearing-query-param
    [redirect] => done
)

Open in new window

Terry Woods

When I remove the redirect=done and just load:
http://localhost/portal/error.php?error=houdini-disappearing-query-param
then I get redirected to http://localhost/portal/error.php/error/houdini-disappearing-query-param and get the same output as before.
Vipin Kumar

ASKER
@Terry,

When i load localhost/portal/error.php?error=houdini-disappearing-query-param&redirect=done i am getting the expected output i.e.
Array
(
    [error] => houdini-disappearing-query-param
    [redirect] => done
)

Open in new window


When I load http://localhost/portal/error.php?error=houdini-disappearing-query-param or http://localhost:5489/portal/error.php?error=runtime-error i get redirected and the result is as below
Array
(
)

Open in new window


Below is the complete code in my .htaccess file
ErrorDocument 404 /portal/error1.php
ErrorDocument 500 /portal/error.php

RewriteEngine On
RewriteBase /portal/

RewriteCond %{QUERY_STRING} error=([^&]+) [NC]
RewriteCond %{QUERY_STRING} !redirect=done [NC]
RewriteRule (.*\.php)$ $1/error/%1? [NC,R=302,L]  # test with a 302 to avoid caching until it's confirmed as working

#RewriteRule ^portal/error\.php/error/(.*) /portal/error.php?error=$1&redirect=done [NC,L]

RewriteRule ^include/(.*)$ error.php [L,R=404]

Open in new window

⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Terry Woods

There's a few differences from the code I successfully tested (ie this: https://www.experts-exchange.com/questions/28969579/Redirect-and-Rewrite-URL-using-htaccess.html?anchor=a41804503#a41799547 ).

Firstly, you've set the RewriteBase to a different value and adjusted the first RewriteRule. Do you need that to be a different value?

Secondly, the 2nd RewriteRule (necessary to be able to work) is commented out in your code, and hasn't been adjusted to work with the different RewriteBase value.

Code tested as working:
RewriteEngine On
RewriteBase /

RewriteCond %{QUERY_STRING} error=([^&]+) [NC]
RewriteCond %{QUERY_STRING} !redirect=done [NC]
RewriteRule ^(portal/error\.php)$ $1/error/%1? [NC,R=302,L]  # test with a 302 to avoid caching until it's confirmed as working

RewriteRule ^portal/error\.php/error/(.*) /portal/error.php?error=$1&redirect=done [NC,L]

Open in new window

Vipin Kumar

ASKER
@Terry,

I have pasted the above exactly in my .htaccess file replacing all the old code. Now the redirection is not happening, it is showing URL http://localhost:5489/portal/error.php?error=runtime-error in the address bar but the output is as expected.

Array
(
    [error] => runtime-error
)

Open in new window

SOLUTION
Terry Woods

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
Vipin Kumar

ASKER
@Terry,

I tried with the code you provided it is still not working. The URL doesn't redirect. Is it because in the main file i am passing the header as "header('Location:error.php?error=runtime-error');". Even I am not understanding why it is working at your end and not at my end.

Thanks
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
Terry Woods

Not sure about whether the header might affect it; I'll get back to you if I can figure it out. You could try removing the / from ".*/error\.php" in my latest suggestion and see if it makes a difference.
Vipin Kumar

ASKER
@Terry,

We have some progress here.

I removed the / from both the Rewrite rules as per your last suggestion, I am getting the redirection as well as the output "Array( error => runtime-error    [redirect] => done)", but there is still one glitch the address bar is showing http://localhost:5489/portal/error.php/error/runtime-error?error=runtime-error i.e. there is a "?error=runtime-error" at the end.

Thanks
ASKER CERTIFIED SOLUTION
Terry Woods

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Terry Woods

It's unlikely to be a problem, but bear in mind that with the more relaxed pattern the RewriteRule using .*error\.php it can also match a different URL like:
portal/someotherapp/adifferenterror.php?anothererror=blah
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Vipin Kumar

ASKER
@Terry,

This works just fine.

What I wanted to know, is that do I need to create a separate rule for every script i.e. for example I have "admin.php" or  "users.php" or we can create a generic rule in htaccess which will work fine for all scripts.

Also, will this script work if there are multiple $_GET variables in URL for any of the scripts.

Thanks
Terry Woods

Would you want admin.php to redirect to
admin.php/error/error-message
?

What other query parameters are you expecting, and is there a pattern for how they're named?
Vipin Kumar

ASKER
@Terry,

no I don't want admin.php to redirect to admin.php/error/error-message. It can redirect to anything for example admin.php?xyy=abc123&uij=ham etc.

as far as I think there will be no pattern in the query parameters they can be named anything.

thanks
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
Terry Woods

You're probably best to create that as a separate question, provide some examples of what you want before and after.
Vipin Kumar

ASKER
@Terry,

I have opened a new question for the same can you please look into it.

https://www.experts-exchange.com/questions/28971545/Generic-Rule-to-Redirect-and-Rewrite-URL-using-htaccess.html

Thanks and unfortunately I cannot give more than 500 points for this question or else I would  have as you put a lot of effort to help me provide a solution. Looking for your assistance in future as well.
Vipin Kumar

ASKER
Thanks for all your help
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.