Please consider the content in my .htaccess:
##
Options +FollowSymlinks -MultiViews
RewriteEngine on
RewriteBase /
## Allow a few SEO Files direct access.
RewriteRule ^robots.txt?$ robots.txt [L]
RewriteRule ^ads.txt?$ ads.txt [L]
RewriteRule ^sellers.json?$ sellers.json [L]
## Avoid rewriting rules for the admin section
RewriteRule ^(admin|resources)($|/) - [L]
## Set Ajax Request File
RewriteRule ^(kahuk-ajax)/?$ kahuk-ajax.php? [L,QSA]
## Set controller with id
RewriteRule ^([^/]+)/([0-9]+)/?$ index.php?con=$1&id=$2 [L,QSA]
## Set controller with slug
RewriteRule ^([^/]+)/([^/]+)/?$ index.php?con=$1&slug=$2 [L,QSA]
## For paging
RewriteRule ^([^/]+)/page/([0-9]+)/?$ index.php?con=$1&page=$2 [L,QSA]
RewriteRule ^([^/]+)/([^/]+)/page/([0-9]+)/?$ index.php?con=$1&slug=$2&page=$3 [L,QSA]
## Set controller for only one parameter
RewriteRule ^page/([^/]+)/?$ index.php?con=page&slug=$1 [L,QSA]
RewriteRule ^([^/]+)/?$ index.php?con=$1 [L,QSA]
## Set home page
RewriteRule ^/?$ index.php?con=home [L]
Whenever I try to browse http://example.com/kahuk-ajax/?prefix=manage-story-vote, this opened the index.php instead of kahuk-ajax.php!
What am I doing wrong?
## Set Ajax Request File
RewriteRule ^(kahuk-ajax)/?$ kahuk-ajax.php? [L,QSA]
:
## Set controller for only one parameter
:
RewriteRule ^([^/]+)/?$ index.php?con=$1 [L,QSA]
The request is first rewritten to kakuk-ajax.php by the first rule, but the second to last rule then rewrites this to index.php during the second pass by the rewrite engine.
You need to prevent that second rule from rewriting requests of the form kakuk-ajax.php. If these URLs do not contain dots in the first path segment (that ordinarily delimits the file extension) then you could simply include a dot in the negated character class. For example:
## Set controller for only one parameter
:
RewriteRule ^([^/.]+)/?$ index.php?con=$1 [L,QSA]
Alternatively, exclude specific file extensions:
RewriteCond %{REQUEST_URI} \.(txt|json|php)$
RewriteRule ^([^/]+)/?$ index.php?con=$1 [L,QSA]
Or, any URL that looks like it has a file extension:
RewriteCond %{REQUEST_URI} \.\w{2,5}$
RewriteRule ^([^/]+)/?$ index.php?con=$1 [L,QSA]
Aside:
RewriteRule ^(kahuk-ajax)/?$ kahuk-ajax.php? [L,QSA]
This rule is a little contradictory. You are removing the query string with the trailing ?, but then appending it again with the QSA flag. If you wish to preserve the query string then you don't need either. And since you are capturing the URL-path, you might as well make use of this in the substitution string. For example:
RewriteRule ^(kahuk-ajax)/?$ $1.php [L]
Also, be wary of allowing an optional trailing slash here. This promotes duplicate content which could potentially cause SEO issues. Consider redirecting one to the other instead.
## Allow a few SEO Files direct access.
RewriteRule ^robots.txt?$ robots.txt [L]
RewriteRule ^ads.txt?$ ads.txt [L]
RewriteRule ^sellers.json?$ sellers.json [L]
The ? at the end of the regex makes the preceding character (t and n in the above examples) optional, which does not really make sense here. Also, you don't need to rewrite to the same file - you don't want any rewrite/substitution to occur here. So, the above is the same as:
RewriteRule ^(robots\.txt|ads\.txt|sellers.json)$ - [L]
The - (hyphen) explicitly indicates "no substitution".
However, having included a "dot" in the (negated character class) directive above, this directive is redundant, except to "fail early".
Related
I got an old project and it has some bizarre issue. Its CodeIgniter project (version 2.X).
Google is indexing our URLs with index.php?. Below is an example
https://www.website.com/index.php?/my-seo-friendly-uri
I can see my pages from above url and with 2 more variants as below
https://www.website.com/index.php/my-seo-friendly-uri
https://www.website.com/my-seo-friendly-uri
We have used https://www.website.com/my-seo-friendly-uri throughout the site.
My question is how I can redirect https://www.website.com/index.php?/my-seo-friendly-uri and https://www.website.com/index.php/my-seo-friendly-uri to https://www.website.com/my-seo-friendly-uri?
The thing I already did
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^index.php/(.*)$ /$1 [R=302,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L]
</IfModule>
This redirects index.php to normal URLs, but index.php? version of url is still not redirecting
In my config.php, I have the following settings
$config['index_page'] = '';
$config['uri_protocol'] = 'REQUEST_URI';
https://www.example.com/index.php?/my-seo-friendly-uri
This URL contains a query string and so requires a slightly different rule in order to match it. The RewriteRule pattern matches against the URL-path only (just index.php in this case). The query string is available in its own variable.
Add the following, before your existing directives (in addition to the directive that matches /index.php/my-seo-friendly-url - which is passed as path-info):
# Redirect URLs of the form "/index.php?/my-seo-friendly-uri"
# And "/?/my-seo-friendly-uri"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^(/.*)
RewriteRule ^(index\.php)?$ %1 [QSD,R=302,L]
The query string is captured (2nd condition), and the backreference (%1) is used to construct the redirect.
The first condition that checks against the REDIRECT_STATUS environment variable is required in order to prevent a redirect loop, since you appear to be using the query string method to route the codeigniter URLs in the later rewrite. The REDIRECT_STATUS env var is empty on the initial request, but set to "200" (as in 200 OK HTTP status) after the first successful rewrite.
The QSD flag (Apache 2.4+) is required to discard the original query string from the redirected request. If you are still on Apache 2.2 then append a ? (empty query string) to the substitution string instead. ie. %1?
By making the match for index.php optional (ie. ^(index\.php)?$) it will also canonicalise URLs that omit index.php, but still include the query string (that may or may not currently be a problem). eg. /?/my-seo-friendly-uri.
Note that this is currently a 302 (temporary) redirect (as is your existing redirect). Only change this to a 301 (permanent) redirect once you have confirmed it works OK. 301s are cached persistently by the browser so can make testing problematic.
Summary
Your .htaccess file should look like this:
RewriteEngine On
# Query string...
# Redirect URLs of the form "/index.php?/my-seo-friendly-uri"
# And "/?/my-seo-friendly-uri"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^(/.*)
RewriteRule ^(index\.php)?$ %1 [QSD,R=302,L]
# Path-Info...
# Redirect URLs of the form "/index.php/my-seo-friendly-uri"
# Also handles "/index.php" only
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^index.php(?:/(.*))?$ /$1 [R=302,L]
# CodeIgniter Front-controller
# (NB: Using query string method to pass the URL)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php?/$1 [L]
Additional notes...
The <IfModule> wrapper is not required.
(.*) is the same as ^(.*)$ since regex is greedy by default.
I've modified your existing path-info redirect (ie. /index.php/foo) to also redirect requests for /index.php only. This now requires an additional condition to avoid a redirect loop.
Your CodeIgniter front-controller is using the query string method to pass /my-seo-friendly-url to the backend (as used in the question). However, you have set $config['uri_protocol'] = 'REQUEST_URI'; - which contradicts with this (although shouldn't necessarily be a problem). However, if you are using the REQUEST_URI method then you can remove the ?/$1 part from the end of the final RewriteRule substitution string. For example:
For example, from this:
RewriteRule (.*) index.php?/$1 [L]
To this:
RewriteRule . index.php [L]
Use .htaccess................
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
<IfModule mod_php5.c>
RewriteRule ^(.*)$ index.php/$1 [L]
</IfModule>
<IfModule !mod_php5.c>
RewriteRule ^(.*)$ index.php?/$1 [L]
</IfModule>
</IfModule>
I have a problem with the configuration of the .htaccess of small website that I'm working on.
I want all pages to be redirected to index.php?page=REQUEST and that file will find in the database the content for the requested page.
The problem occurs when I have installed a forum, so I want these forum pages to redirect to the index.php?page=forum¶ms
Options +FollowSymlinks
RewriteEngine on
RewriteCond %{REQUEST_URI} /(.*).html
RewriteRule ^(.*)forum/category/(.*)?$ index\.php?page=forum&lang=$1&category=$2 [L]
RewriteRule ^(.*)/(.*)(\.html?)$ index\.php?lang=$1&page=$2 [L]
RewriteRule ^(.*)(\.html?)$ index\.php?page=$1 [L]
Evetything works fine, except the forum part. How do I need to change the .htacces?
RewriteEngine on
RewriteRule \.(jpg|png|gif|svg|css|js)$ - [L]
RewriteRule ^(.*)/forum/topic/(.*)?$ index\.php?page=forum&lang=$1&topic=$2 [L]
RewriteRule ^(.*)/forum/category/(.*)?$ index\.php?page=forum&lang=$1&category=$2 [L]
RewriteRule ^(.*)/(.*)(\.html?)$ index\.php?lang=$1&page=$2 [L]
RewriteRule ^(.*)(\.html?)$ index\.php?page=$1 [L]
The problem appears to be that your RewriteCond is matching requests that end in .html. As your forum URLs don't end in .html the condition for the subsequent RewriteRule is never met.
There are some other possible problems too:
^(.*)forum will match www.url.com/en/ when it looks like you probably just want en
category/(.*) will match any characters, including forward slashes and the like. Presumably you just want it to match a decimal identifier.
Links to things that aren't covered by your rewrite config e.g. images
I'd probably rewrite your config to look something like this (N.B. not tested in Apache; only in a regex debugger):
RewriteEngine on
# only match forum URLs
# e.g url.com/en/forum/category/12345
RewriteCond %{REQUEST_URI} ^/.+/forum/category/[0-9]+
RewriteRule ^/(.+)/forum/category/([0-9]+) index.php?page=forum&lang=$1&category=$2 [L]
# match all URLs ending in .html
# e.g. url.com/en/foo.html
# and url.com/foo.html
RewriteCond %{REQUEST_URI} ^/.+\.html$
# a bit complicated, this matches both
# /apage.html
# /folder/apage.html
RewriteRule ^(?:/(.+))?/(.+)\.html$ index.php?lang=$1&page=$2 [L]
The second RewriteRule should always provide a value for page but only provide a value for lang if the URL is of the form /lang/page.html. This should be OK if your index.php file can accept an empty lang parameter or supply a default value.
Alternatively, if you don't mind keeping your existing regex and it's only images, CSS etc you want to bypass in URL rewriting you can add some rules at the start to skip them e.g.
RewriteEngine on
# don't actually rewrite, and stop processing rules
RewriteRule \.(jpg|png|css|js)$ - [L]
# only match forum URLs
# e.g url.com/en/forum/category/12345
RewriteCond %{REQUEST_URI} ^/.+/forum/category/[0-9]+
RewriteRule ^/(.+)/forum/category/([0-9]+) index.php?page=forum&lang=$1&category=$2 [L]
etc...
I'm trying to show a default view (home) when the user lands in the root of my site, this is what I use
RewriteCond %{REQUEST_URI} ^/$
Rewriterule ^(.*)$ index.php?view=home [L]
With this other rule, I'm trying to catch everything that has variables (since all my paths are rewritten, I should never have something like mydomain.com?somevar=true, so i look for & or = or ?), and pass the query string to a page
RewriteCond %{REQUEST_URI} ^([\&|\=|\?]+)$
RewriteRule ^(.*)$ badstuff.php [L,QSA]
What I don't understand is that mydomain.com/?test=true is redirected to index.php?view=home instead of going to badstuff.php
What am i doing wrong? If I comment the 1st cond + rule, the second rule is never matched...
Thanks you.
Edit: Added more rules for better understanding. Forgot to mention, Apache 2.4
This is what I have now
#standard views
Rewriterule ^home$ index.php?view=home [L] (works)
Rewriterule ^about$ index.php?view=about [L] (works)
#default view
RewriteCond %{REQUEST_URI} ^/$
Rewriterule ^(.*)$ index.php?view=home [L] (works)
#bad stuff
Rewriterule ^[\?=&]$ badstuff.php [L,QSA] (doesnt work)
Your chief issue here is that you are attempting to match a query string inside REQUEST_URI, but that variable does not contain the query string.
From the Apache docs:
REQUEST_URI
The path component of the requested URI, such as "/index.html". This notably excludes the query string which is available as its own variable named QUERY_STRING.
So instead, you just need to match any non-empty character inside %{QUERY_STRING}, and you must place that rule before the rule matching / because /?abc=123 would still match the / rule.
# Match a non-empty query string (. is any one character)
RewriteCond %{QUERY_STRING} .
# Don't apply this if the view= has already been applied
RewriteCond %{QUERY_STRING} !view=
# Rewrite to badstuff.php and append the params.
RewriteRule ^.*$ badstuff.php [L,QSA]
# Then rewrite the root
RewriteCond %{REQUEST_URI} ^/$
Rewriterule ^(.*)$ index.php?view=home [L]
Better version:
I would simplify your first rule a bit to eliminate the RewriteCond since only the path needs to be matched by RewriteRule. I've also removed all the () capture groups because you are not actually using the values they capture.
RewriteCond %{QUERY_STRING} .
RewriteCond %{QUERY_STRING} !view=
# Rewrite to badstuff.php and append the params.
RewriteRule .* badstuff.php [L,QSA]
# Match a non-empty path into view=
RewriteRule ^([^/]+)$ index.php?view=$1 [L]
# Then a simpler rule that matches ^$ (no path)
RewriteRule ^$ index.php?view=home [L]
If you applied this in a VirtualHost config instead of .htaccess, the RewriteRule would include the leading /, so you'd need to use instead:
RewriteRule ^/$ index.php?view=home [L]
But / is not used in .htaccess.
Now, if the !view= is too broadly preventing the query string from matching, you may resort to matching in THE_REQUEST for query params.
# Match any query string in the raw request
RewriteCond THE_REQUEST \?[^=]+
RewriteRule .* badstuff.php [L,QSA]
#... Then the other rules
I have the following page:
http://localhost/?news=19&page=2
I want to rewrite this so that it goes kind of as follows
http://localhost/news/19/page/2
This is my .htaccess file, but my code dont work :(
RewriteEngine ON
RewriteBase /
RewriteRule ^page/(.*)$ /?page=$1 [L]
RewriteRule ^news/(.*)$ /?news=$1 [L]
RewriteRule ^news/(.*)/page/(.*)$ /?news=$1&page=$2 [L]
You should specify more precicely what the allowed type of character is and you should make sure your previous rules don't cause your later rules to be ignored.
So you should put your most specific rule first and if you want digits for your news- and page ID's, you should use for example:
RewriteRule ^page/(.*)$ /?page=$1 [L]
RewriteRule ^news/(\d*)/page/(\d*)$ /?news=$1&page=$2 [L]
^^ just a digit instead of any character `.`
RewriteRule ^news/(.*)$ /?news=$1 [L]
I'm making up myself a small blog and I found a useful .htaccess file to remove file extensions:
AddType text/x-component .htc
RewriteEngine On
RewriteBase /
# remove .php; use THE_REQUEST to prevent infinite loops
RewriteCond %{THE_REQUEST} ^GET\ (.*)\.php\ HTTP
RewriteRule (.*)\.php$ $1 [R=301]
# remove index
RewriteRule (.*)/index$ $1/ [R=301]
# remove slash if not directory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} /$
RewriteRule (.*)/ $1 [R=301]
# add .php to access file, but don't redirect
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_URI} !/$
RewriteRule (.*) $1\.php
This works just fine and all pages are showing up .php less. I know wanted to extend this so when I click a link to a specific blog post (say /blog/index.php?art=1) it just shows in the url as website/blog/1. I thought to tag on to the end of the .htaccess file:
RewriteRule ^blog/(.*)$ blog/index.php?art=$0 [L]
But that doesn't seem to be working. EDIT Actually it breaks the blog page so no snippets are pulled through from the DB
My .htaccess file is in the root directory and the blog files are /root/blog/index.php
Any help would be gratefully appreciated
Unlike most other languages, the parameters in .htaccess are not 0-based. To access the first parameter, you should use $1, not $0.
The following should work:
RewriteRule ^blog/(.*)$ blog/index.php?art=$1 [L]
It might also be worthwhile to add some tests in there, for example you might only want numerical values passed to art, so you can improve it using:
RewriteRule ^blog/([0-9]+)$ blog/index.php?art=$1 [L]
Also, it might be worthwhile to add the QSA flag, since this will also preserve any query string that is passed in the original URL:
RewriteRule ^blog/([0-9]+)$ blog/index.php?art=$1 [L,QSA]