Preserve Requested Protocol in Sub-Directory with .htaccess - .htaccess

We have a http > https redirect on our 'top' level:
example.com/top/
Now for a sub-directory of /top/:
example.com/top/sub/
I want to preserve whatever protocol is requested there.
So if it's http://example.com/top/sub/this.php I want it to stay as 'http'
And if it's https://example.com/top/sub/this.php I want it to stay as 'https'
Currently I have an .htaccess file in the /top/sub/ directory with:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) http://%{HTTP_HOST}%{REQUEST_URI} [R=301,END]
Which is doing exactly what I need it to be doing, so in terms of all the requests being sent to the sub-directory it's perfect.
The issue is I'm getting an error message in the error_log reporting this:
[REWRITE] detected external loop redirection with target URL: http://example.com/top/sub/this.php, skip.
I understand why I'm getting this message, because every time a HTTP request is made it's matching this condition, I just don't know how to stop it. I tried using the 'END' parameter to force only one redirect - but this doesn't seem to be working, or at least not working the way I expected it to.
All I want is for the protocol to remain the same as requested for /top/sub/ - the issue is the /top/ redirect sending everything to HTTPS.
Is this possible?

I would be interested to know if there is actually a way to preserve a protocol without creating a loop, however I was able to achieve what I was after by just adjusting the redirect in /top/ to only redirect pages that didn't match /top/sub/ - I really should have thought of that as a solution earlier.
Hope that can help someone.

Related

Handle missing value in URL via htaccess

I am trying to find a way to avoid 500 server errors when a URL is broken and therefore either does not match or breaks an htaccess rule
For example,
https://www.acme.com/directory/url/123/123
This is a valid URL - but sometimes it comes through as
https://www.acme.com/directory/url//123
and this breaks and gives a 500 error.
In htaccess the redirect rule for this is
RewriteRule ^url/([0-9]+)/([0-9]+) /directory/url.php?id=$1&request_id=$2 [L]
To try to combat this I have added:
RewriteCond %{REQUEST_URI} ^(.*)/{2,}(.*)$
RewriteRule . /errors/unexpected-error.php?url=%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
The weird thing is this works on my local but not on live (on local it redirects to unexpected-error but on live in shows a 500 error) so I am not sure if this is a config thing on live or something I am not spotting in my htaccess.
Of course, we are trying to avoid this in the first place by making sure the email containing the URL can never be sent without both values etc but it relies on setup by the customer so we are getting through all possible scenarios
Is there another way of handling this?

Block specific url with ? with htacess

Firstly, I can't get the correct code looking at other post here, not working for me hahahaha.
I would like to block this specific url: /2017/06/wonder-womannuestra-princesa-feminista.html?m=1 (Related to an old blogger url)
Don't know why but different ips, without referrer and user agent, are spamming (not a real visit cause after a redirection to the new one on WordPress they visit all the links in the url) my site always entering by this url and I would like to block ONLY this one.
I've tried to redirect this one with Redirection plugin but I have a redirection to all "?m=(*)" and this one is the one working, not the one related to the specific url.
I just used : RewriteCond %{REQUEST_URI} ^/2017/06/wonder-womannuestra-princesa-feminista.html?m=1 but it doesn't work.
Could you help, I think the problem is that I'm not witting the correct code due to the "?" character. Many thanks.
With your shown samples, attempts considering that you need to block url(mentioned in comments/question), if this is the case then try following. This rule will forbid this specific url from being accessed.
Please these rules at top of your .htaccess file. Make sure to clear your browser cache before testing your URLs.
RewriteEngine ON
RewriteCond %{THE_REQUEST} \s/2017/06/wonder-womannuestra-princesa-feminista\.html\?m=1 [NC]
RewriteRule ^ - [F,L]

I need to redirect my dynamic URL to a clean and SEO friendly static URL using htaccess

I am a web developer. I have developed a news portal for my client. But the URLs of the articles are dynamic and I need to redirect it to a static URL for SEO purpose.
The current URL : https://example.com/single-post.php?id=1&category=news&title=this-is-a-title
Desired URL : https://example.com/news/this-is-a-title
Someone please help me.
I have wrote this :
RewriteCond %{QUERY_STRING} (?:^|&)id=(\d+)(?:&|$)
RewriteCond %{QUERY_STRING} (?:^|&)title=([^&]+)(?:&|$)
RewriteRule ^/?single-post\.php$ /%2/%1 [R=301]
RewriteRule ^/?(.*)/(\d+)$ single-post.php?title=$1&id=$2 [END]
But the URL output is not what I expected. It is like :
https://example.com/this-is-title/?id=1&title=this-is-title
The only title came first without the id and then the old format came again after the slash. I can't understand what is going on here.
What you ask actually is not possible. There is no way for the rewriting module to somehow magically guess the numerical ID of that object you request. What you can actually do is publish URL in the style of https://example.com/news/1/this-is-a-title. Notice the ID in there, that is what is usally done. For that his should point you into the right direction:
RewriteEngine on
RewriteRule ^/?news/(\d+)/(.*)/?$ /single-post.php?id=$1&category=news&title=$2 [END]
Typically your application logic will only need the numerical ID of the requested object to fetch it from your database. So you typically can silently drop the title in the internal rewriting which makes things even more simple:
RewriteEngine on
RewriteRule ^/?news/(\d+) /single-post.php?id=$1&category=news [END]
In case you receive an internal server error (http status 500) using the rule above then chances are that you operate a very old version of the apache http server. You will see a definite hint to an unsupported [END] flag in your http servers error log file in that case. You can either try to upgrade or use the older [L] flag, it probably will work the same in this situation, though that depends a bit on your setup.
This rule will work likewise in the http servers host configuration or inside a dynamic configuration file (".htaccess" file). Obviously the rewriting module needs to be loaded inside the http server and enabled in the http host. In case you use a dynamic configuration file you need to take care that it's interpretation is enabled at all in the host configuration and that it is located in the host's DOCUMENT_ROOT folder.
And a general remark: you should always prefer to place such rules in the http servers host configuration instead of using dynamic configuration files (".htaccess"). Those dynamic configuration files add complexity, are often a cause of unexpected behavior, hard to debug and they really slow down the http server. They are only provided as a last option for situations where you do not have access to the real http servers host configuration (read: really cheap service providers) or for applications insisting on writing their own rules (which is an obvious security nightmare).
UPDATE:
in your comment to this answer you suggest to also do an explit redirection in case the target URL is used on the client side. Here is a variant of version 2 above which adds that redirection:
RewriteEngine on
RewriteCond %{QUERY_STRING} (?:^|&)id=(\d+)(?:&|$)
RewriteRule ^/?single-post\.php$ /news/%1 [R=301]
RewriteRule ^/?news/(\d+) /single-post.php?id=$1&category=news [END]
A variant of version 1 would look similar:
RewriteEngine on
RewriteCond %{QUERY_STRING} (?:^|&)id=(\d+)(?:&|$)
RewriteCond %{QUERY_STRING} (?:^|&)title=([^&]+)(?:&|$)
RewriteRule ^/?single-post\.php$ /news/%1/%2 [R=301]
RewriteRule ^/?news/(\d+) /single-post.php?id=$1&category=news [END]
Is is a good idea to start with a 302 redirection first. And only change that to a 301 redirection once everything works fine. That saves you from hassles with client side caching while you are still trying things out.

How to have two different custom error pages in .haccess?

1.
I have a .haccess file that requires you do be accessing from a certain IP address:
<RequireAll>
Require ip XX.XX.XX.XX.XX YY.YY.YY.YY.YY ZZ.ZZ.ZZ.ZZ.ZZ
</RequireAll>
If someone tries to access the website from a IP other then X, Y, or Z then they get an error 403 Forbidden page. I have customized it using the following:
ErrorDocument 403 /.forbidden.php
2.
If someone tries to access a restricted file in the same directory (even if they are from ip addresses X, Y, or Z) then again they prompted with the SAME custom 403 Forbidden page.
My Question
How can I have two different custom 403 Forbidden pages based on why they are forbidden from accessing? In example 1 the forbidden page would /.wrongip.php and in example 2 the forbidden page would /.restricted.php
If this is about the extent of what you are doing then it is fine but if you are going to be doing a lot of redirecting I would consider doing this in PHP, but I digress. You are going to have to use Apache (2.4) module mod_rewrite to rewrite rules and conditions for the IP restriction portion. I would leave your custom 403 Forbidden as is for handling the other cases of that status code. If you are on shared hosting this module is usually enabled by most hosting providers by default.
RewriteEngine On
RewriteCond %{REMOTE_ADDR} !^111.222.333.444$
RewriteRule ^(.*)$ /.wrongip.php [L]
You will likely avoid confusion if you keep rule rewrites up near the top of your .htaccess file. You only need the RewriteEngine On line once in your file. RewriteCond is one of the conditions for the rule immediately following. You could have multiple conditions mapped to a single rule (using [OR] flag; AND behavior is by default).
In this solution, the ^ character indicates the start of a string. Likewise, $ indicates the end. So, ^(.*)$ is a wildcard and would match any file accessed on your server. Preceded by a single space separator, the /.wrongip.php portion indicates your custom error page to be redirected to. [L] is the flag to indicate the Apache server should stop processing other rules once it matches that one. Use this unless you are using multiple rules to construct a single URL, otherwise you may cause yourself a headache.
There is an additional flag, [R], that I would suggest being aware of and trying to use when possible for easier use in maintaining good practice with HTTP response codes. These help with search rankings and I would recommend specifying a 403 response because by default it will throw a 302 error which can negatively effect ranking over time. Changing the rule to RewriteRule ^(.*)$ /.wrongip.php [R=403,L] would cause the Apache server to issue an HTTP redirect to the browser (to /.wrongip.php) and communicate a 403 Forbidden error in the header. Since my example has all pages redirecting to /.wrongip.php for non-whitelisted IPs, most likely even /.wrongip.php itself, I think in your specific case the [R] flag would result in an HTTP redirect loop where they would keep requesting /.wrongip.php. In this case you should omit the [R] flag, this will cause the Apache server to do an internal redirect.
Without the [R] flag, the client won't have any idea that this redirect went on (hence internal), so you should still emulate the error code in the header of your /.wrongip.php file using PHP.
I have not tested it, but I assume something like
<Directory /var/www/mysite>
ErrorDocument 403 /.restricted.php
<RequireAll>
Require ip XX.XX.XX.XX.XX YY.YY.YY.YY.YY ZZ.ZZ.ZZ.ZZ.ZZ
ErrorDocument 403 /.wrongip.php
</RequireAll>
</Directory>
could do the trick.
Have a look at
https://httpd.apache.org/docs/trunk/custom-error.html and https://httpd.apache.org/docs/trunk/mod/core.html#errordocument for more information on how such configurations work.

Simple RewriteRule with nginx

I'm trying to write a RewriteRule to make a simple url. I want users to be able to type enter
www.example.com/somepage
and have it take them to
www.example.com/abc/somepage.php
How can this be done in .htaccess?
I've tried these to no avail:
RewriteRule ^somepage$ abc/somepage.php [L]
RewriteRule ^/somepage$ /abc/somepage.php [L]
What am I doing wrong?
Edit: nginx can also handle rewrites in its configuration files (and I think is actually preferred), which was my case (see my answer below). HTH
If you want the user's web browser to be redirected to your PHP page then you need the R=301 flag at the end of the RewriteRule.
But if you want the request to be silently rewritten (so that Apache knows where to find the resource, but the user's web browser just sees the "clean" URL) then you don't want the `R' flag.
Try the following:
RewriteRule ^somepage$ /abc/somepage.php
This will only rewrite a request for /somepage so that Apache fetches the content from /abc/somepage.php instead.
Our nginx server was utilizing .htaccess files (as I implemented rewrites there before), but now it is handling the rewrites in its configuration (.conf) files (which is the recommended method).
I do not have permission to modify the .conf files, so I won't post any untested code.. Hope this helps somebody!

Resources