Solved

Redirect and Rewrite URL using .htaccess

Posted on 2016-09-13
38
92 Views
Last Modified: 2016-09-21
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
0
Comment
Question by:Vipin Kumar
  • 18
  • 17
  • 3
38 Comments
 
LVL 34

Expert Comment

by:gr8gonzo
Comment Utility
Haven't tested this, but it'd probably be something like:

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

Author Comment

by:Vipin Kumar
Comment Utility
@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
0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
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

0
 
LVL 1

Author Comment

by:Vipin Kumar
Comment Utility
@Terry,

Its not working. The redirection itself is not happening.
0
 
LVL 34

Expert Comment

by:gr8gonzo
Comment Utility
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]
0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
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

0
 
LVL 1

Author Comment

by:Vipin Kumar
Comment Utility
@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.
0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
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

0
 
LVL 1

Author Comment

by:Vipin Kumar
Comment Utility
@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.
0
 
LVL 34

Expert Comment

by:gr8gonzo
Comment Utility
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.
0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
@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.
0
 
LVL 1

Author Comment

by:Vipin Kumar
Comment Utility
@Terry,

Any solution you have for this query of mine.
0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
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.
0
 
LVL 1

Author Comment

by:Vipin Kumar
Comment Utility
@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
0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
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.
0
 
LVL 1

Author Comment

by:Vipin Kumar
Comment Utility
@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
0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
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?
0
 
LVL 1

Author Comment

by:Vipin Kumar
Comment Utility
@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
0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
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.
0
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 
LVL 1

Author Comment

by:Vipin Kumar
Comment Utility
@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
0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
Can you provide an actual value of one of the error messages you're using?
0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
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

0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
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.
0
 
LVL 1

Author Comment

by:Vipin Kumar
Comment Utility
@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

0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
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

0
 
LVL 1

Author Comment

by:Vipin Kumar
Comment Utility
@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

0
 
LVL 35

Assisted Solution

by:Terry Woods
Terry Woods earned 500 total points
Comment Utility
Not sure why it's not working for you. I've relaxed some of the patterns and retested (works for me), so give this a try:

RewriteEngine On
RewriteBase /portal/
RewriteCond %{QUERY_STRING} error=([^&]+) [NC]
RewriteCond %{QUERY_STRING} !redirect=done [NC]
RewriteRule ^(.*/error\.php)$ $1/error/%1 [NC,R=302,L]
RewriteRule ^(.*/error\.php)/error/(.*) $1?error=$2&redirect=done [NC,L]

Open in new window


Note that changing the RewriteBase didn't make any difference for my test. I think this is because the .*/error\.php part of the patterns pick up an absolute path with a / at the start, rather than a relative one, but I haven't confirmed this.
0
 
LVL 1

Author Comment

by:Vipin Kumar
Comment Utility
@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
0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
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.
0
 
LVL 1

Author Comment

by:Vipin Kumar
Comment Utility
@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
0
 
LVL 35

Accepted Solution

by:
Terry Woods earned 500 total points
Comment Utility
Great! Just add a ? character after the %1 in the first RewriteRule, and that should solve the extra query param problem:
RewriteEngine On
RewriteBase /portal/
RewriteCond %{QUERY_STRING} error=([^&]+) [NC]
RewriteCond %{QUERY_STRING} !redirect=done [NC]
RewriteRule ^(.*error\.php)$ $1/error/%1? [NC,R=302,L]
RewriteRule ^(.*error\.php)/error/(.*) $1?error=$2&redirect=done [NC,L]

Open in new window

0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
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
0
 
LVL 1

Author Comment

by:Vipin Kumar
Comment Utility
@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
0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
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?
0
 
LVL 1

Author Comment

by:Vipin Kumar
Comment Utility
@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
0
 
LVL 35

Expert Comment

by:Terry Woods
Comment Utility
You're probably best to create that as a separate question, provide some examples of what you want before and after.
0
 
LVL 1

Author Comment

by:Vipin Kumar
Comment Utility
@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.
0
 
LVL 1

Author Closing Comment

by:Vipin Kumar
Comment Utility
Thanks for all your help
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

I imagine that there are some, like me, who require a way of getting currency exchange rates for implementation in web project from time to time, so I thought I would share a solution that I have developed for this purpose. It turns out that Yaho…
Things That Drive Us Nuts Have you noticed the use of the reCaptcha feature at EE and other web sites?  It wants you to read and retype something that looks like this.Insanity!  It's not EE's fault - that's just the way reCaptcha works.  But it is …
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now