htaccess RewriteRule: filter certain words - apache

I have
RewriteRule ^post/([^/]+)/([^/]+)$ /post/index.php?$1=$2 [NC]
which does what it's supposed to do: take a URL like post/color/black and turn that into post/index.php?color=black.
The problem is that this also affects things like the stylesheet (located at post/styles/style.css), and other files that really exist.
So the question is: if I know the exact $_GET keys that need to be translated, how can I limit the above RewriteRule to only do its magic for those specific keys, but leave everything else untouched?
Thanks.

You can use:
^post/([^/]+)/(black|white|...)$
or
^post/([^/]+)/((?!bad keywords)[^/]+)$

You can either:
Use the -f flag to exclude actually existing resources from the rewrite process by adding the following RewriteRules:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
Or store your static resources outside /post - this would be best because you can exclude the possibility of collisions with 100% certainty, and you save Apache from looking the file up (which is only relevant with a lot of traffic though).

Related

Apache mod_rewrite path to query string for specific path format

I've been working on this for weeks. I want to be able to use a friendly URL to pass variables to a PHP script. For example, if someone uses this URL:
https://example.com/foo/bar/who
I would like my PHP script to receive this:
https://example.com/index.php/?var1=foo&var2=bar&var3=who
The catch is that I ONLY want to do this rewrite when there are three vars in the path. If there are fewer or more than three, I do not want to rewrite the URL.
I've seen several other explanations related to this type of rewrite but nothing quite like this.
This is almost working, but not quite. I only want the rewrite done if there's something present for those first three variables. I know this is incomplete, but with this method at least the REQUEST_URI contains the values I can parse. But again, I only want to do this when there are three vars in the path.
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule !^index\.php/([^/]*)/([^/]*)/([^/]*)$ index.php [L]
Thank you.
You were pretty close, have it this way. Please make sure you clear your browser cache before testing your URLs. You had already created back references only thing you needed to use them, which I have added those now.
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]*)/([^/]*)/([^/]*)$ index.php?var1=$1&var2=$2&var3=$3 [L]

Editing .htaccess file to modify URL

I'm trying to modify my .htaccess file to modify my URL and have tried many methods but cannot achieve exactly what I want. For example I have this URL:
http://mywebsite.com/FOLDER/index.php?id=5
Now I want it to look like:
http://mywebsite.com/FOLDER/5
or
http://mywebsite.com/FOLDER/ID/5
My .htaccess contains the following code:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^index/([0-9]+)/([0-9a-zA-Z_-]+) index.php?id=$1 [NC]
I cannot figure out what's wrong. Thanks.
You can use:
RewriteEngine on
# external redirect from actual URL to pretty one
RewriteCond %{THE_REQUEST} \s/+FOLDER/index\.php\?id=(\d+) [NC]
RewriteRule ^ /FOLDER/%1? [R=301,L,NE]
# internal forward from pretty URL to actual one
RewriteRule ^FOLDER/(\d+)/?$ FOLDER/index.php?id=$1 [L,QSA,NC]
The first argument of RewriteRule is what the incoming url without domain and without preceding paths (more on that later) is going to be matched against. This url is, in your case, http://mywebsite.com/FOLDER/5. Assuming that your .htaccess file is in your DocumentRoot, the regex will match against FOLDER/5.
You are currently trying to match FOLDER/5 with ^index/([0-9]+)/([0-9a-zA-Z_-]+), which is not going to work. A better regex would be ^(.*)/([0-9]+)$ or ^(.*)/ID/([0-9]+)$. You can then rewrite to $1/index.php?id=$2. I would recommend using the [L] flag to stop rewriting for this round to avoid common problems with multiple rules matching while you do not expect them to.
Besides this, make sure that your .htaccess files are being read (e.g. by checking that if you enter garbage, you get a 500 internal server error), that mod_rewrite is enabled, that you are allowed to override FileInfo. You also may need to turn AcceptPathInfo off.

How to use mod_rewrite to direct anything but PHP pages to index.php?

I have a question that is a bit confusing. I'm trying to understand mod_rewrite but I am pretty confused by it.
What I'm trying to do is redirect all URLs such as /settings/account or /user/user123 to index.php. A PHP script (which I already created) uses $_SERVER['REQUEST_URI'] to break the URL down into pieces then uses include. For example it would include settings.php?page=account or user.php?uid=user123.
But if the URL is /settings.php?page=account or /user.php?uid=user123 I don't want it to be redirected through index. In other words, if the URl has a file extension, just go to that file, but if it doesn't (like /settings) go to index.php to process where it should go.
How can this be done? Thanks in advance for any suggestions!
If you don't want to use the commonplace redirect-every-url-which-has-no-corresponding-file approach, you can also try your approach. To redirect anything without dot to a common script, use:
RewriteRule ^([^.]*)$ index.php?path=$1
You might want to exclude some URLs still, like images/ or css/ etc. Use a simple RewriteCond before the rule then:
RewriteCond %{REQUEST_URI} !images/
RewriteCond %{REQUEST_URI} !css/
What you need is a RewriteCond directive with !-f and !-d patterns.
RewriteCond checks whether a user's HTTP request matches provided condition. In your case, you would want to check if a requested file (which is provided in a variable %{REQUEST_FILENAME}) already exists on your document root using the !-f postfix. Similarly, if you want indexing in directories, you can add the same pattern with !-d, which will check if requested directory is on your document root.
So these two lines before the actual RewriteRule would do the trick:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

how to make url rewrite apache whitout any rewrite condition?

sorry, but i'am less understand about url rewrite...
i want to rewrite my url from :
http://localhost/controller/index.php/user/edit
to
http://localhost/controller/user/edit
i can make it with this .htaccess :
RewriteEngine On
RewriteBase /controller/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [PT,L]
but, the rewrite works if there is no file exist at controller/user/edit.php
i want every request to under my controller/xxx is rewrited to controller/index.php/xxx whether the file is exist or not....
i have remove the RewriteCond so my current one is like this :
RewriteEngine On
RewriteBase /controller/
RewriteRule ^(.*)$ index.php/$1 [PT,L]
but, it shown internal service error..
There are a lot of things that don't make sense to me. Mainly, your question says to want to rewrite a URL having index.php in it to one that does not, but your rewrite rule, which you say works in some cases does the opposite, it pre-pends index.php to requests.
If you have access to your apache error and access log, you might see if there's more information about exactly at what point the error occurred -- was it when the .htaccess file was processed, or was it from within your php program?
I will assume that the goal here is to take "pretty" urls like /controller/user/edit and have the index.php program actually process the /user/edit part of the path.
If so, I think you may want to set the RewriteBase to /, and change your .htaccess to
RewriteEngine On
RewriteBase /
RewriteRule ^(.*)$ controller/index.php/$1 [PT,L]
The RewriteBase / directive says that all requests are relative to the server's DOCUMENT_ROOT setting. The change to the rewrite rule instructs all requests to go to the directory controller and file index.php, appending the original requested path afterwards.
(Note: I don't think you want to use the PT flag in this case, and it would be better form to escape the . which is a regex operator as index\.php, but I think neither of these are relevant to the problem here)
It is not clear if you do want the / before the $1. If your PHP program (index.php) is getting called with it present, and knows how to handle it, then it's fine, but it's a little unusual, and there may be cases where you end up with multiple /'s from within the php program.
But do you really want to do this? The typical use of the RewriteCond %{REQUEST_FILENAME} !-f is to handle cases such as image files and css or javascript files that are static and need not be handled by your controller. RewriteCond %{REQUEST_FILENAME} !-d depends on your system (but it's purpose to see that the request is not for a directory).
Anyway, the basic change as I proposed might help, but if not, perhaps you can clarify your intent and provide some actual URLs and a look inside index.php

How do I get apache RewriteRule working correctly for a subdomain?

I just setup a subdomain with the following RewriteCond:
RewriteCond $1 !^search.php$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/?([^/]+)$ search.php?q=$1 [L,NS]
I'm using the same rewrite condition on my main domain and it works perfectly. However, when I set it up on the subdomain, it simply outputs "index.php" when going to http://sub.domain.com
Every page on the subdomain outputs the page name in the body instead of processing the code, except for the search page, which appears to be working correctly.
What can I do to correct this issue?
I haven't played with your exact regex with mod_rewrite, but if I was looking at writing that regex in another engine, I would have to escape the slash. Also, given that $ is used to indicate a back reference, would that need escaping too (would your $ symbols in the regex be necessary as there is likely to be more text in the URI and it is not matched at the end of a string)?
I would try
RewriteCond $1 !^search.php$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/?([^\/]+)$ search.php?q=$1 [L,NS]
One other thing. Normally $ at the end of a regex means "only match if this is the end of the string". So from that, if RewriteCond is matching on ^search.php$ but the URL is search.php?q=... then I would think that this wouldn't match because search.php is not the end of the string. So that would look like the following (assuming you don't need to change anything else from your original).
RewriteCond $1 !^search.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/?([^/]+)$ search.php?q=$1 [L,NS]
In the main config the path always begins with / and you need an absolute path:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !^search.php$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/([^/]+)$ %{DOCUMENT_ROOT}/search.php?q=$1 [L]
In an .htaccess you need a RewriteBase which is stripped from the url (no / in the Rule now) and the path is relative.
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !^search.php$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]+)$ search.php?q=$1 [L]
Several things come to mind here:
I have a few suggestions/comments/gotchas. Hopefully one of them is useful to you:
Make sure search.php isn't just echoing out its $_GET parameters. While this sounds obvious in retrospect, it's one of the more overlooked solutions.
RewriteRule works slightly differently when you specify it in a server configuration file than if you specify it in an .htaccess. Specifically, ^/ is wrong in a server config version as the entire URL is used (http://sub.domain.com/blah).
Make sure no other rewrite rules are being processed for this subdomain first, either in the main httpd.conf / apache2.conf or .htaccess.
Make sure RewriteEngine On appears in your configuration, as it is activated per-VirtualHost.
The NS flag will ignore redirects done using a relative Redirect or relative RewriteRule.
It sounds like the pattern '^/?([^/]+)$' may not be matching at all.
I'd activate RewriteLog, crank RewriteLogLevel to level 3 or above, and see if your pattern is matching at all. If not, start with a simpler pattern, and then work your way to a more complex pattern.
Or, something else is matching the pattern, so the request never gets to 'RewriteRule ^/?([^/]+)$' at all. You will see this in the RewriteLog.
I believe I recently had a problem where '^/' didn't match in certain cases on a Virtual Host. But '/' worked. The folks in the #httpd on Freenode.org helped me. If I can find this in my notes, I'll post it here.