I have a situation similar to a previous question that uses the following in the accepted answer:
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (googlebot|bingbot|Baiduspider) [NC]
RewriteRule .* - [R=403,L]
It just seems the rules provided from URL above block access to everything (including homepage level)
www.example.com/tbd_templates/
www.example.com/custom_post/
what I really need is to block access to the directories I specified (/tbd_templates/ ,/custom_post/ etc with status code 403) but allow access to the rest of the site structure.
My .htaccess is:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
anyone can help me?
RewriteCond %{HTTP_USER_AGENT} (googlebot|bingbot|Baiduspider) [NC]
RewriteRule .* - [R=403,L]
As mentioned in the linked answer, this code would need to go in the .htaccess file inside the directory you are trying to protect - so that it only applies to everything in that directory (denoted by the .* regex).
However, that is impractical if you need to protect several directories. In this case you should change the RewriteRule pattern to target the specific subdirectories you want to protect (touched on in the linked answer, but no example given).
For example, the following would need go before the WordPress code block (ie, before the # BEGIN WordPress comment marker). (You do not need to repeat the RewriteEngine directive, which already occurs later in the file.)
RewriteCond %{HTTP_USER_AGENT} (googlebot|bingbot|Baiduspider) [NC]
RewriteRule ^(tbd_templates|custom_post)($|/) - [F]
The first argument to the RewriteRule directive (the pattern) is a regular expression that matches against the requested URL-path, less the slash prefix.
The regex ^(tbd_templates|custom_post)($|/) matches requests for /tbd_templates or /custom_post (using regex alternation) or /tbd_templates/<anything> or /custom_post/<anything>.
The F flag is short for R=403. The L flag is not required here, it is implied when using F (or R=403).
Related
i am new to .htaccess usage and tried to learn through online resources but however i write it the rules negate each other and am having a hard time writing a good enough .htaccess file below is my current .htaccess file which works fine for some pages like removing extensions and rewriting subdomains please check below
## Flag for GoDaddy
Options +MultiViews
RewriteBase /
## Remove extensions
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !=f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
## Redirect from extensions to non-extensions
RewriteCond %{THE_REQUEST} \s/+(.+?)\.php[\s?] [NC]
RewriteRule ^ /%1 [R=301,NE,L]
## Redirect Pages
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^post/([a-zA-Z0-9-/]+)$ /post.php?ps=$1
RewriteRule ^([a-zA-Z0-9-/]+)$ post-files.php?ps=$1 [L,QSA]
## Server Only
## Redirect from www - non-www
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ http://$1/$1 [R=301,L]
## SSL Redirect
## RewriteEngine On
## RewriteCond %{HTTPS} ≠On
## RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
## Create Error Pages
ErrorDocument 404 /errors/404.html
ErrorDocument 403 /errors/403.html
ErrorDocument 500 /errors/500.html
## Redirect non-existing pages to index.php
Options +SymLinksIfOwnerMatch
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
Above is the .htaccess am currently using and i got it through tutorials from youtube it works good and redirects files.php to files only which am happy with but
as you can see above this line RewriteRule ^post/([a-zA-Z0-9-/]+)$ /post.php?ps=$1 and the line below it are not passing through the ps but they show 404 page
i want the results to be domain.com/post-file-slug to go to exactly file domain.com/post-file.php?ps=post-slug-here for rule RewriteRule ^([a-zA-Z0-9-/]+)$ post-files.php?ps=$1 [L,QSA]
and
domain.com/post/post-slug-here to go to exactly domain.com/post.php?ps=post-slug-here for rule
RewriteRule ^post/([a-zA-Z0-9-/]+)$ /post.php?ps=$1
I was working on this for 2 days now hopefully fix it soon. Thanks
## Flag for GoDaddy
Options +MultiViews
In what way is this a "flag for GoDaddy"? Enabling MultiViews will cause the ps URL parameter not to be passed to the post.php script. You need to ensure that MultiViews is disabled for the later rewrites to work as intended. ie.
Options -MultiViews
MultiViews (part of mod_negotiation) essentially enables extensionless URLs. It will result in a request for /post/post-slug-here to be "rewritten" to /post.php/post-slug-here before your mod_rewrite directive is processed, so it never matches and never rewrites the request to include the ps URL parameter.
## Remove extensions
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !=f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
## Redirect from extensions to non-extensions
RewriteCond %{THE_REQUEST} \s/+(.+?)\.php[\s?] [NC]
RewriteRule ^ /%1 [R=301,NE,L]
It is currently MultiViews that is allowing your extensionless URLs to work. The first condition (RewriteCond directive) above is incorrect. It should be !-f (not a file), not !=f (does not equal "f" - always true). However, this is still "wrong", as you need to check that the .php file exists before rewriting the request. If you simply rewrite all requests that do not map to a file (which is what you are trying to do here) then the later rewrites to post.php, post-files.php and index.php will not be processed as intended.
The regex \s/+(.+?)\.php[\s?] in the second condition is not strictly correct as it will result in a malformed redirect if .php occurs in the query string when it is omitted in the URL-path. eg. A request for /foo?bar.php would result in a redirect to /foo?bar when there should be no redirect at all in this instance. The regex needs to capture the URL-path only, so change the subpattern (.+?) to ([^?]+) instead.
These two rules are also the wrong way round. The external redirect should be first. As a general rule, external redirects should always go before internal rewrites.
It should be like this instead:
## Remove extensions
## Redirect to remove ".php" extension
RewriteCond %{THE_REQUEST} \s/+([^?]+?)\.php[\s?] [NC]
RewriteRule \.php$ /%1 [R=301,NE,L]
# Rewrite to append ".php" extension if corresponding ".php" file exists
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^.]+)$ $1.php [L]
You should already be linking to the file without the .php extension. The redirect to remove the .php extension is for SEO only when changing an existing URL structure.
No need to backslash-escape a literal dot when used inside a regex character class. The NC flag was superfluous here.
## Redirect Pages
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^post/([a-zA-Z0-9-/]+)$ /post.php?ps=$1
RewriteRule ^([a-zA-Z0-9-/]+)$ post-files.php?ps=$1 [L,QSA]
RewriteCond directives only apply to the first RewriteRule directive that follows. So, the second rule above is processed unconditionally - is that the intention?
In fact, those two condition are probably superfluous. The regex would already appear to exclude actual files since the regex excludes dots. And do you need to be able to access filesystem directories directly?
The character class [a-zA-Z0-9-/] is "confusing". The last hyphen is seen as a literal hyphen (which is presumably the intention), but at first glance it can look like a range specifier (as used earlier in the character class). To avoid confusion when matching a literal hyphen inside a character class, either backslash-escape it, or move it to the first or last character in the character class. eg. [a-zA-Z0-9/-].
You are also missing the L flag from the first rule. (You've included it on the second.) Do you also need the QSA flag? (ie. Are you expecting additional URL parameters on the initial request?)
Having revised the "extension removal" rules above, this does not matter so much, but these rules that rewrite the request to post.php and post-files.php should really be above the "extension removal" rules.
## Redirect from www - non-www
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ http://$1/$1 [R=301,L]
This rule is incorrect and in the wrong place. Canonical redirects (www to non-www and HTTP to HTTPS) should generally be above other rules. As mentioned above, redirects before rewrites.
But this rule is also wholly incorrect. $1 is a backreference to the first captured subpattern in the RewriteRule, so http://$1/$1 will naturally result in a malformed redirect. The first backreference should be %1 (to the last matched CondPattern) to match the requested hostname. Ordinarily, you should also be redirecting to HTTPS here, not HTTP. For example, the rule should read:
:
RewriteRule (.*) https://%1/$1 [R=301,L]
The ^ and $ surrounding the RewriteRule pattern are superfluous since regex is greedy by default.
## SSL Redirect
## RewriteEngine On
## RewriteCond %{HTTPS} ≠On
## RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
Although commented out, it is also incorrect. It needs to go before the other rewrites. It should go at the top of the file if implementing HSTS or after the www to non-www redirect if not (and minimising the number of redirects).
The CondPattern in the preceding condition should be !on, not ≠On (which is wholly invalid on two counts... ≠ is not valid and the comparison is case-sensitive. HTTPS will always be lowercase.)
You are also missing the R=301 and L flags.
No need for a capturing group in the RewriteRule pattern, since this is not being used in the substitution string. ^ would suffice (and be more efficient) instead of (.*).
## Create Error Pages
ErrorDocument 404 /errors/404.html
ErrorDocument 403 /errors/403.html
ErrorDocument 500 /errors/500.html
For readability, you should define your custom error documents at the top of the file. (Technically, it doesn't matter.)
## Redirect non-existing pages to index.php
Options +SymLinksIfOwnerMatch
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
For readability you should define the Options together at the top of the file (with -MultiViews). For example:
Options -MultiViews -Indexex +SymLinksIfOwnerMatch
(Disabling Indexes - auto-generated directory listings - is a good idea.)
You do not need to repeat the RewriteEngine directive. (Only the last instance of this directive does anything.) It is logical to place this rule near the top of the file, before your first mod_rewrite directive. (Although technically, the position of this directive in the file does not actually matter.)
Aside: You should be consistent in the prefix you use on your internal rewrites. On some rules you include the slash prefix (eg. /post.php), and on some you have omitted it (post-files.php). You have defined RewriteBase / (which isn't strictly required here as it happens) - RewriteBase only applies to relative substitution strings (ie. when the slash prefix is omitted).
UPDATE:
also i have file i want to exclude like 404.php in root directory from how do i exclude somefiles from the redirect. when i sent ajax to backend php file it redirected to homepage and failed to retrieve data.
To exclude specific files you would add a rule like the following, after the canonical redirects:
# Exclude "/404.php" from stripping the ".php" extension
RewriteRule ^404\.php$ - [L]
Generally, once you go extensionless for .php files you should be extensionless everywhere. So, there should be no unexpected redirects. The redirect is really only for SEO.
With regards to your AJAX requests, if you are making POST requests, then you could simply exclude all POST requests from further processing. For example:
# Prevent further processing of POST requests to ".php" files
RewriteCond %{REQUEST_METHOD} POST [NC]
RewriteRule \.php$ - [L]
Alternatively (or as well as), if your AJAX requests are setting a custom HTTP request header then you can check for this as well.
Summary
Bringing the above points together, it should look like this:
## Disable MultiViews and Indexes
Options -MultiViews -Indexes +SymLinksIfOwnerMatch
## Create Error Pages
ErrorDocument 404 /errors/404.html
ErrorDocument 403 /errors/403.html
ErrorDocument 500 /errors/500.html
RewriteEngine On
RewriteBase /
#### Canonical redirects
## SSL Redirect
## RewriteCond %{HTTPS} !on
## RewriteRule (.*) https://%{HTTP_HOST}/$1 [R=301,L]
## Redirect from www - non-www
## >>> CHANGE TO "HTTPS://"
RewriteCond %{HTTP_HOST} ^www\.(.+) [NC]
RewriteRule (.*) http://%1/$1 [R=301,L]
#### Rewrite Pages
RewriteRule ^post/([a-zA-Z0-9/-]+)$ post.php?ps=$1 [QSA,L]
RewriteRule ^([a-zA-Z0-9/-]+)$ post-files.php?ps=$1 [QSA,L]
#### Exceptions
## Exclude "/404.php" from stripping the ".php" extension
RewriteRule ^404\.php$ - [L]
## Prevent further processing of POST requests to ".php" files
RewriteCond %{REQUEST_METHOD} POST [NC]
RewriteRule \.php$ - [L]
#### Remove extensions
## Redirect to remove ".php" extension
RewriteCond %{THE_REQUEST} \s/+([^?]+)\.php[\s?] [NC]
RewriteRule \.php$ /%1 [R=301,NE,L]
## Rewrite to append ".php" extension if corresponding ".php" file exists
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^.]+)$ $1.php [L]
## Redirect non-existing pages to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
I have a list of unique data:
Suppose I have the following data:
id name
1 Jhon
2 Peter
3 Mark
4 Scotty
5 Marry
I make a .htaccess rule for id:
RewriteRule brandlisting/(.*)/ site/brandlisting?id=$1 [L]
RewriteRule brandlisting/(.*) site/brandlisting?id=$1 [L]
my URL is:
http://localhost/mate/admin/site/brandlisting/3
this works for id.
Now I need a .htaccess rule for name, so I make a rule for it:
RewriteRule brandlisting/(.*)/ site/brandlisting?name=$1 [L]
RewriteRule brandlisting/(.*) site/brandlisting?name=$1 [L]
http://localhost/mate/admin/site/brandlisting/Mark
When I used the above URL I was faced with following error in the console:
"NetworkError: 400 Bad Request -
http://localhost/mate/admin/site/brandlisting/Mark"
and in browser it shows:
Error 400 Your request is invalid.
My current .htaccess file
RewriteEngine on
RewriteCond %{HTTP_HOST} ^localhost/mate/admin$ [NC,OR]
RewriteCond %{HTTP_HOST} ^localhost/mate/admin$
RewriteCond %{REQUEST_URI} !wordpress/
RewriteRule (.*) /wordpress/$1 [L]
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php/$0 [PT,L]
#RewriteRule brandlisting/(.*)/ site/brandlisting?id=$1 [L]
#RewriteRule brandlisting/(.*) site/brandlisting?id=$1 [L]
RewriteRule brandlisting/(.*)/ site/brandlisting?name=$1 [L]
RewriteRule brandlisting/(.*) site/brandlisting?name=$1 [L]
I am starting with your current .htaccess you have crunch all the available rule which meets your needs in one single .htaccess for example rule for wordpress it should be in directory where your wordpress is installed.
Your rule as per your requirement should be like this if you are trying in root directory,
RewriteEngine on
RewriteBase /mate/admin/
RewriteRule site/brandlisting/([\d]+)/?$ site/brandlisting.php?id=$1 [L]
RewriteRule site/brandlisting/([a-zA-Z]+)/?$ site/brandlisting.php?name=$1 [L]
And for wordpress you directory you can create seperate .htaccess where you can put your rule index.php.
.htaccess rules rely on order. If you anticipate using a lot of routes, keep your htaccess rules simple and put your routes into PHP instead, using one of the several already written routing frameworks.
Here's an explanation as to why your .htaccess file isn't working, line-by-line:
RewriteEngine on
This turned the RewriteEngine on. No problems so far.
RewriteCond %{HTTP_HOST} ^localhost/mate/admin$ [NC,OR]
RewriteCond %{HTTP_HOST} ^localhost/mate/admin$
RewriteCond %{REQUEST_URI} !wordpress/
Only match RewriteRule is it's WordPress. This seems to be working, so let's ignore this block of rules.
RewriteRule (.*) /wordpress/$1 [L]
Options +FollowSymLinks -MultiViews
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
Only match below if the requested filename is not a file or a directory.
RewriteRule .* index.php/$0 [PT,L]
Rewrite any path PATH to index.php/PATH. Stop processing if it matched (note the L as last). That means nothing below will be activated.
#RewriteRule brandlisting/(.*)/ site/brandlisting?id=$1 [L]
#RewriteRule brandlisting/(.*) site/brandlisting?id=$1 [L]
RewriteRule brandlisting/(.*)/ site/brandlisting?name=$1 [L]
RewriteRule brandlisting/(.*) site/brandlisting?name=$1 [L]
Assuming that it doesn't match .* (aka, never), check path for other patterns. Note also that the two lines you have commented, and the two lines you don't, both match the same pattern. If one worked, the other would not.
-- Pro Tip: Regex has a shorthand for including a rule with a trailing slash and without one: /? is equivalent to, either with one slash, or with no slashes. Another way to write this is /{0,1}.
How to Fix
.htaccess redirect rules are a pain. My rule of thumb is to make them as easy as possible to write, which makes them easy to read and to maintain. How to do this? Push the redirect logic to your PHP program, rather than forcing Apache to rely on it.
Solution 1
The htaccess-only approach here would be to ensure you understand what Apache rewrite flags are telling your server to do, and adjust accordingly. You can do this here one of two ways:
Make your more specific rules show up first. i.e., move /site/brandlisting?name=$1 rules to before .* rules.
Add a separate rewrite conditions for any followup processing. As per the Apache2 documentation linked above:
The [L] flag causes mod_rewrite to stop processing the rule set. In most contexts, this means that if the rule matches, no further rules will be processed. This corresponds to the last command in Perl, or the break command in C. Use this flag to indicate that the current rule should be applied immediately without considering further rules.
The key point here is that it is within each rule set. Building a new rule set will continue processing.
Example that should work (not tested):
RewriteEngine on
RewriteCond %{HTTP_HOST} ^localhost/mate/admin$ [NC,OR]
RewriteCond %{HTTP_HOST} ^localhost/mate/admin$
RewriteCond %{REQUEST_URI} !wordpress/
RewriteRule (.*) /wordpress/$1 [L]
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php/$0 [PT,L]
#New Rule Set
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Note that /? is the same as writing two separate rules,
# one with a slash at the end, and one without.
RewriteRule brandlisting/(.*)/? site/brandlisting?name=$1 [L]
There are some great pre-built routers out there, like Silex and Slim. If you don't want to use them, you can still use your own internal logic that parses various pieces. From my experience, the more that I can pull out of my .htaccess file, the happier you'll be. It winds up being far easier to debug issues, and it's easier to iterate changes without introducing unintended consequences.
Solution 2
You can use PHP routers in conjunction with the .htaccess file I provided above, like so:
// Slim example
$app = new Slim\Slim();
$app->get('/brandlisting/:key', function ($key) {
if (is_numeric($key)) {
$id = $key;
// call/run $id logic
} else {
$name = $key;
// call/run $name logic
}
});
// ...
$app->run();
If you do this, you can remove any of your brandlisting logic from .htaccess and instead put it into your index.php.
Conclusion
If you can help it, experience tells me that it's better to not write your app logic into .htaccess rules. Instead, make your .htaccess rules simple and use a routing library. If you want to use .htaccess, make sure you understand the Apache rewrite flags you're using, and that Apache reads everything from top to bottom. For example, if the [L] flag is used, Apache stops reading all other rules in the rule set. That means, you have to create a new rule set with additional rules that need to be processed, or put your more specific rules first. Keep in mind that, if those rules have an [L] flag, they will also stop execution of any subsequent rules.
You can use redirect here.
Assuming you have the following folders:
<server root>/mate/admin
place in .htaccess in mate/admin
RewriteBase /mate/admin/
RewriteRule "site/brandlisting/([^\\]+)/" "site/brandlisting?id=$1" [R,L]
RewriteRule "site/brandlisting/([^\\]+)" "site/brandlisting?id=$1" [R,L]
You may be running into an issue where a Directory or other directive is causing your rewrite rules to repeatedly fire and cause infinite redirects.
See the documentation for RewriteRule Flags: L.
Specifically, the following quoted text is relevant:
If you are using RewriteRule in either .htaccess files or in
sections, it is important to have some understanding of
how the rules are processed. The simplified form of this is that once
the rules have been processed, the rewritten request is handed back to
the URL parsing engine to do what it may with it. It is possible that
as the rewritten request is handled, the .htaccess file or
section may be encountered again, and thus the ruleset may be run
again from the start. Most commonly this will happen if one of the
rules causes a redirect - either internal or external - causing the
request process to start over.
It is therefore important, if you are using RewriteRule directives in
one of these contexts, that you take explicit steps to avoid rules
looping, and not count solely on the [L] flag to terminate execution
of a series of rules, as shown below.
You may need to add a rewrite condition or take other steps to prevent looping.
I've made some PHP code that will direct the user based on the URL, and I've found some code for htaccess that gives the URL to the index page which lets my code work. However, it's also technically revealing what is a file/folder and what isn't.
If I go to website.com/somethingrandom/somethingelse, I'll get a 404 error, whereas going to website.com/cache/private will say forbidden.
How would I edit it so that it will act like no files exist, aside from a few select file types, such as images, css, and js files?
Here is the code as it currently stands:
RewriteBase /
RewriteEngine On
# If the request is not for a valid file
RewriteCond %{REQUEST_FILENAME} !-d
# If the request is not for a valid directory
RewriteCond %{REQUEST_FILENAME} !-f
# This rule converts your flat link to a query
RewriteRule ^(.*)$ index.php?_page_location=$1 [L,NC,NE]
Have your rules like this:
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L,NC]
# add trailing slash to directories
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule [^/]$ %{REQUEST_URI}/ [L,R=301,NE]
# If the request is not for known file types
RewriteCond %{REQUEST_URI} !\.(?:jpe?g|gif|php|bmp|png|ico|tiff|css|js)$ [NC]
# This rule converts your flat link to a query
RewriteRule .* index.php?_page_location=$0 [L,QSA]
If you want to hide some file or directory, i.e. appear it as not existant, you might redirect with the R|redirect flag
RewriteRule ^cache/private - [R=404,L]
This tells the client, there is no such file named cache/private (404). Beware though, that this is for all clients, even yourself.
To restrict this, you must prefix the rule with some RewriteCond or wrap it in some conditional statement like If or similar.
If you want to hide all files, use a "broader" regular expression, like
RewriteRule ^ - [R=404,L]
This will return a "Not found" for all of your website's URLs. You can also give a set of URLs, like in this
RewriteRule ^(?:cache/private|secrets|database) - [R=404,L]
which will hide everything below
cache/private
secrets
database
See Apache - Regular Expressions and http://www.regular-expressions.info/ for details on how to customize your own pattern.
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...
So I've been searching for a while now and can't find anything specific on how to create a pretty url / seo / slug url type system WITHOUT sending everything to a index.php or moving things into subfolders.
Basically I'm making a website which you can currently go to urls like movie.php?id=#### / show.php?id=####. Ideally I'd like the url to be movie/#### or movie/id/#### (or down the line slugs of the name that i can use to grab the right one) etc.
Is there a way to do it without having a single index.php router or am I just going to have to rewrite all my files to adhere to this style?
You can create a rewrite rule in .htaccess that routes the movie urls to movie.php as follows:
movie/123:
RewriteRule ^movie/(\d+)$ movie.php?id=$1 [L]
movie/id/123:
RewriteRule ^movie/id/(\d+)$ movie.php?id=$1 [L]
movie/title-of-movie:
RewriteRule ^movie/(\S+)$ movie.php?slug=$1 [L]
movie/title/title-of-movie:
RewriteRule ^movie/title/(\S+)$ movie.php?slug=$1 [L]
combination movie/123/title-of-movie:
RewriteRule ^movie/(\d+)/(\S+)$ movie.php?id=$1&slug=$2 [L]
Edit: added a full .htaccess example for 1 required with up to 2 extra optional parameters with a fallback on index.php if the url is not for movies.
Options -Indexes
IndexIgnore */*
Options FollowSymLinks
AddDefaultCharset utf-8
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^movie/([^/]+)/?([^/]*)/?([^/]*)$ movie.php?param1=$1¶m2=$2¶m3=$3 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule . index.php [L]
</IfModule>
^ to match from the beginning
$ to match until the end
? for 0 or 1 occurrence
+ for 1 or more occurrences
* for 0 or more occurrences
If the url rule does not match and the file does not exist then it will route the url to index.php, but you can remove that last part if you don't want that.
Yes, assuming your URL structure follows a relatively consistent pattern, you can definitely do this with an .htaccess file and mod_rewrite (without the need for an index.php file, commonly referred to as a front controller).
Here's a really simple example:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.*)/(.*)$ $1.php?id=$2 [NC,L]
This takes an incoming URL like http://example.com/movie/3 and performs a transparent/internal rewrite (so the user doesn't see the URL change) to http://example.com/movie.php?id=3.
Of course, this example could be expanded to handle more parameters, etc. but hopefully this gets you started on the right path. I highly recommend you read the mod_rewrite documentation for more details: http://httpd.apache.org/docs/2.4/mod/mod_rewrite.html