Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

Redirect and Rewrite URL using .htaccess

Posted on 2016-09-13
38
Medium Priority
?
203 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 35

Expert Comment

by:gr8gonzo
ID: 41796816
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
ID: 41796829
@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
ID: 41797529
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
Configuration Guide and Best Practices

Read the guide to learn how to orchestrate Data ONTAP, create application-consistent backups and enable fast recovery from NetApp storage snapshots. Version 9.5 also contains performance and scalability enhancements to meet the needs of the largest enterprise environments.

 
LVL 1

Author Comment

by:Vipin Kumar
ID: 41797623
@Terry,

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

Expert Comment

by:gr8gonzo
ID: 41798336
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
ID: 41798963
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
ID: 41799101
@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
ID: 41799547
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
ID: 41799581
@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 35

Expert Comment

by:gr8gonzo
ID: 41799753
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
ID: 41800678
@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
ID: 41802056
@Terry,

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

Expert Comment

by:Terry Woods
ID: 41802941
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
ID: 41803448
@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
ID: 41803540
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
ID: 41803550
@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
ID: 41803618
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
ID: 41803963
@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
ID: 41804076
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
 
LVL 1

Author Comment

by:Vipin Kumar
ID: 41804230
@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
ID: 41804490
Can you provide an actual value of one of the error messages you're using?
0
 
LVL 35

Expert Comment

by:Terry Woods
ID: 41804495
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
ID: 41804497
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
ID: 41804503
@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
ID: 41804526
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
ID: 41804581
@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 2000 total points
ID: 41806089
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
ID: 41806593
@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
ID: 41808054
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
ID: 41808086
@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 2000 total points
ID: 41808240
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
ID: 41808243
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
ID: 41808263
@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
ID: 41808408
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
ID: 41808448
@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
ID: 41808506
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
ID: 41809943
@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
ID: 41809945
Thanks for all your help
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Nothing in an HTTP request can be trusted, including HTTP headers and form data.  A form token is a tool that can be used to guard against request forgeries (CSRF).  This article shows an improved approach to form tokens, making it more difficult to…
Originally, this post was published on Monitis Blog, you can check it here . In business circles, we sometimes hear that today is the “age of the customer.” And so it is. Thanks to the enormous advances over the past few years in consumer techno…
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …
Suggested Courses

886 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