mod-rewrite when index.php is in the URL - regex

I wish to rewrite http://example.com/admin/pages/index.php to http://example.com/index.php?admin=admin&cid=pages.
It works for http://example.com/admin/pages (which I also want), but not for http://example.com/admin/pages/index.php.
How is this accomplished?
RewriteEngine On
RewriteBase /
# If the request is for a valid directory, file, or link, don't do anything
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^ - [L]
#remove the trailing slash
RewriteRule (.+)/$ $1
# If you add this first rule to support views, be sure to remove the QSA flag from the second rule (maybe not required since the first rule has the L flag)
#replace admin/cid with index.php?admin=admin&cid=cid
RewriteRule ^([^/]+)/([^/]+)/?$ index.php?admin=$1&cid=$2 [L,QSA]
#replace mypage with index.php?admin=mypage
RewriteRule ^([^/]+)/?$ index.php?admin=$1 [L,QSA]
EDIT
Random changes shows that this might be correct.
RewriteRule ^([^/]+)/([^/]+)/index.php/?$ index.php?admin=$1&cid=$2 [L,QSA]
RewriteRule ^([^/]+)/([^/]+)/?$ index.php?admin=$1&cid=$2 [L,QSA]
#replace mypage with index.php?admin=mypage
RewriteRule ^([^/]+)/index.php/?$ index.php?admin=$1 [L,QSA]
RewriteRule ^([^/]+)/?$ index.php?admin=$1 [L,QSA]

Problem is your first rule that is skipping all files & directories from rules.
Replace your rules with this:
RewriteEngine On
RewriteRule ^index\.php$ - [L,NC]
#remove the trailing slash
RewriteRule (.+)/$ $1 [L,R=302]
# If you add this first rule to support views, be sure to remove the QSA flag from the second rule (maybe not required since the first rule has the L flag)
#replace admin/cid with index.php?admin=admin&cid=cid
RewriteRule ^([^/]+)/([^/]+)(?:/?|/index\.php)$ index.php?admin=$1&cid=$2 [L,QSA]
#replace mypage with index.php?admin=mypage
RewriteRule ^([^/.]+)/?$ index.php?admin=$1 [L,QSA]

Related

Redirect to default language except for /amp/ URLs

I'm struggling to solve a redirection but without any success.
I changed the URLs of my site forcing a default language, before it was site.com/help/ and now it's site.com/en/help/. Thanks to help from Stack Overflow I made the redirection, but then I faced a new problem with the AMP pages: site.com/amp/help/ are now redirected to site.com/en/amp/help/ while they are supposed to be site.com/amp/en/help/.
Again, thanks to help on this site, I changed the structure of URLs to site.com/en/help/amp/ (amp always at the end). To achieve this, I had to delete the .php extension I had in some pages and also decided to remove the trailing slash.
I'm now facing two new issues: the 301 redirection to a non .php page and URLs with trailing slashes to a non trailing slash don't work. Below is my htaccess code.
RewriteEngine on
# amp
RewriteRule ^(.*/)?amp/(.+?)/?$ /$1$2/amp [R=301,NC,L]
## redirect to default language (fr)
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_URI} !/inc
RewriteCond %{REQUEST_URI} !/ajax/
RewriteCond %{REQUEST_URI} !/img/
RewriteRule ^(?![a-z]{2}(?:[/-]|$))(.*)$ /fr/$1 [R=301,L,NE]
## Unless directory, remove trailing slash
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)/$ /$1 [R=301,NE,L]
## add trailing slash in front of directories
RewriteCond %{DOCUMENT_ROOT}/$1 -d
RewriteRule ^[a-z]{2}(?:-[a-z]{2})?/(.+)$ /$1/ [L]
# remove .php
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_FILENAME} !global.js
RewriteCond %{REQUEST_URI} !/ajax/
RewriteCond %{REQUEST_URI} !results.php
RewriteRule ^(.+)\.php(.*)$ /$1$2 [R=301,NC,NE,L]
## amp pages
RewriteRule ^(.*)/amp$ /$1?amp=1 [NC,QSA,L]
## folders of languages
#RewriteRule ^([a-z]{2}(?:-[a-z]{2})?)/(.*)$ /$2?lang=$1 [QSA,L]
RewriteRule ^([a-z]{2}|[a-z]{2}-[a-z]{2})$ /$2?lang=$1 [QSA,L]
RewriteRule ^([a-z]{2}|[a-z]{2}-[a-z]{2})/(.*)$ /$2?lang=$1 [QSA,L]
## hide .php extention
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_FILENAME} !global.js
RewriteRule ^(.+?)/?$ $1.php [L]
Have it this way:
RewriteEngine on
# changed amp URLs
RewriteRule ^(.*/)?amp/(.+?)/?$ /$1$2/amp/ [R=301,NC,L]
## redirect to default language (en)
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_URI} !/img/
RewriteRule ^(?![a-z]{2}(?:[/-]|$))(.*)$ /en/$1 [R=301,L,NE]
## Unless directory, remove trailing slash
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !/amp/$ [NC]
RewriteRule ^(.+)/$ /$1 [R=301,NE,L]
## add trailing slash in front of directories after lang rewrite
RewriteCond %{DOCUMENT_ROOT}/$1 -d
RewriteRule ^[a-z]{2}(?:-[a-z]{2})?/(.+[^/])$ /$0/ [L]
# remove .php
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteRule ^(.+)\.php$ /$1/ [R=301,NC,NE,L]
## amp pages
RewriteRule ^(.+/)amp/?$ /$1?amp=1 [NC,QSA,L]
## folders of languages
RewriteRule ^([a-z]{2}(?:-[a-z]{2})?)/(.*)$ /$2?lang=$1 [QSA,L]
## hide .php extention
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_FILENAME} !global.js
RewriteRule ^(.+?)/?$ $1.php [L]
Explanation of this trailing slash rule:
## add trailing slash in front of directories after lang rewrite
RewriteCond %{DOCUMENT_ROOT}/$1 -d
RewriteRule ^[a-z]{2}(?:-[a-z]{2})?/(.+[^/])$ /$0/ [L]
Take an example URI: /fr/cart.
In a later rule we remove lang component from URL and pass it as lang=<fr|en> query parameter. Part after lang parameter e.g. /cart doesn't have a trailing slash and if it is a real directory then /cart?lang=fr will be redirected to /cart/?lang=fr by Apache's mod_dir module and your internal URL will be exposed in browser.
So in this current rule we capture part after lang component and check if we don't have a trailing slash and it is a directory then this rule internally rewrites to /fr/cart/ with a trailing slash. Later rule then rewrites it to /cart/?lang=fr and mod_dir doesn't redirect anymore.
#anubhava's solution works perfectly well except for one little case: /fr/amp/page.php redirects to /fr/page.php/amp, I had to make some changed to the code and managed to make it work. Below is the updated code with small changes I made:
1- removed some slashes at the end of some rules as I don't need them any more
2- removed this rule RewriteCond %{REQUEST_URI} !/amp/$ [NC]
3- to fix the .php problem, I replaced RewriteRule ^(.+)\.php$ /$1/ [R=301,NC,NE,L] by RewriteRule ^(.+)\.php(.*)$ /$1$2 [R=301,NC,NE,L].
RewriteEngine on
## changed amp URLs
RewriteRule ^(.*/)?amp/(.+?)/?$ /$1$2/amp [R=301,NC,L]
## redirect to default language (en)
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_URI} !/img/
RewriteRule ^(?![a-z]{2}(?:[/-]|$))(.*)$ /en/$1 [R=301,L,NE]
## Unless directory, remove trailing slash
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)/$ /$1 [R=301,NE,L]
## add trailing slash in front of directories
RewriteCond %{DOCUMENT_ROOT}/$1 -d
RewriteRule ^[a-z]{2}(?:-[a-z]{2})?/(.+)$ /$1/ [L]
# remove .php
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteRule ^(.+)\.php(.*)$ /$1$2 [R=301,NC,NE,L]
## amp pages
RewriteRule ^(.+/)amp$ /$1?amp=1 [NC,QSA,L]
## folders of languages
RewriteRule ^([a-z]{2}(?:-[a-z]{2})?)/(.*)$ /$2?lang=$1 [QSA,L]
## hide .php extention
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_FILENAME} !global.js
RewriteRule ^(.+?)/?$ $1.php [L]

.htaccess case-insensitive directories

I access to the file.php writing mydomain.com/file. I need to be able to access also writing mydomain.com/FILE.
In .htaccess I use the following rules to remove extension:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.+?)/?$ /$1.php [L]
# redirect to .php-less link if requested directly
RewriteCond %{THE_REQUEST} ^[A-Z]+\s.+\.php\sHTTP/.+
RewriteRule ^(.+)\.php $1 [R=301,L]
If this rules should be changed- it's up to you.
Define this RewriteMap in Apache or vhost config:
RewriteMap lc int:tolower
Then inside your .htaccess have an additional rule to lowercase all uppercase URIs:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301,NE]
# redirect to .php-less link if requested directly
RewriteCond %{THE_REQUEST} ^[A-Z]+\s.+\.php\sHTTP [NC]
RewriteRule ^(.+)\.php$ /$1 [R=301,L,NC,NE]
# convert each REQUEST_URI to lowercase
RewriteRule ^(.*?[A-Z]+.*)$ /${lc:$1} [R=301,L,NE]
# internally add .php
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.+?)/?$ $1.php [L]
Use [NC] flag in your rules
Use of the [NC] flag causes the RewriteRule to be matched in a
case-insensitive manner. That is, it doesn't care whether letters
appear as upper-case or lower-case in the matched URI.
https://httpd.apache.org/docs/current/rewrite/flags.html
You need to take care of two aspects: first the case insensitive matching and second the case conversion to lowercase.
Apache's rewriting module provides the NC flag for the first aspect and a somewhat more complex approach to the second one:
RewriteEngine On
# remove trailing slash (/) if no such folder exists
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /${lc:$1} [NC,L,R=301]
# internally rewrite to a php script if it exists and convert to lower case
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+)$ /${lc:$1}.php [NC,L]
# redirect to .php-less link if requested directly
RewriteRule ^(.+)\.php$ ${lc:$1} [NC,L,R=301]
I have the impression though that your original set of rewriting rules does not really achieve what you attempt to, that is it syntactically invalid even. That is why I changed a few aspects.

Regex pattern to exclude specific words at the start of url using htaccess

[Edited code]*
This is the current code I am using
Options +FollowSymLinks
RewriteCond %{REQUEST_URI} (bus/(.*))
RewriteRule bus/(.*) page1.php?param=$1 [L,NC,QSA]
RewriteCond %{REQUEST_URI} (car/(.*))
RewriteRule car/(.*) test/page2.php?param=$1 [L,NC,QSA]
RewriteCond %{REQUEST_URI} (bike/(.*))
RewriteRule bike/(.*) test/page3.php?param=$1 [L,NC,QSA]
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+)/(.+)$ new.php?param1=$1&param2=$2 [L,QSA]
I am trying to get the wild card condition in the last line if the above conditions fail. But the server returning with the 404. Its not catching the condition.
Any Help would be appreciated.
Keep all specific rules are top and 3rd generic catch-all rule at the last:
RewriteEngine On
RewriteRule ^bus/(.+)$ page1.php?param=$1 [L,NC,QSA]
RewriteRule ^car/(.+)$ test/page2.php?param=$1 [L,NC,QSA]
RewriteRule ^bike/(.+)$ test/page3.php?param=$1 [L,NC,QSA]
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+)/(.+)$ new.php?param1=$1&param2=$2 [L,QSA]
Two RewriteCond are required before last rule to prevent rewriting actual files and directories.
Your need to use the L flag at the end of your rules to stop multiple rule processing :
RewriteRule ^ask/(.*) forum.php?param=$1 [L,NC]
RewriteRule ^city/(.*) city.php?param=$1 [L,NC]

Apache modrewrite .htaccess - similar link

I am wondering if it is possible to achieve this bellow:
Sometimes second attribute will be submenu
RewriteRule ^([\w-]+)/([\w-]+)/?$ index.php?menu=$1&submenu=$2 [L,QSA]
Sometimes it will be location
RewriteRule ^([\w-]+)/([\w-]+)/?$ index.php?menu=$1&news=$2 [L,QSA]
But normally, this way it does not work. Is there any possible way to achieve this?
EDIT:
Current complete rewrite rule:
RewriteEngine on
ErrorDocument 404 /error
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
RewriteRule ^([\w-]+)/?$ index.php?menu=$1 [L,QSA]
RewriteRule ^([\w-]+)/([\w-]+)/?$ index.php?menu=$1&news=$2 [L,QSA]
RewriteRule ^([\w-]+)/([\w-]+)/?$ index.php?menu=$1&submenu=$2 [L,QSA]
RewriteRule ^([\w-]+)/([\w-]+)/([\w-]+)/?$ index.php?menu=$1&submenu=$2&news=$3 [L,QSA]
To elaborate on my comment further you can have rules like this:
ErrorDocument 404 /error
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
RewriteRule ^([\w-]+)/?$ index.php?menu=$1 [L,QSA]
RewriteRule ^([\w-]+)/n-([\w-]+)/?$ index.php?menu=$1&news=$2 [L,QSA]
RewriteRule ^([\w-]+)/([\w-]+)/?$ index.php?menu=$1&submenu=$2 [L,QSA]
RewriteRule ^([\w-]+)/([\w-]+)/([\w-]+)/?$ index.php?menu=$1&submenu=$2&news=$3 [L,QSA]
Now your news links should like this: http://domain.com/main-menu/n-sports
Consider that your regex starts matching \w, which stands for "word character", usually [A-Za-z0-9_]. Notice the inclusion of the underscore and digits. This also means that this doesn't match accented characters for example. For sure this don't match the leading slash that begins every path in urls.
You should change your rewrites adding a leading slash:
RewriteRule ^/([\w-]+)/?$ index.php?menu=$1 [L,QSA]
RewriteRule ^/([\w-]+)/([\w-]+)/?$ index.php?menu=$1&news=$2 [L,QSA]
# RewriteRule ^/([\w-]+)/([\w-]+)/?$ index.php?menu=$1&submenu=$2 [L,QSA]
RewriteRule ^/([\w-]+)/([\w-]+)/([\w-]+)/?$ index.php?menu=$1&submenu=$2&news=$3 [L,QSA]
I have also commented the third rule because the regex is identical to the second. Your approach also have a logical problem, since there is no difference between these lines, so there is no way to call index.php?menu=$1&submenu=$2

Conditionally redirecting directory structure URL to html file

My goal is to redirect any url such as http://mydomain.com/somename to http://mydomain.com/somename.html except for http://mydomain.com/name1 and http://mydomain.com/name2 For these two, I wish to redirect them to http://mydomain.com/main.php?g1=name1 (or name2, etc). If these later two have two or three more directories in the URL (i.e. http://mydomain.com/name1/val2/val3), I wish to add them as individual GET values such as http://mydomain.com/main.php?g1=name1&g2=val2&g3=val3. I would like the browser to keep showing the directory path, and not something like http://mydomain.com/somename.html.
Below is my unsuccessful attempt. How can I accomplish this? Thank you
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
## If the request is for a valid directory, file, or link, don't do anything
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^ - [L]
RewriteCond %{REQUEST_URI} !^/name1 [OR] RewriteCond %{REQUEST_URI} !^/name2
RewriteRule ^(.*)$ $1.html [L]
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/?$ ?p=$1&c=$2&v=$3 [L,QSA]
RewriteRule ^([^/]+)/([^/]+)/?$ p=$1&c=$2 [L,QSA]
RewriteRule ^([^/]+)/?$ ?p=$1 [L,QSA]
</IfModule>
You have the right idea in most places, but you need to change the order of your rules to match more specific stuff before less specific stuff. Generally, I'm allowing a trailing / in the rules below via /?. Remove that from the end if you won't permit a trailing / to be matched.
RewriteEngine on
RewriteBase /
# This should be fine as you have it....
## If the request is for a valid directory, file, or link, don't do anything
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^ - [L]
# Reverse your rule order here.
# First match name1|name2 with an optional trailing /
# but nothing else following...
RewriteRule ^(name1|name2)/?$ main.php?g1=$1 [L,QSA]
# Two additional dirs
RewriteRule ^(name1|name2)/([^/]+)/([^/]+)/?$ main.php?g1=$1&g2=$2&g3=$3 [L,QSA]
# Three additional dirs
RewriteRule ^(name1|name2)/([^/]+)/([^/]+)/([^/]+)/?$ main.php?g1=$1&g2=$2&g3=$3&g4=$4 [L,QSA]
# Last, do the generic rule to rewrite to .html
# using [^.]+ to match anything not including a .
# You could be more specific with something like [a-z]+ if that
# corresponds to your expected input
RewriteRule ^([^.]+)$ $1.html [L,QSA]
If you wanted to check that the URI is not name1, name2 in a condition, use an [AND] which is implicit:
RewriteCond %{REQUEST_URI} !/name1
RewriteCond %{REQUEST_URI} !/name2
RewriteRule ^([^.]+)$ $1.html [L,QSA]