htaccess not working but check successful localhost - apache

I have a simple .htaccessfile
DirectoryIndex index.php
RewriteEngine On
RewriteRule ^v4r.info/(.*)/(.*) v4r.info/NGOplus/index.php?NGO=$1&page=$2 [L,QSA]
I tested the file in htaccess.madewithlove.com, it gives a correct result and copy&pasting the result works flawlessly. (http://localhost/v4r.info/NGOplus/index.php?NGO=action-for-woman&page=board.list.php&ff=710;;;;;&startdate=2017-11-11)
But htaccess fails on localhost with an error:
File does not exist:
/var/www/html/public_html/v4r.info/action-for-woman/board.list.php
The test URL is
localhost/v4r.info/NGOplus/index.php?NGO=action-for-woman&page=board.list.php&ff=710;;;;;&startdate=2017-11-11
htaccess is active. (rubbish line gives "internal server error")
in another directory htaccess is working fine.
apache.conf seems ok (AllowOverride All)
Added:
The htaccess file is not in the base directory but in the 1. subdirectory (v4r.info).
What works is htaccess in v4r.info/NGOplus with a symlink 'action-for-woman' to NGOplus
RewriteRule ^(.+?)/?$ index.php?page=$1 [L,QSA]
Here, apache does a «local» rewrite, i.e. just the last part of the URL (the directory name 'action-for-woman' I have to extract from $_SERVER ...)

my .htaccess file is in v4r.info directory what is not the root directory.
In that case, your rule will never match. The RewriteRule pattern matches a URL-path relative to the directory that contains the .htaccess file.
But anyhow, rewriting is not recursive afaik.
Yes, it is "recursive" in a directory context (ie. .htaccess). In that the rewrite engine "loops" repeatedly until the URL passes through unchanged, or you have explicitly set END (Apache 2.4).
Try the following instead:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} !index\.php$
RewriteRule ^([^/]+)/([^/]+)$ /v4r.info/NGOplus/index.php?NGO=$1&page=$2 [L,QSA]
The check against the REDIRECT_STATUS environment variable is to ensure that only direct requests are rewritten and not already rewritten requests.
However, this pattern is still far too generic as it matches any two path segments. I put the 2nd condition that checks index.php just so you can request /v4r.info/NGOplus/index.php directly (as you were doing in your tests). However, this could be avoided by making the regex more specific.

Related

How can I create a redirect with .htaccess to correct path instead of page acess

I am making a multilingual dynamic site that creates a virtual path per language.
So french pages go to domain.com/fr/ english domain.com/en/page domain.com/fr/some/page but in reality these pages are in the base folder and /fr/ is converted to a query string.
This is all working with the following .htaccess:
RewriteEngine on
DirectorySlash Off # Fixes the issue where a page and folder can have the same name. See https://stackoverflow.com/questions/2017748
# Return 404 if original request is /foo/bar.php
RewriteCond %{THE_REQUEST} "^[^ ]* .*?\.php[? ].*$"
RewriteRule .* - [L,R=404]
# Remove virtual language/locale component
RewriteRule ^(en|fr)/(.*)$ $2?lang=$1 [L,QSA]
RewriteRule ^(en|fr)/$ index.php?lang=$1 [L,QSA]
# Rewrite /foo/bar to /foo/bar.php
RewriteRule ^([^.?]+)$ %{REQUEST_URI}.php [L]
My problem is that some sites (Like a Linkedin post) somehow remove the trailing / in the index page automatically. So if I put a link in my post of domain.com/fr/ somehow they make the link domain.com/fr even if it shows domain.com/fr/ but that 404's as domain.com/fr dosent exist.
So how can I redirect domain.com/fr to domain.com/fr/ or localhost/mypath/fr (There's many sites in my local workstation) to localhost/mypath/fr/.
I tried something like:
RewriteRule ^(.*)/(en|fr)$ $1/$2/ [L,QSA,R=301]
RewriteRule ^(en|fr)$ $1/ [L,QSA,R=301]
But that ended up somehow adding the full real computer path in the url:
localhost/mypath/fr becomes localhost/thepathofthewebserverinmypc/mypath/fr/
I would very much appreciate some help as I have yet to find the right rule.
Thank you
RewriteRule ^(en|fr)$ $1/ [L,QSA,R=301]
You are just missing the slash prefix on the substitution string. Consequently, Apache applies the directory-prefix to the relative URL, which results in the malformed redirect.
For example:
RewriteRule ^(en|fr)$ /$1/ [L,R=301]
The substitution is now a root-relative URL path and Apache just prefixes the scheme + hostname to the external redirect. (The QSA flag is unnecessary here, since any query string is appended by default.)
This needs to go before the existing rewrites (and after the blocking rule for .php requests).
Note that the "internal rewrite" directives are correct to not have the slash prefix.
Aside:
DirectorySlash Off
Note that if you disable the directory slash, you must ensure that auto-generated directory listings (mod_autoindex) are also disabled, otherwise if a directory without a trailing slash is requested then a directory listing will be generated (exposing your file structure), even though there might be a DirectoryIndex document in that directory.
For example, include the following at the top of the .htaccess file:
# Disable auto-generated directory listings (mod_autoindex)
Options -Indexes
UPDATE:
this worked on the production server. As the site is in the server root. Would your know how can I also try and "catch" this on my localhost ? RewriteRule ^(.*)/(en|fr)$ /$1/$2/ [L,R=301] dosent catch but with only RewriteRule ^(en|fr)$ /$1/ [L,R=301] localhost/mypath/fr becomes localhost/fr/
From that I assume the .htaccess file is inside the /mypath subdirectory on your local development server.
The RewriteRule pattern (first argument) matches the URL-path relative to the location of the .htaccess file (so it does not match /mypath). You can then make use of the REQUEST_URI server variable in the substitution that contains the entire (root-relative) URL-path.
For example:
RewriteRule ^(en|fr)$ %{REQUEST_URI}/ [L,R=301]
The REQUEST_URI server variable already includes the slash prefix.
This rule would work OK on both development (in a subdirectory) and in production (root directory), so it should replace the rule above if you need to support both environments with a single .htaccess file.

how do I rewrite a URL and maintain the file name

I have a rewrite written in my .htaccess file. I am trying to redirect the following
https://olddomain.com/folder/file.pdf to https://newdomain.com/folder/file.pdf. file.pdf can change so I need to change the domain but leave the folder and file name needs to stay what ever it is. it could be file.pdf or file1.pdf etc
I have this code in my .htaccess file
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/folder/(.*)$
RewriteRule ^(.*) https://newdomain.com/folder/%1 [R=301,NC]
If the file.pdf exists on the old server then the redirect works but if the file does not exist on the old server the redirect does not work.
Any help fixing this would be appreciated.
If the file.pdf exists on the old server then the redirect works but if the file does not exist on the old server the redirect does not work.
That sounds like you've put the rule/redirect in the wrong place. If you have other directives before this redirect that implement a front-controller pattern then you will experience this same behaviour since any request for a non-existent file would be routed to the front-controller (and request for an existing file is ignored) before your redirect is triggered - so no redirect occurs.
If this is the case then you need to move your rule to the top of the file, before any existing rewrites.
RewriteCond %{REQUEST_URI} ^/folder/(.*)$
RewriteRule ^(.*) https://newdomain.com/folder/%1 [R=301,NC]
However, your existing rule is not quite correct. Importantly, you are missing the L flag on the RewriteRule directive and the preceding RewriteCond directive is not required. For example, try the following instead:
RewriteRule ^folder/.* https://newdomain.com/$0 [NC,R=301,L]
This does assume your .htaccess file is located in the document root of the site.
Alternatively, you create an additional .htaccess file inside the /folder with the following:
RewriteEngine On
RewriteRule ^ https://newdomain.com%{REQUEST_URI} [R=301,L]
The REQUEST_URI server variable contains the full URL-path of the request (including the slash prefix).
By default, the mod_rewrite directives in the /folder/.htaccess file will completely override any directives in the parent (root) .htaccess file (the mod_rewrite directives in the parent are not even processed).

Windows 10 Xampp Apache - htaccess rewriterule not working

I am using apache XAMPP on Windows 10 and am trying to get htaccess working. I have this so far...
RewriteEngine On
RewriteRule ^noexist/?$ /folder/
I want someone to go to
www.mysite.com/noexist/test.php -> www.mysite.com/folder/test.php
But I still want the URL to be www.mysite.com/noexist/test.php
I am just getting a 404, where am I going wrong? I have confirmed the htaccess file is being loaded by putting invalid code in and it throws an error so I am certain the file is being used.
RewriteRule ^noexist/?$ /folder/
The regex ^noexist/?$ matches noexist or noexist/ only, so /noexist/test.php is ignored by this rule. It also only rewrites to /folder/ only.
In other words, this rewrites /noexist (or /noexist/) to /folder/ only.
To rewrite /noexist/<something> to /folder/<something> then you need to capture the <something> part and pass this through to the target URL (i.e the substitution string). For example:
RewriteRule ^noexist/(.*) /folder/$1 [L]
The $1 backreference in the substitution string contains the URL-path captured by the parenthesised subpattern (ie. (.*)) in the RewriteRule pattern.
Don't forget the L (last) flag. (This is important if you have other directives later in the file.)
Note that this rewrite is unconditional, regardless of whether /folder/<something> exists or not. If you want to check that /folder/<something> exists before rewriting then add an additional condition. For example:
RewriteCond %{DOCUMENT_ROOT}/folder/$1 -f
RewriteRule ^noexist/(.*) /folder/$1 [L]
This assumes your .htaccess file is located in the document root.

Apache does not rewrite request if file on path exists

I'm doing a rewrite with mod_rewrite on every request that does not match an existing file or directory. This is my configuration:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /index.php [NC,L]
This is used to map URLs like /abc/foo or /abc/foo/10 to my app. And it works just fine.
To improve the performance, my app now stores the results of a call to /abc/foo in a file foo in the corresponding directory /abc - so that after the first call the rewrite conditions do no longer apply (file does not exist) and apache directly serves the data without first invoking the app. Works fine as well.
The problem is: Requesting /abc/foo/10 does now no longer cause the URL to get rewritten, instead I get an error "404 File Not Found". The log entries state that the rewrite condition !-f is no longer true, but actually the file /abc/foo/10 does not exist. /abc/foo exists, but is a file, not a directory.
How can I get this to work?
(MultiViews is disabled)
This is because foo exists as a file and apache serves foo with the additional /10 passed as a query string. So, your application should write some additional code to the foo file, that also checks if a request includes some additional url component and then handle creation of the directory "foo" and the file 10.
You must be in per-dir/htaccess context w/ AcceptPathInfo on.
Therefore REQUEST_FILENAME matched the part that existed, and is not the same as REQUEST_URI.
Use the REQUEST_URI var if you don't care where the request was previously mapped in your rewritecond.
In per-vh context, these vars are always the same.
Project design is a little bit wrong - others already pointed out that it's not scallable - how could You cache a request to /abc/foo/10 if there is already a /abc/foo file?
Answer to that and to Your problem is usage of subfolders instead of files.
So instead of cache structure of:
/abc/foo
/abc/bar
...?
use:
/abc/index.html
/abc/foo/index.html
/abc/bar/index.html
/abc/foo/10/index.html
and each time create new directory with index.html
This time Apache would find out that there is /abc/foo folder but no /abc/foo/10 file in it, so RewriteCond will apply.
edit
You could also try a different way - to modify url with mod_rewrite, changing urls:
/abc/foo
/abc/bar
/abc/foo/10
to something like:
/cache/abc~foo
/cache/abc~bar
/cache/abc~foo~10
htaccess rules (roughly):
# redirecting to cache folder and removing last '/'
RewriteCond %{REQUEST_URI} ^/(abc|cde)
RewriteRule ^(.*?)/?$ /cache/$1 [L]
# recursive replacing '/' with '~'
RewriteCond %{REQUEST_URI} ^/cache/.*/
RewriteRule cache/(.*)/(.*)$ /cache/$1~$2 [L]
Your standard htaccess rules should follow

mod_rewrite is ignoring rules in subdirectories

Wanted rewrite behaviour (internal rewrite!)
http://<subdomain>.domain.tld/<path> -> /<subdomain>/<path>
http://www.domain.tld/path/file.php -> /www/path/file.php
http://project.domain-tld/index.php -> /project/index.php
Folder structure:
/ root
.htaccess
/www www.domain.tld
index.php
/www
file.php
/foo
/bar
file.php
/project project.domain.tld
index.php
someRandomFiles
/somesubdomain somesubdomain.domain.tld
index.php
someRandomFiles
/anothersubdomain anothersubdomain.domain.tld
index.php
someRandomFiles
Full .htaccess
# Unicode
AddDefaultCharset utf-8
# Activate mod_rewrite
RewriteEngine on
RewriteBase /
# Subdomains
# Extract (required) subdomain (%1), and first path element (%3), discard port number if present (%2)
RewriteCond %{HTTP_HOST}<>%{REQUEST_URI} ^([^.]+)\.janbuschtoens\.de(:80)?<>/([^/]*) [NC]
# Rewrite only when subdomain not equal to first path element (prevents mod_rewrite recursion)
RewriteCond %1<>%3 !^(.*)<>\1$ [NC]
# Rewrite to /subdomain/path
RewriteRule ^(.*) /%1/$1 [L]
My .htaccess seems to work. You can live test it here:
http://test.janbuschtoens.de/
rewrites to /test/
http://www.janbuschtoens.de/
rewrites to /www/
But there is some strange behaviour in subdirectories. mod_rewrite seems to ignore the rule if the first directory in the requested path has the same name as the subdomain itself. For example:
http://www.domain.tld/foo/bar/file.php -> /www/foo/bar/file.php - Fine!
http://www.domain.tld/ -> /www/ - Fine!
http://www.domain.tld/www/ -> /www/ - Should be: /www/www/
http://www.domain.tld/www/www/ -> /www/www/ - Should be: /www/www/www/
For another live test:
http://test.janbuschtoens.de/ rewrites to /test/
http://test.janbuschtoens.de/test/ rewrites to /test/
It seems like the rule gets ignored.
This is the only good rule that I was able come up with, otherwise after initial rewriting (which is very easy) it goes into the loop (and that is the problem). For example: www.domain.com/www/123.png gets properly redirected into /www/www/123.png, but then goes to the next loop, where it get's redirected to /www/www/www/123.png and then again and again.
This rule ONLY gets invoked if FINAL filename DOES EXIST.
RewriteCond %{HTTP_HOST} ^(.+)\.domain\.com$
RewriteCond %{DOCUMENT_ROOT}/%1/$1 -f [OR]
RewriteCond %{DOCUMENT_ROOT}/%1/$1 -d
RewriteRule ^(.*)$ /%1/$1 [QSA,L]
For example: if you request www.domain.com/www/123.png, and file/folder WEBSITEROOT/www/www/123.png exist, then it will be rewritten, otherwise nothing.
The same here: if you request meow.domain.com/ .. but have no WEBSITEROOT/meow/ folder on your drive, it gets nowhere.
Please note, this still will not help much if you have subfolder with the same name as subdomain. For example: if you request www.domain.com it should be rewritten to WEBSITEROOT/www/ ... but if you also have WEBSITEROOT/www/www/ then (because of loop) it will be rewritten to WEBSITEROOT/www/www/ instead.
Unfortunately I have not found the way how to bypass it. If you wish -- you can try combining your rules with mine.