.htaccess rewrite content to subfolder - .htaccess

I have the following folders structure on my web server:
I need some rewrite rules:
When I visit http://testdomain1.com/ I need to set /pages/testdomain1.com/ as the root directory to display content from this dir.
Similarly, http://testdomain2.com/ root folder is /pages/testdomain2.com/ etc..
When the requested URL has the la var - I need to rewrite to landing directory.
Example:
http://testdomain1.com/?la=template1 - set /lands/template1/ as root dir
I have some issue with my current .htaccess (for first task):
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www.)?testdomain1.com$
RewriteRule ^(/)?$ pages/%{HTTP_HOST}/index.html [L]
Rewrite rule works, but all assets data (js, css) don't work (404 not found).
How can I set the right rules?

... but all assets data (js,css) don't work (404 not found). How can I set right rules?
This is most probably caused by using relative URL paths to your assets. You need to "fix" your URL paths to be root-relative or absolute. This is not something that should be fixed in .htaccess, your rewrite is otherwise OK.
See my answer to the following question on the Webmasters stack, relating to the use of relative URL paths to static assets when using URL rewriting:
https://webmasters.stackexchange.com/questions/86450/htaccess-rewrite-url-leads-to-missing-css
RewriteCond %{HTTP_HOST} ^(www.)?testdomain1.com$
RewriteRule ^(/)?$ pages/%{HTTP_HOST}/index.html [L]
This only rewrites requests for the root, ie. testdomain1.com/. And not testdomain1.com/foo - is that intentional?
I need to have access to any page (example.com/page.html) not only index.html.
If by that you mean that a request of the form http://testdomain1.com/foo should be rewritten to /pages/testdomain1.com/foo, then you would need to change the above to something like the following:
RewriteCond %{QUERY_STRING} !^la=[\w-]+
RewriteCond %{HTTP_HOST} ^(?:www.)?(testdomain1\.com)$
RewriteRule !^pages/ pages/%1%{REQUEST_URI} [L]
Note that this rewrites everything, including CSS, JS and images.
The first condition (RewriteCond directive) excludes URLs that contain the la URL parameter. (These URLs are handled below.)
This also fixes a bug in your existing directive, whereby a request for the www subdomain (eg. www.testdomain1.com) would have resulted in an incorrect rewrite. The %1 backreference in the substitution string contains the domain being requested - less an optional www subdomain. (I assume you don't have a subdirectory www.testdomain1.com?) Although, arguably, you should already be canonicalising the www/non-www earlier in the config file.
(Remember to escape literal dots.)
UPDATE:
i tried to use this case for multiple domains, not only for testdomain1.com. So i need change RewriteCond %{HTTP_HOST} ^(www.)?testdomain1.com$ part. I just tried RewriteCond %{REQUEST_URI} but don't working.
For multiple domains, you can either:
Duplicate the above code block for each domain and change the testdomain1.com domain in the second condition.
If this applies to just 3 domains then you can use alternation in the second condition, to match any of the 3 domains. For example:
RewriteCond %{HTTP_HOST} ^(?:www.)?(testdomain1\.com|testdomain2\.com|testdomain3\.com)$
If this should apply to any domain, then make the regex more general to match any domain. For example:
RewriteCond %{HTTP_HOST} ^(?:www.)?([a-z0-9.-]+?)\.?$
2) When request URL have "la" var - I need rewrite to land directory.
Example: http://testdomain1.com/?la=template1 - set /lands/template1/ as root dir
As mentioned in my comment, you probably shouldn't be rewriting to a directory. It is not the directory that handles the request, but ultimately a file. By rewriting to a directory I assume you are relying on mod_dir issuing an internal subrequest for the directory index document (as specified by the DirectoryIndex directive). For the sake of this example, I will assume the directory index is index.php.
This would need to go before the above rewrite, since it is more specific:
RewriteCond %{QUERY_STRING} ^la=([\w-]+)
RewriteRule ^$ /lands/%1/index.php [L]
%1 (as opposed to $1) is a backreference to the captured pattern in the last matched CondPattern. The regex [\w-]+ restricts the la parameter value to the characters 0-9, a-z, A-Z, _ and -. The la parameter must also be the first URL parameter.

Related

Redirect all URLS to new URL EXCEPT for /backend/ with .htaccess

I want to redirect all incoming queries to a new domain, except for /backend
I have this in my .htaccess, everything works, except for the /backend. I tried a few combinations, it just doesnt work.
I fear /backend is a virtual address....
what can i do?
HERE IS THE CODE:
RewriteCond %{HTTP_HOST} ^example.de$ [OR]
RewriteCond %{HTTP_HOST} ^www.example.de$
RewriteCond %{REQUEST_URI} !^/backend/$
RewriteRule (.*)$ https://www.bing.de/ [R=302,L]
PLEASE HELP. Thank you. Patrick
I fear /backend is a virtual address....
In which case you most probably have other mod_rewrite directives that rewrite the request to a front-controller (such as index.php) - and that's the problem. Whilst your existing rule includes an exception for /backend/ (the originally requested URL), so the rule is skipped on the first pass by the rewrite engine, once the request is rewritten to the front-controller (eg. index.php) the rewrite engine begins a 2nd pass which results in the rule being successfully executed since the URL is now /index.php (or whatever your front-controller is) and not /backend/.
You either need to:
modify the other directives that rewrite the request to the front-controller, so as not to trigger a 2nd pass through the rewrite engine. (You've not included your complete .htaccess file, so I'll discount this approach for now.)
OR, make sure you only examine the originally requested URL and not the rewritten URL. (The REQUEST_URI server variable is modified as the request is rewritten.)
However, I would assume that your /backend/ page also links to static assets (such as images, CSS, JS)? In which case, you also need to make exceptions for any additional static assets that are used by the page, otherwise these will also be redirected. For the sake of this example, I will assume all you static assets are located in an /assets subdirectory.
Try the following instead, near the top of your root .htaccess file:
RewriteCond %{HTTP_HOST} ^(www\.)?example\.de [NC]
RewriteCond %{THE_REQUEST} !\s/backend/\s
RewriteRule !^assets/ https://www.bing.de/ [R=302,L]
Note that this rule must go before the rewrite to the front-controller.
The THE_REQUEST server variable contains the first line of the HTTP request headers and importantly, does not change as the request is rewritten. This contains a string of the form GET /backend/ HTTP/1.1 (containing the request method, URL and protocol).
If there are no external assets then change the RewriteRule pattern from !^assets/ to simply ^, to match everything.

HTACCESS How to "cut" URL at one point

I am new to .htaccess and I don't understand it well. Recently I have built the following code:
RewriteEngine On
RewriteCond %{HTTP_HOST} (.*)
RewriteCond %{REQUEST_URI} /api/v2/
RewriteRule ^api/v2(.*) /api/v2/api.php?input=$1
This was in the root public folder (example.com/.htaccess). But now I have to create second Rewrite and I want to make .htaccess file in example.com/api/v2/ folder. I tried to remove /api/v2/ part in each Rewrite Rule, but only thing I got was error 500.
What I want to achieve:
If someone uses this link: https://example.com/api/v2/test/test/123, I'd like to make it into https://example.com/api/v2/api?input=test/test/123 with .htaccess located in example.com/api/v2 folder.
Addressing your existing rule first:
RewriteCond %{HTTP_HOST} (.*)
RewriteCond %{REQUEST_URI} /api/v2/
RewriteRule ^api/v2(.*) /api/v2/api.php?input=$1
The first RewriteCond (condition) is entirely superfluous and can simply be removed. The second condition simply asserts that there is a slash after the v2 and this can be merged with the RewritRule pattern. So, the above is equivalent to a single RewriteRule directive as follows:
RewriteRule ^api/v2(/.*) /api/v2/api.php?input=$1 [L]
This would internally rewrite the request from /api/v2/test/test/123 to /api/v2/api.php?input=/test/test/123 - note the slash prefix on the input URL parameter value.
However, unless you have another .htaccess file in a subdirectory that also contains mod_rewrite directives then this will create a rewrite loop (500 error).
Also note that you should probably include the L flag here to prevent the request being further rewritten (if you have other directives).
If someone uses this link: https://example.com/api/v2/test/test/123, I'd like to make it into https://example.com/api/v2/api?input=test/test/123 with .htaccess located in example.com/api/v2 folder.
I assume /api? is a typo and this should be /api.php?. Note also that the slash is omitted from the start of the URL parameter value (different to the rule above).
I tried to remove /api/v2/ part in each Rewrite Rule, but only thing I got was error 500.
This is the right idea, however, you need to be careful of rewrite loops (ie. 500 error response) since the rewritten URL is likely matching the regex you are trying to rewrite.
Try the following instead in the /api/v2/.htaccess file:
RewriteEngine On
RewriteCond %{REQUEST_URI} !api\.php$
RewriteRule (.*) api.php?input=$1 [L]
The preceding RewriteCond directive checks that the request is not already for api.php, thus avoiding a rewrite loop, since the pattern .* will naturally match anything, including api.php itself.
You could avoid the additional condition by making the regex more specific. For example, if the requested URL-path cannot contain a dot then the above RewriteCond and RewriteRule directives can be written as a single directive:
RewriteRule ^([^.]*)$ api.php?input=$1 [L]
The regex [^.]* matches anything except a dot, so avoids matching api.php.
Alternatively, only match the characters that are permitted. For example, lowercase a-z, digits and slashes (which naturally excludes the dot), which covers your test string test/test/123:
RewriteRule ^([a-z0-9/]*)$ api.php?input=$1 [L]
Or, if there should always be 3 path segments, /<letters>/<letters>/<digits>, then be specific:
RewriteRule ^([a-z]+/[a-z]+/\d+)$ api.php?input=$1 [L]

Redirect certain subfolders by removing the parameter question mark

I am using .htaccess to redirect certain subfolders of my domain, to remove the question mark to improve my URLs.
Currently my URLs are like this:
www.example.com/post/?sometitle
I am trying to remove the question mark, so it is the following URL:
www.example.com/post/sometitle
Currently I have the following code in my .htaccess file:
RewriteCond %{THE_REQUEST} /post/?([^\s&]+) [NC]
RewriteRule ^ /post/%1 [R=302,L,NE]
i am using php GET parameters, i am attempting for when the browser visits example.com/post/sometitle that the page that is currently example.com/post/?sometitle is displayed
In that case you need to the opposite of what you are asking in your question: you need to internally rewrite (not externally "redirect") the request from example.com/post/sometitle to example.com/post/?sometitle.
However, you must have already changed all the URLs in your application to use the new URL format (without the query string). You shouldn't be using .htaccess alone for this.
I also assume that /post is a physical directory and that you are really serving index.php in that directory (mod_dir is issuing an internal subrequest to this file). So, instead of /post/?sometitle, it's really /post/index.php?sometitle?
For example:
RewriteEngine On
# Rewrite /post/sometitle to filesystem path
RewriteRule ^post/([\w-]+)$ /post/index.php?$1 [L]
So, now when you request /post/sometitle the request is internally rewritten and handled by /post/index.php?sometitle instead.
I have assumed that "sometitle" can consist of 1 or more of the characters a-z, A-Z, 0-9, _ and -. Hence the regex [\w-]+.
If this is a new site then you can stop there. However, if you are changing an existing URL structure that has already been indexed by search engines and linked to by external third parties then you'll need to redirect the old URLs to the new. (Just to reiterate, you must have already changed the URL in your application, otherwise users will experience repeated redirects as they navigate your site.)
To implement the redirect, you can add something like the following before the above rewrite:
# Redirect any "stray" requests to the old URL
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ([\w-]+)
RewriteRule ^post/$ /post/%1 [R=302,NE,QSD,L]
The check against the REDIRECT_STATUS environment variable is to ensure we only redirect "direct requests" and thus avoiding a redirect loop.
(Change to 301 only when tested as OK, to avoid caching issues.)
In Summary:
RewriteEngine On
# Redirect any "stray" requests to the old URL
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ([\w-]+)
RewriteRule ^post/$ /post/%1 [R=302,NE,QSD,L]
# Rewrite /post/sometitle to filesystem path
RewriteRule ^post/([\w-]+)$ /post/index.php?$1 [L]
UPDATE: If you have multiple URLs ("folders") that all follow the same pattern, such as /post/<title>, /home/<title> and /build/<title> then you can modify the above to cater for all three, for example:
# Redirect any "stray" requests to the old URL
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ([\w-]+)
RewriteRule ^(post|home|build)/$ /$1/%1 [R=302,NE,QSD,L]
# Rewrite /post/sometitle to filesystem path
RewriteRule ^(post|home|build)/([\w-]+)$ /$1/index.php?$2 [L]
Aside: (With my Webmasters hat on...) This is not really much of an "improvement" to the URL structure. If this is an established website with many backlinks and good SE ranking then you should think twice about making this change as you could see a dip in rankings at least initially.
If only changing from query is your requirement then try with below, we are using QSD flag to discard our query string after our rule matched.
RewriteCond %{QUERY_STRING} ([^\s&]+) [NC]
RewriteRule ^ /post/%1 [R=302,L,NE,QSD]

Redirect All Unused Link on a subdomain to a domain

I want to redirect all the unused link in my subdomain.olddomain.com to newdomain.com
i tried this but it doesn't seem to work for subdomain
RewriteCond %{HTTP_HOST} !^subdomain\.olddomain\.com [NC]
RewriteRule ^/(.*) http://www.newdomain.com/$1 [L,R=301]
I manage to make the code below but the issue is it does not redirect or catch all the unused like. It only redirects the root and returns page error when accessing unused link(e.g. tag) An example url look like below (OsCommerce)
sub.domain.com/product_info.php?products_id=999&osCsid=29f8a9504d1c4de90a1a1e4106344280
RewriteCond %{HTTP_HOST} !^www\.newdomain\.com$ [NC]
RewriteRule ^(.*)$ http://www.newdomain.com/$1 [R=301,L]
Additional Info:
What I am trying to do is redirect all the link coming from subdomain.olddomain.com to newdomain.com so for example when someone visit subdomain.olddomain.com/tags/vanilla or subdomain.olddomain.com/product_info.php?products_id=999&osCsid=29f8a9504d1c4de90a1a1e4106344280m they will automatically be redirected to newdomain.com , the newdomain.com is located in another server server
From the documentation (emphasis mine):
Per-directory Rewrites
The rewrite engine may be used in .htaccess files and in sections, with some additional complexity.
To enable the rewrite engine in this context, you need to set "RewriteEngine On" and "Options FollowSymLinks" must be enabled. If
your administrator has disabled override of FollowSymLinks for a
user's directory, then you cannot use the rewrite engine. This
restriction is required for security reasons.
When using the rewrite engine in .htaccess files the per-directory prefix (which always is the same for a specific directory) is
automatically removed for the RewriteRule pattern matching and
automatically added after any relative (not starting with a slash or
protocol name) substitution encounters the end of a rule set. See the
RewriteBase directive for more information regarding what prefix will
be added back to relative substitutions.
If you wish to match against the full URL-path in a per-directory (htaccess) RewriteRule, use the %{REQUEST_URI} variable in a
RewriteCond.
The removed prefix always ends with a slash, meaning the matching occurs against a string which never has a leading slash. Therefore, a
Pattern with ^/ never matches in per-directory context.
Although rewrite rules are syntactically permitted in and sections (including their regular expression counterparts),
this should never be necessary and is unsupported. A likely feature to
break in these contexts is relative substitutions.
The .htaccess-file is per-directory context, so your rule will never ever match anything. Your rule should look like:
RewriteCond %{HTTP_HOST} !^subdomain\.olddomain\.com [NC]
RewriteRule ^(.*)$ http://www.newdomain.com/$1 [L,R=301]
This is assuming that newdomain.com does not use this .htaccess file, as that would cause an infinite redirect.

Redirect to fallback file if first attempt fails

I have this in my .htaccess:
RewriteRule ^images/([^/\.]+)/(.+)$ themes/current/images/$1/$2 [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^images/([^/\.]+)/(.+)$ modules/$1/images/$2 [L,NC]
The idea is that it does the following:
// Rewrite this...
images/calendar/gear.png
// ... to this
themes/current/images/calendar/gear.png
// HOWEVER, if that rewritten path doesn't exist, rewrite the original URL to this:
modules/calendar/images/gear.png
The only things that change here are calendar and gear.png, the first of which could be any other single word and the latter the file name (possibly with path) to an image file.
I can rewrite the original URL to the first rewrite as shown in the example just fine, but what I cannot do is get my .htaccess to serve up the file from the other, fallback location if the first location 404s. I was under the impression that not using [L] in my first RewriteRule would rewrite the URL for RewriteCond.
The problem I'm having is that instead of serving the fallback file, the browser just shows a 404 to the first rewritten path (themes/current/calendar/gear.png), instead of falling back to modules/calendar/gear.png. What am I doing wrong?
Please note that my regex isn't perfect, but I can refine that later. Right now I'm concerning myself with the rewrite logic itself.
Fallthrough rules are fraught with bugs. My general recommendation is than any rule with a replacement string other than - should trigger an internal redirect to restart the .htaccess parse. This avoids the subrequest and URI_PATH bugs.
Next once you go to 404, again in my experience this is unrecoverable. I have a fragment which does something similar to what you are trying to do:
# For HTML cacheable blog URIs (a GET to a specific list, with no query params,
# guest user and the HTML cache file exists) then use it instead of executing PHP
RewriteCond %{HTTP_COOKIE} !blog_user
RewriteCond %{REQUEST_METHOD}%{QUERY_STRING} =GET [NC]
RewriteCond %{ENV:DOCUMENT_ROOT_REAL}/blog/html_cache/$1.html -f
RewriteRule ^(article-\d+|index|sitemap.xml|search-\w+|rss-[0-9a-z]*)$ \
blog/html_cache/$1.html [L,E=END:1]
Note that I do the conditional test in filesystem space and not URI (Location) space. So this would map in your case to
RewriteCond %{DOCUMENT_ROOT}/themes/current/images/$1/$2l -f
RewriteRule ^images/(.+?)/(.+)$ themes/current/images/$1/$2 [L]
Though do a phpinfo() to check to see if your hosting provider uses an alternative to DOCUMENT_ROOT if it is a shared hosting offering e.g an alternative environment variable as mine uses DOCUMENT_ROOT_REAL.
The second rule will be picked up on the second processing past after the internal redirect.

Resources