Rewriting url with htaccess when a directory exists - php

I'm trying to redirect a dynamic page to a dir, example:
url.com/index.php?page=download
to
url.com/download
The rule is very simple:
RewriteRule ^download$ /index.php?page=download
FULL .HTACCESS
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} !^www\.url\.com$
RewriteRule ^(.*) http://url.com/$1 [R=301,L]
Redirect 301 /index.php?page=download http://url.com/download
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule .* - [L]
RewriteRule ^download$ /index.php?page=download
The problem is that I already have a directory named "download" and it's returning me a "403 Forbidden Error".
I have noticed that renaming the directory to anything different than the name (download) the rule is using will work.
So, my question is: how can I have my url rewritten the way I need and keep the directory?
-- EDIT --
My server, by default, protects every directory with a "403 Forbbiden Error". I believe this is the reason why it's not working, but I'm not sure.
Is it a conflict indeed?
What is happening?

/download/?page=download
The reason why this is happening is because somewhere mod_dir redirects all requests for directories that are missing the trailing slash to include the trailing slash. This is interferring with your rewrite rule. Since your server is automatically setup to deny listing of directories, it's probably safe to go ahead and turn directory slashes off:
DirectorySlash Off
Answer by: https://stackoverflow.com/users/851273/jon-lin

Your problem is, I think, due to this specific rewrite rule:
RewriteRule .* - [L]
Apache will read your htaccess in detail, line by line, and will try to map each rewrite rule in turn (+ conditions, obviously). Let's follow it in detail.
RewriteCond %{HTTP_HOST} !^www\.url\.com$
RewriteRule ^(.*) http://url.com/$1 [R=301,L]
These two by themselves are NOT fine but not the source of your problem. If the HTTP HOST is anything but www.url.com, it will redirect to http://url.com/... which is not www.url.com, which will then redirect to url.com. You have a potential infinite loop but only if the HTTP HOST is not www.url.com to start with. If it matched, due to the L flag, it breaks processing and returns the redirect.
Redirect 301 /index.php?page=download http://url.com/download
This line is fine. You're doing a 301 redirect to anyone who happens to know index.php?page=download.
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule .* - [L]
This line is NOT fine. The rewrite condition specifies that, so far, anything that is not a redirect from above will work for the next rule. The next rule matches EVERYTHING (.* means everything. 0 or more characters of anything) and in-rewrites to -, which in mod_rewrite language is a do not touch flag. This is fine. However, the L flag breaks the chain and returns, which causes your download/ folder to show as the list of your actual download folder, which is the source of your 403 error.
Remove the L flag to get the next rule to process:
RewriteRule ^download$ /index.php?page=download
Which is fine by itself.

Related

Redirect entire sub-directory to root directory

So I am trying to clean up my search engine redirect errors. I had some old development sites that got indexed that I want to redirect to the main site.
Basically I want everything in the /dev/ folder to go to https://myfakewebsite.com/
I added this to .htaccess file in the /dev/ directory:
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^(.*)$ /$1 [R=301,L]
I tried this but it doesn't quite work, it does take out the /dev/ but it keeps the rest of the link there.
For example: https://myfakewebsite.com/dev/index.php?route=product/category&path=122
redirects to: https://myfakewebsite.com/index.php?route=product/category&path=122
I want it to redirect to: https://myfakewebsite.com/ (removing the /index.php?route=product/category&path=122 part).
Is there a way to do this with .htaccess?
You can use the following rule in your /dev/.htaccess
RewriteEngine on
RewriteRule (.*) / [L,R=301]
The rule above redirects all requests from /dev to the root of site ie . /dev/* => / including query strings from /dev?querystring to /?querystring . By default mod-rewrite appends old query string to the destination path so if you do not want it then you can use QSD flag in your rule or you can another rule to handle and remove QUERY_STRING .
You can use the following rules to redirect urls with and without query string to / . The ? at the end of the rule's destination discards the old query string.
RewriteEngine on
# redirect /dev?querystring to /
RewriteCond %{QUERY_STRING} .+
RewriteRule (.*) /? [L,R=301]
# redirect /dev/uri to /
RewriteRule (.*) / [L,R=301]
Make sure to clear your browser cache before testing these redirects.
You might want to achieve this kind of "trivial" redirect with the RedirectMatch directive from mod_alias, instead of doing this with mod_rewrite.
RedirectMatch 301 "/dev/(.*)" "/$1"
See documentation at https://httpd.apache.org/docs/2.4/mod/mod_alias.html.
You left the match results as part of the redirect on this line:
RewriteRule ^(.*)$ /$1 [R=301,L]
Specifically $1 as part of /$1 (the redirecting portion of the rule). Since this file is within the /dev directory it automatically removes /dev/ then applies the match to the redirect. Since you are using the capture ($1) as part of the rule, it'll take everything it matched after /dev/ (in your rule you should read it as ^/dev/(.*)$) and apply it to /$1, where $1 is whatever it "found" during ^(.*)$ in the previous step.
Try removing the pattern match, e.g.:
RewriteRule ^(.*)$ / [R=301,L]
Additionally, since you aren't using the results of the match you can remove the parenthesis (e.g. ^.*$). You can also put this .htaccess file in the root and simply redirect ^/dev(/?.*)$ to / depending on how you want to manage your subdirectories.

.htaccess Multiple Rewrite Rules with Extensions

So, I'm not very good with Apache config or .htaccess rewrite rules.... And I'm trying to do some modifications to how my localhost server works...
What I'm trying to do is return a 404 error on any request with the extension '.php'. If the uri does not have an extension, then route the request to 'ini.php'. If the uri contains an extension that isn't of '.php', then it should just follow normal procedures in fetching the file.
What I have now:
Rewrite Engine on
DirectorySlash off
RewriteCond $1 (.php)
RewriteRule ^(.*)$ - [L,NC,R=404]
RewriteCond $1 !^(.+)
RewriteRule ^(.*)$ ini.php [L,NC]
My logic is that if it's not a .php, and it doesn't have an extension, then route it to ini.php. Otherwise it should route normally.
Right now it looks like the .php rule is working in returning 404 errors.. However, if a request for a path without an extension is received, it tries to route to ini.php and hits a 404 page. Is it maybe processing like the second rule and then hitting the first rule?
Anyways, can someone help me sort it out and give me some guidance on it? I tried google and a bunch of different solutions, but I couldn't find something that worked for this situation...
UPDATE:
I changed the code to the following and added ini.php to the DirectoryIndex settings in httpd:
RewriteEngine on
RewriteCond %{REQUEST_URI} (\.[php^\\/]+)$
RewriteRule ^(.*)$ - [L,NC,R=404]
RewriteCond %{REQUEST_URI} !(\.[^\\/]+)$
RewriteRule ^.+$ / [L,NC]
Can you check if it looks alright?
I've turned on DirectorySlash again. Thanks.
This will do it:
RewrieEngine on
# 404 any URL ending .php (ignoring any query string)
RewriteRule ^(.+)\.php$ - [R=404,L,NC]
# Rewrite any URL that does not contain a dot (.), and therefore has no extension, to ini.php
RewriteRule ^([^.]*)$ ini.php [END]
I am assuming it will go in a .htaccess file from what you said. It would need changing to go in the main config.
Don't turn DirectorySlash off. It's a security risk to do so (see the link) and it only applies to existing directories anyway so is not causing any problems for you. There is no space in RewriteEngine.

Why is this .htaccess not silently redirecting?

Can anyone tell me why the following visibly changes the URL in the browser, rather than redirecting silently? The redirect works, but visibly.
Example URL: http://domain.com/_test/sportswire/uk/football/huddersfield
...visibily redirects with query string arguments showing.
RewriteEngine on
RewriteBase /_test/sportswire
#favour naked domain over www
RewriteCond %{HTTP_HOST} ^www\.(.+) [NC]
RewriteRule ^(.*) http://%1/$1 [R=301,NE,L]
#disallow trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
###THIS RULE### channel pages - territory/sport/channel/[res type?]
RewriteRule ^(\w+)\/(\w+)\/(\w+)(?:\/(\w+))?$ channel.php?territory=$1&sport=$2&team=$3&res_type=$4 [L,NC,R=301]
#channel pages - with item (if from external referrer) - territory/sport/channel/res_type/"item"/item_id/pretty
RewriteRule ^(\w+)\/(\w+)\/(\w+)\/(\w+)\/story\/\w{11}\/[^\/]+$ channel.php?territory=$1&sport=$2&team=$3&res_type=$4&item=$5 [L,NC,R=301]
What I've tried/read:
Remove the R flag (no joy; and I have other .htaccess files with R flags that redirect silently)
Add/remove a rewrite base (done; also tried an absolute one)
Don't use absolute URLs (I'm not)
I'm fairly convinced there's nothing on planet earth quite as perplexing as mod-rewrite.
Try removing the [R] flag altogether, so that the server won't notify the browser of the change.
htaccess changes take effect immediately, so you don't need to restart the server. However, since you previously tried R=301, your browser may remember to go straight to the URL with the query string and never even ask the server for the URL you're trying to redirect. To see the effect of the change I recommended, start a new browser instance in incognito or private browsing mode and test the new rule.
Side note: why are you escaping all the / in your paths? I don't think you need to.
[R] flag should not be there. Try restarting Apache if that is possible, I've noticed that it helps sometimes.
Try another browser or different URL, they can cache redirects.

How to do both internal and external .htacces rewrite to completely remove ALL QUERY_STRING elements from ALL URIs, with relative path

I want to remove all client request querystrings whatsoever, no exceptions.
I have tried everything I can find, and everything I know about regular expressions, and this task puzzles me. I have been able to achieve removal of the query strings, but now all requests have the full file path prepended to the working directory upon rewrite and redirect.
Examples: there is no http in these because stackoverflow won't let me post URLs.
I access the file: /localhost/testing/dogs/pups.txt
Yes, pups.txt exists and lives right there.
Server returns this to browser: /localhost/home/user/public_html/testing/dogs/pups.txt
If I access it with a query string appended:
/localhost/testing/dogs/pups.txt?bark=woof
I get the same output to the browser:
/localhost/home/gost/public_html/testing/dogs/pups.txt
So I know the query string is being nixed, while the full root path is being added to the hypertext address.
How do I tell mod_rewrite to keep the relative path of the existing files, so that this prepending of the full file path stops, and accurately cause it to rewrite internally and externally so that no query string ever makes it to php-land?
Here is the current .htaccess file. It resides in directory /home/user/public_html/testing. Where deployed online, it is NOT possible to put it in the root web directory, the obvious move that would instantly resolve this problem.
# These are commented out on purpose because they kill access to the server.
# The weird rules for regex in Apache configurations is baffling me. This
# does remove all QUERY_STRING characters, but, it then rewrites by
# prepending the web root path to the current directory, causing error 404.
# RewriteCond %{QUERY_STRING} ^
# RewriteRule (.*) $1? [R=301,L]
# These rules work fine. Whatever does not end with a media or document
# extension gets sent to index.php
RewriteRule ^.*\.(gif|jpe?g|png|txt|svg|pdf|rtf|odt|doc|docx)$ - [L]
RewriteRule ^.*\.(tex|epub|mobi|csv|ods|xls|swf|flv)$ - [L]
RewriteRule ^ index.php [L]
Change this RewriteCond %{QUERY_STRING} ^ to this RewriteCond %{QUERY_STRING} .
and add the directory to the rule since you can't use rewritebase. So it should look like this
RewriteCond %{QUERY_STRING} .
RewriteRule (.*) /testing/$1? [R=301,L]
I can't accept my own answer for two days, so if anyone wants to add logic about mod_rewrite for future questioners, have at it. Per Panama Jack's advice, this .htaccess file does the job and this question is answered.
RewriteEngine On
RewriteCond %{QUERY_STRING} .
RewriteRule (.*) /testing/$1? [R=301,L]
RewriteRule ^.*\.(gif|jpe?g|png|txt|svg|pdf|rtf|odt|doc|docx)$ - [L]
RewriteRule ^.*\.(tex|epub|mobi|csv|ods|xls|mm|)$ - [L]
RewriteRule ^ test.php [L]

How to implement 301 redirection with PHP/Apache?

When user is visiting by www.domain.name, redirect to domain.name.
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.domain\.name$ [NC]
RewriteRule (.*) http://domain.name/$1 [R=301,QSA,L]
Put this in an .htaccess file in your root directory of your website:
RewriteEngine On
RewriteCond %{HTTP_HOST} .
RewriteCond %{HTTP_HOST} !^domain\.name
RewriteRule (.*) http://domain.name/$1 [R=301,L,QSA]
This is what they do, in order:
Turn the rewrite engine on
Make sure that HTTP_HOST was provided
If it doesn't start with the name without the www or any other sub domain, then allow the rewrite to continue. This prevents an endless redirect back to itself.
Grab everything after the URL (.*), including the querystring QSA, and redirect R=301 to the correct domain. The L just says this is the last command in the file if a match is found.
In Apache you add a Redirect line to your configuration files. In php you reply with a status code 301 and a Location: header.
However, a redirect requires an additional network round trip. Are you sure you don't want to just use a ServerAlias line so that the same content is served up whether they visit with or without the www.?

Categories