Apache ModRewrite Working in vhost but not .htaccess - apache

I have the following mod rewrites:
RewriteEngine On
# rest api rewrites
RewriteCond %{REQUEST_URI} /api/v [NC]
RewriteRule ^(.*)$ /index.php/$1 [L,QSA]
# main application rewrite
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteRule ^/[a-zA-Z0-9\-\_/]+?$ /index.html [L,QSA]
When I put these into my vhost config, everything works as excepted however when I put this into my .htaccess file, the first rewrite does an infinite loop (the log show an INTERNAL REWRITE) and the second rewrite doesn't work at all.
Why would these rewrites would in the vhost but not my .htaccess file?

The first rule loops because your target matches the regex, so once it rewrites the first time and the rules loop, the ^(.*)$ matches the URI that you've just rewritten to (/index.php/etc...`), so it causes an infinite loop (or loops as many times as the internal redirect limit is configured to). You need to add a condition to prevent the looping:
# rest api rewrites
RewriteCond %{REQUEST_URI} !^/index\.php
RewriteCond %{REQUEST_URI} /api/v [NC]
RewriteRule ^(.*)$ /index.php/$1 [L,QSA]
The second rule doesn't get applied at all because the URI being put through rules in an htaccess file has the leading slash stripped off (because htaccess is essentially like a <Directory> in vhost/server config), so you need to at least make that leading slash optional:
# main application rewrite
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteRule ^/?[a-zA-Z0-9\-\_/]+?$ /index.html [L,QSA]

Related

For specific url 'www.example.com/mobile' I want url rewrite to another specific path: 'root_folder/mobile/index.html'

I created a website in Symfony and the mobile version in Ionic.
Now all URLs are redirected to /public/index.php.
I want to add another URL rewrite in .htaccess to redirect all www.example.com/mobile/* to ionic app that is in the root folder /mobile/index.html.
I already tried to add this in root_folder/mobile/.htaccess
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/mobile/.*$
RewriteRule ^mobile/(.*)$ /mobile/index.html [R=301,NC,L]
My root_folder .htaccess is:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteCond %{REQUEST_URI} !^/public/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /public/$1
RewriteCond %{HTTP_HOST} ^(www.)?example.ch$
RewriteCond %{REQUEST_URI} !\.(gif|jpe?g|png|svg|webp|mp4|css|js|txt)$
RewriteRule ^(.*)?$ public/index.php [L]
<If "%{REQUEST_URI} =~ m#/mobile/?#i">
RewriteCond %{REQUEST_URI} !^/mobile/.*$
RewriteRule ^mobile/(.*)$ /mobile/index.html [R=301,NC,L]
</If>
RewriteCond %{REQUEST_URI} !^/mobile/.*$
RewriteRule ^mobile/(.*)$ /mobile/index.html [R=301,NC,L]
The RewriteRule pattern matches against the URL-path relative to the directory that contains the .htaccess file. So, the above RewriteRule will never match when inside the /mobile/.htaccess file. Likewise, the condition will never be successful, since if the .htaccess is triggered then /mobile/ must already be present in the URL-path.
This is also an external 301 redirect, not an internal rewrite. It needs to be an internal rewrite (just like the rewrite to public/index.php in the root).
However, presumably you also want static assets to be ignored and served directly, so you need exceptions for files (and optionally directories), just as you are doing in the root .htaccess file (when rewriting to public/index.php).
Try the following instead, in the /mobile/.htaccess file:
# /mobile/.htaccess
RewriteEngine On
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.html [L]
You don't need to specify /mobile in any of the directives since the RewriteRule pattern matches against the relative URL-path (as mentioned above) and the substitution string is (by default) relative to the directory that contains the .htaccess file.
By default, the mod_rewrite directives in the /mobile/.htaccess file completely override the directives in the parent .htaccess file. The directives in the parent .htaccess file are not even processed.
<If "%{REQUEST_URI} =~ m#/mobile/?#i">
RewriteCond %{REQUEST_URI} !^/mobile/.*$
RewriteRule ^mobile/(.*)$ /mobile/index.html [R=301,NC,L]
</If>
You should remove this <If> block in the root .htaccess file. (It's not actually doing anything.)

Apache mod_rewrite for SEO urls, but rewrite to 404 if file doesn't exist

I'm unable to find the answer for this, so please let me know if it's been resolved before.
I'm using mod_rewrite to do "pretty" URLs, but if you request a file that doesn't exist (like, a typo) it will redirect and add .php a bunch of times and then fail. The code I have below:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ http://inquisito.rs/$1/ [R=301,l]
RewriteRule ^(.*)/$ /$1.php [L]
So if you go to http://inquisito.rs/aion/ it will show you the aion page, but if you go to, lets say, inquisito.rs/aio/ on accident, it gives this
http://inquisito.rs/aio.php.php.php.php.php.php.php.php.php.php.php.php.php.php.php.php.php.php.php.php/
Thanks in advance, I can't tell you how many times I've used information from here to resolve issues at work and at home.
Using the example you've given, this is how the rules are applied:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f # /aio/ is not a file, so this matched
RewriteCond %{REQUEST_URI} !(.*)/$ # This DOES NOT match, because you have a trailing slash
RewriteRule ^(.*)$ http://inquisito.rs/$1/ [R=301,L] # This rule doesn't run, because the condition above wasn't met
# This rule is separate from the RewriteConds above
RewriteRule ^(.*)/$ /$1.php [L] # This does match because of the lack of RewriteConds and because you have a trailing slash
Try this (untested) set of rules instead:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f # Make sure no matching file exists
RewriteCond %{REQUEST_URI} !\.php$ # Don't match requests that already end .php
RewriteCond %{REQUEST_URI} !(.*)/$ # Check for missing trailing slash
RewriteRule ^(.*)$ http://inquisito.rs/$1/ [R=301,L] # Redirect with trailing slash
# Separate rule
RewriteCond %{REQUEST_URI} !\.php$ # Don't match requests that already end .php
RewriteRule ^(.*)/$ /$1.php [L] # Internal redirect to matching PHP file
It's important to note that all matching RewriteRules cause a new request to be processed by htaccess again.

.htaccess redirect to WWW with current htaccess code?

I want to redirect my URLs to the www version. I can do this, but I already have working .htaccess code that is redirecting the browser to my index.php file where the URL is processed. I have this code (which I did not write), and I do not know enough about htaccess to figure the problem out:
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(.*)$ /index.php [NC]
I have tried simply using the full URL path in the redirect, but this produces a 404 error when I attempt to access pages. I have also attempted to simply include more rules underneath this code, with no success.
Do you mean you want http://example.com/foo/bar to redirect to http://www.example.com/foo/bar?
If so, this should do the trick, while preserving your intent
RewriteEngine On
# First redirect non-www hosts (the "L" flag means we won't process
# any more rewrite conditions in this redirect; on the next request,
# the rewrite condition won't match and we'll fall through to your
# original rule)
RewriteCond %{HTTP_HOST} !^www\.(.*) [NC]
RewriteRule ^(.*)$ http://www.yourdomain.com/$1 [R=301,NC,L]
# Handle normal requests
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(.*)$ /index.php [NC]:

Apache Rewrite Rules - Path Style

I am coming from the IIS world to Apache and would appreciate some help on the rewrite rules.
I want this relative path:
/index.php?go=order&id=12345
to be rewritten as:
/go/order/id/12345
Also, if there are more parameters, they should be converted to path format:
/index.php?go=order&id=12345&action=process
becomes
/go/order/id/12345/action/process
How do I achieve this please? Thanks for any input.
Try putting this in your vhost config:
RewriteEngine On
# Start converting query parameters to path
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.php\?[^\ ]+
RewriteCond %{QUERY_STRING} ^([^=]+)=([^&]+)&?(.*)$
RewriteRule ^(.*)$ $1/%1/%2?%3 [L]
# done converting, remove index.php and redirect browser
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.php\?[^\ ]+
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^/index.php/(.*)$ /$1 [R=301,L]
# internally rewrite paths to query strings
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/index\.php
RewriteRule ^/([^/]+)/([^/]+)/?(.*) /$3?$1=$2 [L,QSA]
# No more path, rewrite to index.php
RewriteRule ^/$ /index.php [L]
These rules will make it so if you type in a URL like http://yourdomain.com/index.php?a=b&1=2&z=x in your browser, the browser will get redirected to http://yourdomain.com/a/b/1/2/z/x. When the clean looking URL gets requested, the 2nd set of rules internally rewrites it back to /index.php?a=b&1=2&z=x. If you want to put these rules in an htaccess file (in your document root), you need to remove all the leading slashes in the RewriteRule's. So ^/ needs to be ^ in the last 3 rules.
Note that if you simply go to http://yourdomain.com/index.php, without a query string, nothing gets rewritten.

trailing slashes in 301 redirect

I've tried to look through the multiple mod_rewrite questions, so I apologize if this is a duplicate.
I'm trying set it so that if you go to domain.com/about.php it removes .php and if you go to domain.com/about it simply remains like that.
Options +FollowSymlinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ /$1.php [L,QSA]
RewriteRule ^(.*)/$ /$1 [L,R=301]
So, right now if you go to domain.com/about it displays the page, but if you go to domain.com/about.php it doesn't remove the extension.
Additionally, I have 301 redirects
redirect 301 /our-clients http://www.domain.com/about-ourclients
That works perfect, but if the user goes to domain.com/our-clients/ with the trailing slash, they are directed to about-ourclients.php
Any advice on how to rewrite my rules?
This should do the job:
Options +FollowSymlinks
RewriteEngine On
RewriteBase /
# remove .php ONLY if requested directly
RewriteCond %{THE_REQUEST} (\.php\sHTTP/1)
RewriteRule ^(.+)\.php$ /$1 [R=301,L,QSA]
# remove trailing slash ONLY if it is not an existing folder
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# rewrite to FILENAME.php if such file does exist and is not a folder
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ /$1.php [L,QSA]
It will redirect all direct requests to php files: /something.php will be redirected to /something
Will remove the trailing slash IF requested resource is not directory. So if you requesting /home/ and you do have such folder, then it will NOT be redirected to /home.
Will internally rewrite requests to the same named PHP file IF it does exist. If you are requesting /about and you have /about.php then it will do rewrite; If you have no /about.php then nothing happens (well, at least not on these rules -- if you have more rules then such request can be matched later .. or 404 error page will be shown).
If you are requesting /about, you have /about.php and you also have /about folder, then request will go into folder. If you do not want this to happen ( /about should always be rewritten to /about.php) then you need to remove RewriteCond %{REQUEST_FILENAME} !-d from last block. But since you have exactly the same condition in your current .htaccess then I assume it is desired behaviour.