mod_rewrite for URL with more than one variable - .htaccess

Hi i'm trying to follow Mod_Rewrite for URL with multiple variables and edit it to suit my website but have a bit of a problem i have searched across the internet and could not really find anything which helps
I'm trying to turn example.com/editor/windows/chrome into this example.com?app=editor&os=windows&browser=chrome
Any ideas?
my current .htaccess file:
# Various rewrite rules.
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([a-zA-Z0-9_-]+)/?$ index.php?app=$1 [QSA]
RewriteRule ^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/?$ index.php?app=$1&os=$2&browser=$3 [QSA]
</IfModule>
I can get it to part work up-to example.com/editor/windows but can't get the third to include the browser

Your third rule doesn't include a capture group for the browser. This statement is missing:
RewriteRule ^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)$ index.php?app=$1&os=$2&browser=$3 [QSA]
RewriteRules are applied from top to bottom until [L] is found. Thus, in your question both rules are applied (which might casue bad performance).
A more clean version would be,
# Various rewrite rules.
<IfModule mod_rewrite.c>
RewriteEngine on
# don't rewrite URLs for existing files, directories or links
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule .* - [L]
# now match the URIs according to OP needs
# Redirect example.com/editor and example.com/editor/ to example.com/index.php?app=editor and stop after this rule
RewriteRule ^([a-zA-Z0-9_-]+)/?$ index.php?app=$1 [QSA,L]
# Redirect example.com/editor/windows and example.com/editor/windows/ to example.com/index.php?app=editor&os=windows and stop after this rule
RewriteRule ^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/?$ index.php?app=$1&os=$2 [QSA,L]
# Redirect example.com/editor/windows/chrome and example.com/editor/windows/chrome/ to example.com/index.php?app=editor&os=windows&browser=chrome and stop after this rule
RewriteRule ^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/?$ index.php?app=$1&os=$2&browser=$3 [QSA,L]
</IfModule>
However, the last three RewriteRule rules can also be compiled to one:
RewriteRule ^([a-zA-Z0-9_-]+)(?:/([a-zA-Z0-9_-]+)(?:/([a-zA-Z0-9_-]+)))/?$ index.php?app=$1&os=$2&browser=$3 [QSA,L]

As long as you don't mind having blank $_GET[] variables, you can reduce it all down to a single rule. Also not that you have 2 conditions that check for !-f and !-d. Those conditions only apply to the immediately following rule, and will not apply to any other rules unless you duplicate the condition.
So you can try:
# Various rewrite rules.
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([a-zA-Z0-9_-]+)(?:/([a-zA-Z0-9_-]+)|)(?:/([a-zA-Z0-9_-]+)|)/?$ index.php?app=$1&os=$2&browser=$3 [L,QSA]
</IfModule>

Related

Multiple rewrite rules in htaccess file causing conflicts

I've been working on a new set of htaccess rewrite rules for a module I am creating. The htaccess file already has some rules for the PHP-based application and those rules are now broken. I am wondering if there is a way to fix this. Here is the code:
# My Module Rules
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?(.*?)/?$ ./page.php?url=$1 [L]
RewriteCond %{THE_REQUEST} /page\.php\?url=([^\&\ ]+)
RewriteRule ^/?page\.php$ ./%1/? [R=301, L]
</IfModule>
# Application Rules
<IfModule mod_rewrite.c>
RewriteEngine on
# RewriteBase is set to "/" so rules do not need updating if the
# installation directory is relocated. It is imperative that
# there is also a RewriteCond rule later that can effectively get
# the actual value by comparison against the request URI.
#
# If there are _any_ other RewriteBase directives in this file,
# the last entry will take precedence!
RewriteBase /
# Redirect directories to an address with slash
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ $1/ [R]
# Send all remaining (routable paths) through index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Determine and use the actual base
RewriteCond $0#%{REQUEST_URI} ([^#]*)#(.*)\1$
RewriteRule ^.*$ %2index.php [QSA,L]
</IfModule>
The rules I have above are working for my module URLs:
https://www.example.com/page.php?url=test-page => https://www.example.com/test-page/
However, it's breaking the rewrite rules for the main application, here is an example:
https://www.example.com/admin/setup => 404 Error
I've tried to re-arrange the rules, but then my rewrite doesn't work. I'm also trying to not edit the application's rules because those are standard for people who use it.
I tried to add another conditional that would check to see if the requested URL contains "page.php", but it did not fix the issue. Here was the code I used:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/?page\.php$
RewriteRule ^/?(.*?)/?$ ./page.php?url=$1 [L]
RewriteCond %{THE_REQUEST} /page\.php\?url=([^\&\ ]+)
RewriteRule ^/?page\.php$ ./%1/? [R=301, L]
</IfModule>
Perhaps something is wrong with the code and I'm hoping someone could point me in the right location. Thank you all!

.htaccess redirect .php and .html requests

I work with a framework called SilverStripe ... we are currently in the process of migrating an old site onto this framework. The problem is that the old site URLs ended with .php or .html whilst in the new site they don't.
I need to amend the second rewrite rule in such a way that I pump the request to main.php without any .html or .php extensions.
In my current .htaccess I have the following rules:
# Turn off index.php handling requests to the homepage fixes issue in apache >=2.4
<IfModule mod_dir.c>
DirectoryIndex disabled
</IfModule>
SetEnv HTTP_MOD_REWRITE On
RewriteEngine On
# Enable HTTP Basic authentication workaround for PHP running in CGI mode
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Deny access to potentially sensitive files and folders
RewriteRule ^vendor(/|$) - [F,L,NC]
RewriteRule silverstripe-cache(/|$) - [F,L,NC]
RewriteRule composer\.(json|lock) - [F,L,NC]
# Process through SilverStripe if no file with the requested name exists.
# Pass through the original path as a query parameter, and retain the existing parameters.
RewriteCond %{REQUEST_URI} ^(.*)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* framework/main.php?url=%1 [QSA]
# If framework isn't in a subdirectory, rewrite to installer
RewriteCond %{REQUEST_URI} ^(.*)/framework/main.php$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . %1/install.php? [R,L]
Possible solution (still testing):
RewriteCond %{REQUEST_URI} ^(.*)\.html [OR]
RewriteCond %{REQUEST_URI} ^(.*)\.php [OR]
RewriteCond %{REQUEST_URI} ^(.*)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* framework/main.php?url=%1 [QSA]
Add the following rules to your .htaccess file below the # Deny access to potentially sensitive files and folders block of rules:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} ^(.+)\.html$
RewriteRule (.*)\.html$ /$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} ^(.+)\.php$
RewriteRule (.*)\.php$ /$1 [R=301,L]
The first two lines check that the url is not a directory and is not file.
The third line checks that the url contains either .html or .php.
The forth line removes .html / .php from the url
You can just tweak your existing rule a bit:
# Turn off index.php handling requests to the homepage fixes issue in apache >=2.4
<IfModule mod_dir.c>
DirectoryIndex disabled
</IfModule>
SetEnv HTTP_MOD_REWRITE On
RewriteEngine On
# Enable HTTP Basic authentication workaround for PHP running in CGI mode
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Deny access to potentially sensitive files and folders
RewriteRule ^vendor(/|$) - [F,L,NC]
RewriteRule silverstripe-cache(/|$) - [F,L,NC]
RewriteRule composer\.(json|lock) - [F,L,NC]
# Process through SilverStripe if no file with the requested name exists.
# Pass through the original path as a query parameter, and retain the existing parameters.
# Strip out .html or .php from request URI
RewriteCond %{REQUEST_URI} ^(.+?)(?:\.(?:html|php))?$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ framework/main.php?url=%1 [L,QSA]
# If framework isn't in a subdirectory, rewrite to installer
RewriteCond %{REQUEST_URI} ^(.*)/framework/main\.php$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . %1/install.php? [R,L]
Here is a short solution to the problem
Try the following rule :
RewriteRule ^([^.]+)\.(html|php)$ /framework/main.php?url=$1 [NC,L,QSA]
This will rewrite
/file.php OR /file.html
to
/framework/main.php?url=$1
pattern explained :
^([^.]+).(html|php)$ matches any request starting with any characters excluding dot followed by a littrel dot char followed by literal php or html in the end of the uri.
Note : this should be the first rule in your htaccess before any other rules.
Try this code:-
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html
Hope this code will work for you :)
How about the basic...
Redirect 301 /about-us.html http://www.domain.com/about-us
EDIT Now you've mentioned that you have hundreds of these... the above answer is still valid as you can add hundreds of these to the htaccess (I've seen it many times)... however it is very possible also like this...
RedirectMatch 301 (.*)\.html$ http://www.domain.com$1/
The downside of not doing this line by line is now that you may have a specific html file that you do want to allow access to still and that will need adding as an exception to this rule.

.htaccess rule not excluding existing files when rule has a slash condition

I am redirecting this type of url
http://www.site.com/windows/games/ or http://www.site.com/windows/games
http://www.site.com/windows/software/ or http://www.site.com/windows/software
to
http://www.site.com/windows/ct.php?ct=games
http://www.site.com/windows/ct.php?ct=software
Site structure
wamp/www/Site/windows/ct.php
I am trying this way its redirecting properly but when url has trailing slash at end its rewriting css, js files too.
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^windows/([^/]*)/?$ /Site/windows/ct.php?ct=$1 [L]
i.e
this type of url has css and javascript applied.
http://www.site.com/windows/games
but this type of url has no css and javascript applied. (not working with trailing slash).
http://www.site.com/windows/games/
I have tried several syntax like
RewriteRule ^windows/([^/]+)/?$ /windows/ct.php?ct=$1 [L]
RewriteRule ^windows/(^(.[^/]*)/?)$ /windows/ct.php?ct=$1 [L]
RewriteRule ^windows/([^/]*)/? /windows/ct.php?ct=$1 [L]
RewriteRule ^windows/([^/]+)/? /windows/ct.php?ct=$1 [L]
but it didn't work.
Complete .htaccess
Options +FollowSymlinks -MultiViews
RewriteEngine on
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^windows/([^/]*)/?$ /Site/windows/ct.php?ct=$1 [L]
RewriteRule ^[^/]*/[^/]*/(.*\.html) /Site/error/400/ [L]
RewriteRule ^(error) - [L]
RewriteRule ^sitemap\.xml$ sitemap.php [L]
RewriteRule ^rss/(.*?)\.xml$ rss/$1.php [L]
</IfModule>
ErrorDocument 404 /Site/error/404/
Please see and suggest any possible way to do it.
Thanks.
The issue here is that your relative paths break when you add a trailing slash as it introduces two-levels of directory structure while the CSS/JS file paths come out only once ... So, your RewriteRule is actually firing for CSS/JS files as well when resolving 404s for paths like /windows/global/js/js.js. But, the scripts still fail to work because they aren't under /Site and that's where your rule is serving the request from.
So, to fix things without touching the relative URLs or resource locations; add another rule as follows:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^windows/([^/]*)/?$ /Site/windows/ct.php?ct=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^windows/(global/.*)$ /$1 [L] # handles css|js files
The rest of your .htaccess (of course) remains the same.
I use the following rule in .htaccess, but this may be too general:
RewriteRule ^q/([^/]+)/([^/]+)(\/?)$ /path/to/q.php?type=$1&q=$2&{QUERY_STRING} [NC]
This may be better for you:
RewriteRule ^windows(\/?)$ /path/to/windows.php?{QUERY_STRING} [NC]
RewriteRule ^windows/([^/]+)(\/?)$ /path/to/windows.php?type=$1&{QUERY_STRING} [NC]
You will have to change this according to your situation. I haven't tested this, but I hope it is good enough for you to get where you want.

How to change URL? htaccess

What I have
newsy/czytaj/items/odbierz-250zl-na-reklame.html
This is what I would have
newsy/odbierz-250zl-na-reklame.html
How to do this with mod-rewrite? I don't understand RewriteRule.
My .htaccess
RewriteEngine On
RewriteCond %{REQUEST_URI} (ftp|https?):|/etc/ [NC,OR]
RewriteCond %{QUERY_STRING} (ftp|https?):|/etc/ [NC]
RewriteRule .* - [F,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .*\.html$ index.php [L]
RewriteEngine on
RewriteRule ^newsy/([^\./]+)\.html /newsy/czytaj/items/$1.html [L]
This will rewrite anything that starts with newsy and add a /czytaj/items between it and the html file.
In principle you just create a corresponding rewrite rule:
RewriteRule ^newsy/czytaj/items/(.+) /newsy/$1 [L]
It is crucial not to omit [L]flag. Otherwise your rewrite engine may get stuck in an endless loop. Also in the beginning of the .htaccessfile remember to enable mod_rewrite with:
RewriteEngine On
For more help on mod_rewrite, I recommend checking out mod_rewrite-cheatsheet. For an exhaustive URl Rewriting Guide see a corresponding page from Apache 2.0 Documentation.

htaccess 301 redirect example.com/beta/xyz to example.com/xyz

I need a general rule that maps every URL in the /beta subdirectory to the corresponding URL in the root; essentially I need to remove /beta from all URLs.
In case it makes any difference, the URLs are dynamically generated by WordPress.
Currently my .htaccess file is:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
#END WordPress
Can you tell me where to put the new lines?
Thank you!
Could you try this?
RewriteEngine On
RewriteRule ^beta/(.*)$ http://example.com/$1 [R=301,L]
Your question is not entirely clear, but I would bet that what you want is having a Wordpress installed in somedir/beta appear in yoursite.com/ instead of yoursite.com/beta/. The rules you pasted are in somedir/beta/.htaccess, and are the default Wordpress rules. You must leave those alone.
What you need for that is to put the following rules in the root directory, as in, somedir/.htaccess, after changing example.com to your own domain. Your webserver first reads this root .htaccess, and when it does, it will know to rewrite requests to /beta.
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteCond %{REQUEST_URI} !^/beta/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /beta/$1
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteRule ^(/)?$ beta/index.php [L]
</IfModule>
More info in the Codex:
https://codex.wordpress.org/Giving_WordPress_Its_Own_Directory

Resources