Set .htaccess rules to specify different folders - php

I want to set a rule in .htaccess if I enter in the url www.mydomain.com/compare.php set 'public_html' as root otherwise anything come in the url set root as 'public' folder.
RewriteRule ^(?!compare-source.php).*)$ public/$1 [L]
I want to achieve following result.
if url is www.mydomain.com/compare.php hit following file.
public_html/compare.php
if urls are www.mydomain.com/ OR www.mydomain.com/home etc hit following file.
public_html/public/index.php
I am weak in regex and in these apache rules always :-( can someone give me the solution with good description?
Your answers are welcome, please can you describe how this crazy things work in detail. Thanks.

Try:
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/public
RewriteRule ^((?!compare\.php).*)$ /public/$1 [L]
The RewriteEngine directive enables or disables the runtime rewriting engine.
The RewriteCond directive defines a rule condition. The following Rule is only used if this condition is met; In our case, if REQUEST_URI (the path component of the requested URL) does not (because of !) begin (because of ^) with /public. We need this condition because we don't want to rewrite already rewritten URL - that would cause loop and Internal error 500.
Finally, the RewriteRule will match regex Pattern (^((?!compare\.php).*)$) against part of the URL after the hostname and port, and without the leading slash. If the pattern is matched, the Substitution (public/$1) will replace the original URL-path.
In plain language, if URL path does not begin with compare.php (because of ?!), pick everything (.*) between beginning (^) and end ($) and place it in variable $1. Then replace the original URL path with /public/$1.
#Anubhava's answer is also correct, he just placed both conditions in RewriteRule, and also it could be written even more readable as:
RewriteCond %{REQUEST_URI} !^/public
RewriteCond %{REQUEST_URI} !^/compare\.php
RewriteRule ^(.*)$ /public/$1 [L]

You can use this .htaccess in site root:
RewriteEngine On
# route /home/ or /home to /
RewriteRule ^home/?$ / [L,NC]
# if not compare-source.php or public/* then route to /public/*
RewriteRule ^(?!public/|compare-source\.php$).*)$ public/$1 [L,NC]

Related

Rewrite subdomain and URL-path to URL parameters but allow access to files

I'm struggling with my .htaccess file and setting it up the way I want it. The main function is a website that gets the language from the subdomain and the current page from the subfolders.
Requirements
I have three requirements that I need my .htaccess file to do;
Wildcard subdomain redirected to lang variable
Subfolder(s) redirected to page variable
Local files respected (this is where I'm stuck)
(Bonus) Split up the page variable into segments for each slash; page, sub1, sub2, etc
Examples
en.example.com/hello -> /index.php?lang=en&page=hello
es.example.com/hola -> /index.php?lang=es&page=hola
(Bonus) en.example.com/hello/there/sir -> index.php?lang=en&page=hello&sub1=there&sub2=sir
My current .htaccess
This is my current setup which actually kinda works, if I don't need any local files (lol). This means local images aren't found when my .htaccess below is active. I tried adding RewriteCond %{REQUEST_FILENAME} !-f to respect local files but that breaks the whole file it seems - and I don't know why.
RewriteCond %{REQUEST_URI} ^/$
RewriteCond %{HTTP_HOST} ((?!www).+)\.example\.com [NC]
RewriteRule ^$ /index.php?lang=%1 [L]
RewriteCond %{HTTP_HOST} ((?!www).+)\.example\.com [NC]
RewriteRule ^(.+)$ /index.php?lang=%1&page=$1 [L]
RewriteRule ^index\.php$ - [L]
RewriteRule ^(.*)$ /index.php?page=$1 [L,QSA]
If your URLs don't contain dots then exclude dots from your regex - this naturally excludes real files (that contain a dot before the file extension). This avoids the need for a filesystem check.
Your script should handle /index.php?lang=%1 and /index.php?lang=%1&page= exactly the same, so the first rule is superfluous.
RewriteRule ^index\.php$ - [L]
This rule should be first, not embedded in the middle.
Try the following instead:
RewriteRule ^index\.php$ - [L]
RewriteCond %{HTTP_HOST} ^((?!www).+)\.example\.com [NC]
RewriteRule ^([^.]*)$ /index.php?lang=%1&page=$1 [QSA,L]
RewriteRule ^([^.]*)$ /index.php?page=$1 [QSA,L]
Your last rule that rewrites everything else to index.php, less the lang URL param is questionable. Why not just include this in the preceding rule and validate the language in your script? Which you need to do anyway.
Assuming there is always a subdomain, then your rules could then be reduced to:
RewriteRule ^index\.php$ - [L]
RewriteCond %{HTTP_HOST} ^(.+)\.example\.com [NC]
RewriteRule ^([^.]*)$ /index.php?lang=%1&page=$1 [QSA,L]
Requests for the www language are then validated by your script and defaulted accordingly, as if the lang param was not passed at all (which you need to be doing anyway).
If your subdomain is entirely optional and you are accessing the domain apex then make it optional (with a non-capturing group) in the regex:
RewriteCond %{HTTP_HOST} ^(?:(.+)\.)?example\.com [NC]
:
The lang param would then be empty if the domain apex was requested.
(Bonus) en.domain.com/hello/there/sir -> index.php?lang=en&page=hello&sub1=there&sub2=sir
It would be preferable (more efficient, flexible, etc) to do this in your PHP script, not .htaccess.
But in .htaccess you could do something like this (instead of the existing rule):
:
RewriteRule ^([^/.]*)(?:/([^/.]+))?(?:/([^/.]+))?(?:/([^/.]+))?(?:/([^/.]+))?$ /index.php?lang=%1&page=$1&sub1=$2&sub2=$3&sub3=$4&sub4=$5 [QSA,L]
The URL params are empty when that path segment is not present.
It is assumed the URL-path does not end in a slash (the above will not match if it does, so a 404 will result). If a trailing slash needs to be permitted then this should be implemented as a canonical redirect to remove the trailing slash. Or reverse the logic to enforce a trailing slash.
This particular example allows up to 4 additional "sub" path segments, eg. hello/1/2/3/4. You can extend this method to allow up to 8 (since there is a limit of 9 backreferences in the Apache syntax) if required. Any more and you will need to use PHP. (You could potentially handle more using .htaccess, but it will get very messy as you will need to employ additional conditions to capture subsequent path segments.)
I tried adding RewriteCond %{REQUEST_FILENAME} !-f to respect local files but that breaks the whole file it seems
That should also be sufficient (if dots are permitted in your URLs). But I wonder where you were putting it? It should not "break" anything - it simply prevents the rule from being processed if the request does map to a file - the rule is "ignored".
This is of course assuming you are correctly linking to your resources/static assets using root-relative (starting with a slash) or absolute (starting with scheme + hostname) URLs. If you are using relative URLs then they will probably result in 404s. If this is the case then see my answer to the following question on the Webmasters stack:
https://webmasters.stackexchange.com/questions/86450/htaccess-rewrite-url-leads-to-missing-css

.htaccess redirect and rewrite url if REQUEST_URI starts with specific path

I am working on a Wordpress site, it requires a plugin that needs to access the API endpoint of WP.
It wants to access the site's:
http://myhost.test/wp/wp-json/erp/v1/hrm/employees/1\?include\=department,designation,reporting_to,avatar,roles
but changes to the folder structure, causes the real, and actual link should be:
http://myhost.test/wp-json/erp/v1/hrm/employees/1\?include\=department,designation,reporting_to,avatar,roles
as you can see, there should be no /wp at the start of the %{REQUEST_URI}
I am trying to make this work: but it won't redirect the request:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} ^/wp/wp\-json/
RewriteRule ^/wp/wp\-json(.*) /wp\-json$1 [L,R]
I do not understand what I am doing wrong,
I am catching everything after ^/wp/wp-json then forward it to ^/wp-json
What is going on?
Regards,
Using mod_rewrite in .htaccess context vs a <Directory> or <VirtualHost> context each have slightly different requirements in how the patterns are parsed. Most importantly to your situation, in .htaccess the first argument to RewriteRule is not matched against a leading slash / because the pattern is considered relative to the directory it is in.
Remove the leading / from your RewriteRule matcher argument:
RewriteRule ^wp/wp\-json(.*) /wp\-json$1 [L,R]

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]

.htaccess file rewrite rule check

I want to rewrite my apache mod_rewrite pattern. I use to do with following:
RewriteEngine on
RewriteRule /^([^A-Z0-9a-z]+)\.html /search.php?search_id=$1&%{QUERY_STRING}
With the above rule I can't get what I expecting.
Can anyone tell what is wrong with my code and how to solve it.
Edited.
my requirement is simple.
I want to redirect if i enter /1.html to /search.php?search_id=1
Thats it.
This should work:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !search\.php
RewriteCond %{REQUEST_URI} ^/([0-9]+)\.html [NC]
RewriteRule .* search.php?search_id=%1 [L,QSA]
Maps silently
http://example.com/FileID.html
To:
http://example.com/search.php?search_id=FileID
search.php is considered a fixed string, while FileID can be any number.
For permanent redirection, replace [L,QSA] with [R=301,L,QSA]
You have a typo in your rule try this:
RewriteEngine on
RewriteRule ^/([^A-Z0-9a-z]+)\.html /search.php?search_id=$1&%{QUERY_STRING}
By the way you could also try to use this:
RewriteRule ^/?([^A-Z0-9a-z]+)\.html /search.php?search_id=$1&%{QUERY_STRING}
This makes the leading slash optional.
Are you typing 1.html after the domain? That is if your domain is example.com, then you type example.com/1.html?
If it is you are doing then don't use / before the regular expression in .htaccess file.
Try adding the following into your main .htaccess file. That is located in the directory which has your home page of the website:
RewriteEngine On
#RewriteBase /
RewriteRule ^([A-Za-z0-9]+)\.html/?$ /search.php?search_id=$1 [NC, L]
I have used RewriteBase as a comment. If you use a shared server then keep it as a comment or delete the line.
EDIT: [NC, L] use to tell that, NC flag for rule no need to be case sensitive (no case) and L flag for stop if this was matched.

Apache mod_rewrite module issue

I have the following code in my .htaccess.
RewriteEngine On
RewriteRule ^/(\w+)/?$ /?user=$1
I'm trying to rewrite
http://domain.com/?user=username into http://domain.com/username. Unfortunately this code doesn't rewrite anything. Please help
Note:
I checked phpinfo() and mod_rewrite is loaded.
Update
I need to get username from url like http://facebook.com/username. But this code rewrites every folder in root folder, so my /css folder become http://domain.com/css/?u=common. How to allow this code works only for http://domain.com/index.php
The mistake you are doing is the use of / in the beginning of the line ^/(\w+)/?$
rewrite rules strips off the / from the beginning of the pattern to be matched in .htaccess and directory context.
Try doing this:
RewriteEngine On
RewriteRule ^(\w+)/?$ /?user=$1
From RewriteRule Directive docs :
What is matched?
In VirtualHost context, The Pattern will initially be matched against the part of the URL after the hostname and port, and before the query string (e.g. "/app1/index.html").
In Directory and htaccess context, the Pattern will initially be matched against the filesystem path, after removing the prefix that lead the server to the current RewriteRule (e.g. "app1/index.html" or "index.html" depending on where the directives are defined).
If you wish to match against the hostname, port, or query string, use a RewriteCond with the %{HTTP_HOST}, %{SERVER_PORT}, or %{QUERY_STRING} variables respectively.
Edit: Answer updated as per OP's request:
Add this :
RewriteEngine On
#do nothig if URL is trying to access the folder CSS.
RewriteRule *css/* - [L]
#checks where the URL is a valid file/folder.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(\w+)/?$ /?user=$1
I think that you are doing it the right way round, but explained it the wrong way round!
Is the problem that you don't need the initial / as the URL passed to test doesn't include it!?
I suspect it should be RewriteRule ^(\w+)/?$ /?u=$1
Also, be careful you don't end up with a loop!

Categories