mode_rewrite (.htaccess) wrong outcome - .htaccess

I'm not sure what's wrong. I use massively rewrite on to domain with various rules with no problem, now here on subdomain the rewritten result point wrong data.
The space is accessible from multiple domains, and I want to switch by hostname to specific subfolder for CSS contents:
RewriteEngine on
# - - - shared space / multiple css.*.tld subdomains - - -
# domain 1
RewriteCond %{HTTP_HOST} ^css\.firstdomain\.com$
RewriteRule ^css/(.*)$ fir/$1
# domain 2
RewriteCond %{HTTP_HOST} ^css\.seconddomain2\.com$
RewriteRule ^css/(.*)$ sec/$1
# *.min.css -> scss.php?file=*
RewriteRule ^(.+)\.min\.css$ scss.php?scss=$1 [QSA]
#
First there are rules to rewrite universal /css/ path to path specific for files for that host, then last line should change *.min.css to scss.php?scss=$1 - so it send the file /without the extension .min.css/ as parameter to php file which then searches for that file with .scss extension to check last modified and either return cached or recompile the source scss file to cached css file
Now I'd expect when I enter: http://css.firstdomain.com/css/first/first.min.css
should rewrite to: http://css.firstdomain.com/scss.php?file=fir/first/first.min.css
but it rewrites to: http://css.firstdomain.com/scss.php?file=fir/first/first.min.css/first/first
So it rewrites it like almost twice for some reason. What might be the reason for this?
There will be problem of some kind with the firs part as entering straight http://css.firstdomain.com/fir/first/first.min.css
rewrites to correct (scss.php?file=fir/first/first).

Oooh found it! I missed the [L] (last) flag after rules for each domain, now it works like it should
For completeness, here is the code:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^css\.firstdomain\.com$
RewriteRule ^css/(.*)$ fir/$1 [QSA,L]
RewriteRule ^(.+)\.min\.css$ scss.php?scss=$1 [QSA,L]

Related

How to rewrite directory for multiple level directories

This is my .htaccess
RewriteEngine On
# browser requests PHP
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^\ ]+)\.php
RewriteRule ^/?(.*)\.php$ /$1 [L,R=301]
# check to see if the request is for a PHP file:
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^/?(.*)$ /$1.php
RewriteCond %{REQUEST_URI} !^/(views|css|js|media|partials|php)
RewriteRule (.*) /views/$1
This is my project structure:
The idea is that all my HTML files are structured in the folder views, but I don't want my URL to be http://example.com/views/index but just http://example.com/index without the views-part.
This is working fine in the following case:
http://example.com/account/
But fails as soon as I try to access a file in the accounts-folder e.g: http://example.com/account/voeg-kind-toe
That results in a 404. Seems like this .htaccess solution only works for one-level directories.
Edit:
Interesting: If I place the bottom two lines on top (so placing the code to rewrite the view-part before the code to remove the php-extension); the php-extension works but the /views//part don't.
Create .htaccess like this
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteCond %{REQUEST_URI} !^/views/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /views/$1
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteRule ^(/)?$ views/ [L]
As mentioned in my comment above, providing there are no other directives/conflicts then this should still "work" in a roundabout way. However, there is an issue with the following directive in the order you have placed it:
# check to see if the request is for a PHP file:
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^/?(.*)$ /$1.php
You aren't testing for files in the /views subdirectory. But also, REQUEST_FILENAME does not necessarily contain what (I think) you think it does. When you request /account/voeg-kind-toe (an entirely virtual URL path) then REQUEST_FILENAME contains /account (it actually contains an absolute filesystem path, but I've kept it brief). So, the above is testing whether /account.php exists, not /account/voeg-kind-toe.php, or even /views/account/voeg-kind-toe.php - which is presumably the intention.
So, on the first pass, the above condition fails, no rewrite occurs, and processing continues...
The second rule then rewrites the request for /account/voeg-kind-toe to /views/account/voeg-kind-toe. Providing there are no further mod_rewrite directives, the rewrite engine then starts over. This time, /views/account/voeg-kind-toe is the input.
On the second pass, REQUEST_FILENAME is /views/account/voeg-kind-toe (since /views/account is a physical directory) and the request is rewritten to /views/account/voeg-kind-toe.php (since the filesystem check should be successful). Providing you have no other directives then processing should now stop.
This is working fine in the following case: http://example.com/account/
/account/ is simply rewritten to /views/account/ by the last rule.
Edit: Interesting: If I place the bottom two lines on top (so placing the code to rewrite the view-part before the code to remove the php-extension); the php-extension works but the /views//part don't.
The same process as above occurs, EXCEPT this all occurs in a single pass and so is less dependent on other directives that might occur later in the file.
I'm not sure what you mean by "the /views//part don't"?
Assuming you only have .php files within the /views directory and all URLs are intended to target the /views subdirectory and you don't need to reference directories directly then you could do this is a single directive and rewrite everything that does not contain (what looks like) a file extension to /views/<whatever>.php.
For example:
RewriteRule !\.\w{2,4}$ /views%{REQUEST_URI}.php [L]
The L (last) flag is required if you have other mod_rewrite directives that follow - to prevent additional processing.
This does mean you can't rely on the directory index. ie. You need to request /index (as in your example), not simply / to serve /views/index.php.
(You still need your first rule that removes .php from the requested URL - although this is only strictly necessary if you are changing an existing URL structure, where you previously used .php on the URLs.)

.htaccess subdomain Rewrite rule is not working

I am making a website builder an I would like to make urls prettier.
The url would be for example:
https://ccc-bb.example.com => https://example.com/project/show/ccc/bb
This is my .htaccess file:
<IfModule mod_rewrite.c>
RewriteEngine On
# prevents files starting with dot to be viewed by browser
RewriteRule /\.|^\.(?!well-known/) - [F]
# front controller
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)\-(.*)$ https://example.com/project/show/$1/$2 [L]
When I use above (https://ccc-bb.example.com) it sends me to the subdomain empty folder. The folder has only the .htaccess file.
What am I missing? I've never edited an .htaccess file and Google didn't help me (or I don't know what should I looking for).
Your first rule for dotfiles is okay but would be better the other way around, since the second part can only match the start, but the first can only match in subdirectories.
RewriteRule ^\.(?!well-known/)|/\. - [F]
Your other rule's problem is that you are expecting it to match the subdomain. RewriteRules do not operate on the entire string you see in your browser's address bar, only the path part, and in .htaccess they see even less as the leading directory is stripped off, too. To access the info you want, use a RewriteCond:
RewriteCond %{HTTP_HOST} ^([^-]++)-([^-.]++)\.example\.com$
RewriteRule ^(?!project/show/).* project/show/%1/%2/$0 [L,DPI]
(You don't need to include \.example\.com$ if your main domain contains no hyphens.)

htaccess subdomain rewrite without a redirect

Using htaccess Rewrite, I want my url http://*.phoneataxi.com/ (where * is a wildcard, excluding 'www') to show in the address bar as is but get information from http://*.phoneataxi.com/test.php?c=*.
I have tried so many different things but nothing is doing exactly what I need. Most examples are redirecting the subdomain to the '/test.php' file in the address bar which I don't want to do.
I'm trying not to have to create individial subdomains and subdomain folders within my webroot.
Ideas?
I use this htaccess file to make Apache act as a proxy for another host:
IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} ^ghost\.pileborg\.se$
RewriteRule (.*) http://vps.pileborg.se/ghost/$1 [P]
</IfModule>
It causes all access to http://ghost.pileborg.se/ to be "redirected" to http://vps.pileborg.se/ghost/.
UPDATE (2020)
Some of the answers regarding this topic is very old and no longer work as expected.
After searching for hours on something that actually works, this is what I came up with; edit as you see fit:
RewriteEngine on
RewriteBase /
RewriteCond %{HTTP_HOST} ([a-z0-9]+)\.
RewriteRule ^(.*)$ - [E=BASE:%1]
RewriteCond %{DOCUMENT_ROOT}/%{ENV:BASE}/index.php -f
RewriteRule ^(.*)$ %{ENV:BASE}/index.php [L,NC,QSA]
RewriteCond %{DOCUMENT_ROOT}/%{ENV:BASE}/index.html -f
RewriteRule ^(.*)$ %{ENV:BASE}/index.html [L,NC,QSA]
Breakdown
Make sure that the rewrite module is installed and enabled on your host
first we turn the rewrite engine on and set the path-base
then isolate the subdomain - any letters/numbers before the first dot
set a variable in this runtime environment that contains the subdomain
check if the subdomain folder and index-file exists
if it does exist -then use that file as the request-handler (no redirect)
if it does not exist then the request carries on normally
Flags
The flags used here are explained here, but the ones used above are quite simple:
[L] Last rule, ignore the rest
[NC] No Case, no uppercase/lowercase restrictions
[QSA] I remember this as "Query String Attach" :D

htaccess - rewrite URL to make querystring nice

I have a site with a folder, and a htaccess file within that folder. For the index.php file within that folder, I want to rewrite the querystring for a certain parameter, so that typing in this URL:
www.example.com/myfolder/myparameter
Behaves like this (ie makes $_GET['parameter'] = 'myparameter' in my code)
www.example.com/myfolder/index.php?parameter=myparameter
I have looked at many questions on StackOverflow, but have not managed to get this working. My code so far is
RewriteEngine on
RewriteCond %{QUERY_STRING} ^(.*) [NC]
RewriteRule ^$ %0 [QSA]
But that just isn't working at all.
Please use this code
RewriteEngine on
RewriteRule (.*) index\.php?parameter=$1 [L,QSA]
RewriteEngine on
RewriteRule (^.*/)([^/]+)$ $1index\.php?parameter=$2 [L,QSA]
update
sorry use #somasundaram's answer. Per-directory .htaccess rewrite rules lose the directory prefix:
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.
(from the apache docs)

How do I get the [L] flag of RewriteRule (.htaccess) really working?

To newcomers: While trying to comprehensively describe my problem and phrase my questions I produced huge ammount of text. If you don't want to read the whole thing, my observations about (read "proof of") [L] flag not working the misconception, from which it all sprung, is located in Additional observations section. Why I misunderstood apparent behaviour is described in my Answer as well as solution to given problem.
Setup
I have following code in my .htaccess file:
# disallow directory indexing
Options -Indexes
# turn mod_rewrite on
Options +FollowSymlinks
RewriteEngine on
# allow access to robots file
RewriteRule ^robots.txt$ robots.txt [NC,L]
# mangle core request handler address
RewriteRule ^core/(\?.+)?$ core/handleCoreRequest.php$1 [NC,L]
# mangle web file adresses (move them to application root folder)
# application root folder serves as application GUI address
RewriteRule ^$ web/index.html [L]
# allow access to images
RewriteRule ^(images/.+\.(ico|png|bmp|jpg|gif))$ web/$1 [NC,L]
# allow access to stylesheets
RewriteRule ^(css/.+\.css)$ web/$1 [NC,L]
# allow access to javascript
RewriteRule ^(js/.+\.js)$ web/$1 [NC,L]
# allow access to library scripts, styles and images
RewriteRule ^(lib/js/.+\.js)$ web/$1 [NC,L]
RewriteRule ^(lib/css/.+\.css)$ web/$1 [NC,L]
RewriteRule ^(lib/(.+/)?images/.+\.(ico|png|bmp|jpg|gif))$ web/$1 [NC,L]
# redirect all other requests to application address
# RewriteRule ^(.*)$ /foo/ [R]
My web application (and its .htaccess file) is located in foo subfolder of DOCUMENT_ROOT (accessed from browser as http://localhost/foo/). It has PHP core part located in foo/core and JavaScript GUI part located in foo/web. As can be seen from the code above, I want to allow access only to single core script that handles all requests from GUI and to 'safe' web files and redirect all other requests to base application address (last commented directive).
Problem
Behaviour
It works until I try the last part by uncommenting the last redirecting directive. If I comment some more lines, the appropriate page parts stop working, etc.
However, when I uncomment last line, which should be performed only when matching of all previous rules fails (at least that's what I understand), page goes into redirection cycle (Firefox throws error page with something like "This page isn't redirecting properly"), because it's redirecting to http://localhost/foo/ again and again and again, forever.
Questions
What I don't understand is this processing of this rule:
RewriteRule ^$ web/index.html [L],
specifically the [L] flag. The flag apparently doesn't work for me. When the last line is commented, it correctly redirects, but when I uncomment it, it is always processed, even though rewriting should stop on [L] flag. Anyone got any ideas?
Also, on a sidenote, I'd be thrilled to know why my following attempt at fixing it doesn't work either:
RewriteEngine on
RewriteRule ^core/(\?.+)?$ core/handleCoreRequest.php$1 [NC,L]
RewriteRule ^(.*)$ web/$1 [L]
RewriteRule ^.*$ /foo/ [L]
This actually doesn't work at all. Even if I remove the last line, it still doesn't redirect anything correctly. How does the redirecting work in the first example, if it doesn't work in the second?
It would also be of great benefit to me, if anybody knew any way to actually debug these directives. I spend hours on this without even the slightest clue what could possibly be wrong.
Additional observations
After trying the advice given by bbadour (not that I haven't tried it before, but now that I had a second opinion, I gave it another shot) and it didn't work, I've come up with the following observation. By rewriting last line to this:
RewriteRule ^(.*)$ /foo/?uri=$1 [R,L]
or this
RewriteRule ^(.*)$ /foo/?uri=%{REQUEST_URI} [R,L]
and using Firebug's Net panel, I found out more evidence, that the [L] flag is clearly not working as expected in the previously mentioned RewriteRule ^$ web/index.html [L] rule (let's call it THE RULE from now on). In first case I get [...]uri=web/index.html, in second case [...]uri=/foo/web/index.html. That means that THE RULE gets executed (rewrites ^$ to web/index.html), but the rewriting doesn't stop there. Any more ideas, please?
After hours of searching and testing, I finally found the real problem and solution. Hopefully this will help somebody else too, when they come across the same problem.
Cause of observed behavior
.htaccess file is processed after every redirect (even without [R] flag),
which means that after the RewriteRule ^$ web/index.html [L] is processed, mod_rewrite correctly stops rewriting, goes to the end of the file, redirects correctly to /foo/web/index.html, and then the server starts processing .htaccess file for the new location, which is the same file. Now only the last rewrite rule matches and redirects back to /foo/ (this time with [R], so the redirect can be observed in browser) ... and the .htaccess file is processed again, and again, and again...
Once more for clarity: Because only the hard redirects can be observed, it seems like the [L] flag is ignored, but it is not so. Instead, the .htaccess is processed two times redirecting back and forth between /foo/ and /foo/web/index.html.
Solution
Disallow direct access to subfolder
To virtually move subdirectory to application root directory, additional complex conditional rewrites must be used. Variable THE_REQUEST is useful for distinguishing between hard and soft redirects:
RewriteCond %{THE_REQUEST} ^GET\ /foo/web/
RewriteRule ^web/(.*) /foo/$1 [L,R]
For this rewrite rule to be matched, two conditions must apply. First, on second line, the "local URI" must start with web/ (which corresponds with absolute web URI /foo/web/). Second, on first line, the real request URI must start with /foo/web/ too. Together this means, that the rule only matches when the file inside the web/ subfolder is requested directly from the browser, in which case we want to do a hard redirect.
Redirect to allowed content from root to subfolder (soft)
RewriteCond $1 !^web/
RewriteCond $1 ^(.+\.(html|css|js|ico|png|bmp|jpg|gif))?$
RewriteRule ^(.*)$ web/$1 [L,NC]
We want to redirect to allowed content only if we haven't done it already, hence the first condition. Second condition specifies mask for allowed content. Anything matching this mask will be softly redirected, possibly returning 404 error if the content doesn't exist.
Hide all content not in subfolder or not allowed
RewriteRule !^web/ /foo/ [L,R]
This will do a hard redirect to application root for all URIs not beginning with web/ (and remember, only requests that can begin with web/ at this point are internal redirects for allowed content.
Real example
My code shown in my "question" after using solution tips mentioned above gradually transformed into the following:
# disallow directory indexing
Options -Indexes
# turn mod_rewrite on
Options +FollowSymlinks
RewriteEngine on
# allow access to robots file
RewriteRule ^robots.txt$ - [NC,L]
# mangle core request handler address
# disallow direct access to core request handler
RewriteCond %{THE_REQUEST} !^(GET|POST)\ /asm/core/handleCoreRequest.php
RewriteRule ^core/handleCoreRequest.php$ - [L]
# allow access to request handler under alias
RewriteRule ^core/$ core/handleCoreRequest.php [NC,QSA,L]
# mangle GUI files adressing (move to application root folder)
# disallow direct access to GUI subfolder
RewriteCond %{THE_REQUEST} ^GET\ /foo/web/
RewriteRule ^web/(.*) /foo/$1 [L,R]
# allow access only to correct filetypes in appropriate locations
RewriteCond $1 ^$ [OR]
RewriteCond $1 ^(images/.+\.(ico|png|bmp|jpg|gif))$ [OR]
RewriteCond $1 ^(css/.+\.css)$ [OR]
RewriteCond $1 ^(js/.+\.js)$ [OR]
RewriteCond $1 ^(lib/js/.+\.js)$ [OR]
RewriteCond $1 ^(lib/css/.+\.css)$ [OR]
RewriteCond $1 ^(lib/(.+/)?images/.+\.(ico|png|bmp|jpg|gif))$
RewriteRule ^(.*)$ web/$1 [L,NC]
# hide all files not in GUI subfolder that are not whitelisted above
RewriteRule !^web/ /foo/ [L,R]
What I don't like about this approach is that the application root folder must be hardcoded in .htaccess file (as far as I know), so the file must be generated on application install, not simply copied.
To debug, try simplifying your regex, and the url you ask for (a part of the full url you wanna match), and see if it's working, now step by step, add more bits to the regex adn the testing url, till you find where things are stopping to work properly.
Try using:
RewriteRule ^(.*)$ /foo/ [R,L]
If it still loops, put a RewriteCond in front of it to skip the rule if it is already /foo/

Resources