.htaccess question - URL-rewriting - apache

I have an issue with URL-rewriting in .htaccess. Here is .htaccess file:
RewriteEngine On
RewriteBase /community/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^view-all-results$ forums/index.php?view=view-all-results [R=302]
RewriteRule ^view-all-results/$ forums/index.php?view=view-all-results [R=302]
I need to rewrite url like "/community/view-all-results?u=2" to "community/forums/index.php?view=view-all-results&u=2".
But according to the above rule I'll get "community/forums/index.php?view=view-all-results".
I tried to change RewriteRule to
RewriteRule ^view-all-results?(.*)$ forums/index.php?view=view-all-results&$1 [R=302]
But it doesn't work properly. It still rewrites URL to "community/forums/index.php?view=view-all-results".
When I changed rule(put + instead of *):
RewriteRule ^view-all-results?(.+)$ forums/index.php?view=view-all-results&$1 [R=302]
I've got URL like "community/forums/index.php?view=view-all-results&s". So I don't understand this behavior.((
I will be very appreciated for any suggestions.

The magic flag is in the docs: [QSA], which will add the original querystring to your url.
Normal matching is only done against the path, not agains the querysting, which you would find in the magic variable %{QUERY_STRING}). Matching this variable can be done in a RewriteCond condition. You could also append this variable to the resulting url, but QSA is infinitely more userfriendely here.

Give this a try...
RewriteEngine On
RewriteBase /community/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^view-all-results/?$ forums/index.php?view=view-all-results [QSA]
Basically the first half of a RewriteRule doesn't match against the QUERY_STRING, so you second to example will never match against it. The main thing your first code was missing was the QSA flag, which tells it to pass the QUERY_STRING it receives along with the newly created QUERY_STRING. I also removed the R=302, as I assume you don't want the URL to change.
Edit: Oh, I also combined the rules by making the trailing slash optional.

Related

handle image URL (.htaccess) by passed variable

I would like to handle my image URLs in two different ways.
First, when the browser calls for:
http://example.com/image.jpg (need to be shown)
Second, when the browser calls for:
http://example.org/image.jpg?actionId=123 (need to be URL rewrote to index.php?actionId=123)
The point is, when the URL has it's specified variable, then we need to redirected to the index.php with that variable and it's value.
I'm using .htaccess with mod_rewrite, which is the following now:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?q=$1 [QSA]
</IfModule>
So it's checks for existing file or directory, any other way, it's passed to index.php in 'q' param.
Thank you in advance!
For the first example you don't need to do anything, the image will be shown if it exists. Therefore you only need to consider the case with the query string:
RewriteEngine On
RewriteCond %{QUERY_STRING} actionId=([^&]+)
RewriteRule \.jpg$ index.php?actionId=%1 [L]
If there are other parameters that you also need to pass to to index.php then just doing the rewrite should be enough as the query string is sent by default. To be sure use the QSA flag:
RewriteEngine On
RewriteCond %{QUERY_STRING} actionId=([^&]+)
RewriteRule \.jpg$ index.php [QSA,L]

.htaccess Get requests in the URI

I don't know how I would word this, and I can't make sense of the docs for httpd so I was wondering if anyone knew how to do this.
I would like to get
www.example.com/v/12345/yadayada.png
to actually go to
www.example.com/view?key=12345&img=yadayada.png
I've seen this done some websites but I cant find out how to do this.
Thanks
Edit 1:
I tried this, and then entered the following URL:
www.example.com/v/3f210a2c76cb100f4f7fbd7691a9eb967cb7a1a7/10b78802581bfd59f3fe2b447575bdf7.png
When I did this I got the following error:
The requested URL /v/3f210a2c76cb100f4f7fbd7691a9eb967cb7a1a7/10b78802581bfd59f3fe2b447575bdf7.png was not found on this server.
This is my current .htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
RewriteRule ^([^./]+\.png)$ /i/$1 [L,NC]
RewriteRule ^v/([0-9]+)/([^/.]+\.(png|jpe?g|gif))$ /view.php?k=$1&img=$2 [L]
#JonLin had the right rule, but the rewrite rule you have declared before that one,
RewriteRule ^([^./]+\.png)$ /i/$1 [L,NC]
is applied to the example url you provided. So, with a request like
www.example.com/v/3f210/10b7.png
would get rewritten to
www.example.com/i/v/3f210/10b7.png
It's worth noting the Flags used for your rules
L - Stop the rewriting process immediately and don't apply any more rules
NC - Makes the pattern comparison case-insensitive.
If you were to remove that rule you would get the results you want. You should also determine if that rule is needed and modify it, the flags, and/or rearrange the order of your rules.
RewriteEngine On
RewriteRule ^v/([0-9]+)/([^/.]+\.(png|jpe?g|gif))$ /view.php?k=$1&img=$2 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
Try these rules in the htaccess file in your document root:
RewriteEngine On
RewriteRule ^v/([0-9a-f]+)/([^/.]+\.(png|jpe?g|gif))$ /view?key=$1&img=$2 [L]

Apache Mod Rewrite with Periods in URL

Ok,
so I am using (or trying to use) two primary mod_rewrite rules, and they seem to be conflicting with one another
RewriteRule ^/?help$ index.php?page=help [L]
and
RewriteRule ^/?([a-zA-Z0-9._-]+)$ index.php?user=$1 [L]
If I get rid of the period ->. in the second rule, my help page is displayed, and I can display a user page as well, but when I add the period, my help page doesn't display, but instead (I think) gets processed as a user page.
Anyone have any pointers?
I looked at something another user ran into here - Apache / mod_rewrite / Periods messing with pattern , and modified his rule, and it is working -
RewriteRule ^/?help$ index.php?page=help [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?([a-zA-Z0-9\[\]\.()+|_-]+)$ index.php?user=$1 [L]
Thankyou for the response.
First, if you are doing this in .htaccess mod_rewrite does not stop processing but instead does an internal redirect. See this answer for details.
You need to escape the period in your second rewrite rule. Period (or dot) will match any character if not escaped.
Fixed rule:
RewriteRule ^/([a-zA-Z0-9\._-]+)$ /index.php?user=$1 [L]
Edit 3:
Based on your comments and own answer, here's an updated solution. The way RewriteCond %{REQUEST_FILENAME} works in Apache depends on the context you are in. You can also omit the ? from the matching pattern.
RewriteRule ^/help$ /index.php?page=help [L]
# If you are inside <VirtualHost> context
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteRule ^/([a-zA-Z0-9\._-]+)$ /index.php?user=$1 [L]
# If you are inside <Directory> or .htaccesscontext
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/([a-zA-Z0-9\._-]+)$ /index.php?user=$1 [L]
Do bear in mind that this solution causes conflicts if there are users with the same name as any of the files or directories you have on your server.

RewriteCond strange behavior (file exists check)

I can't understand why redirect depends on RewriteRule (not on RewriteCond).
My .htaccess:
Options +FollowSymLinks +SymLinksIfOwnerMatch
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.*)$ true.txt
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ false.txt
</IfModule>
Root folder contains:
true.txt (contains 'true')
false.txt (contains 'false')
test.txt (contains 'test')
If I try to open test.txt I get true and if I try to open nonexist.txt i get true too.
Now I change my .htaccess:
...
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.*)$ $1
...
And now if I try to open test.txt I get test and if I try to open nonexist.txt i get false.
UPDATE: Thanks for answers, I understood how it works but one problem still exists.
If I try to check 'if file exists' in another directory it always returns false.
/files/test.txt
/script/.htaccess
/script/false.txt
/script/true.txt
now my .htaccess looks like
RewriteCond %{REQUEST_FILENAME} .*(true|false).*$
RewriteRule .* - [S=2]
RewriteCond %{DOCUMENT_ROOT}/files/%{REQUEST_FILENAME} -f
RewriteRule ^(.*)$ true.txt [L]
RewriteCond %{DOCUMENT_ROOT}/files/%{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ false.txt [L]
I always get false.
I also tried RewriteCond ../files/%{REQUEST_FILENAME} and also always get false result.
If I move test.txt in script folder then and change RewriteCond %{REQUEST_FILENAME} all works fine.
It's because of the way mod_rewrite works: the user requests test.txt, mod_rewrite catches the requests and rewrites the URI to false.txt, then it makes a second pass, by sending an internal request for false.txt, which is caught and rewritten to true.txt. Then a third pass is made, the request is caught and rewritten to true.txt, but since the URI stays the same, no more passes are made.
It's rather counter-intuitive, but there's logic to it. Here's the control flow diagram from the docs:
The [L] flag is often advertised as a magic bullet to stop the recursion, but in fact it just ensures that once a request matches a pattern, then the execution stops and no further processing will take place in that pass, but the internal request will be sent out anyhow, so a second pass is made through the same ruleset. The execution stops only if the URI is unchanged after a pass.
re: update
Your problem is, the REQUEST_FILENAME environmental variable actually holds a path (by default the full filesystem path, but there are a few twists to that), so %{DOCUMENT_ROOT}/files/%{REQUEST_FILENAME} ends up being something horrible.
As for a solution... well, it's tricky, I think. It'd be a lot easier if the .htaccess were in root. The only solution I can think of right now is:
RewriteEngine on
RewriteCond %{REQUEST_URI} script/(.*)$
RewriteCond %{DOCUMENT_ROOT}/files/%1 -f
RewriteRule .* true.txt [L]
RewriteCond %{REQUEST_URI} !(true.txt)|(false.txt)
RewriteRule .* false.txt [L]
It's rather ugly, and not very scalable or portable. In the first condition I get the file's name, in the second I check if it exists, and if it does, it's true. Everything else is false. Then again, if the files directory is also in the scope of the .htaccess, it's easier and nicer by magnitudes.
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_URI} !(true|false)\.txt$
RewriteRule .* true.txt [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* false.txt [L]
Note the second RewriteCond to prevent rewriting true.txt and false.txt files, and L flag on the rules to stop rules execution
These are to prevent rules loop
UPDATE:
%{REQUEST_FILENAME} is full path, hence if you add it to some path, you'll get false (it will try to match this, essentially: /var/www/subfolder/var/www/filename.txt
To match a file in another folder you will need a match vs URI part...
Here's how you can do it:
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_URI} ^/([^/]+)$
RewriteCond %{DOCUMENT_ROOT}/files/%1 -f
RewriteRule .* files/$0 [L]
The first condition checks if the request was to some filename in the root directory (it checks that uri starts with a /, but does not contain any more slashes
Note that the first condition encloses everything but the slash in the beginning with parentheses - this matched subpattern will be used later
The second condition ensures the file, which name is saved in subpattern %1 (matched by first condition) exists in subfolder files/ inside %{DOCUMENT_ROOT}
If both the rules matched, the request is rewritten to that file (via sub-request - the browser is not redirected).
Instead of using "RewriteCond %{REQUEST_FILENAME} !-f" you can try:
"RewriteCond %{THE_REQUEST} !-U", which checks the if the address exists.
Sometimes the file path and the address where the file is served are different, making the former unusable.
example:
RewriteEngine On
RewriteCond %{THE_REQUEST} !-U
RewriteRule ^(.*/media/.*)\.(gif|png|jpe?g)$ https://xyz.company.com$1.$2 [NC,L,R=301]

Help with mod_rewrite rule for dynamic url

Ugh.. mod_rewrite makes me feel stupid. I just haven't wrapped my brain around it yet. :/
I have this url:
http://example.com/a/name/
...that I want to point here:
http://example.com/a/index.php?id=name
...where name is what is getting passed to index.php as the id argument.
Anything I've tried results in either a 404 or a 500.. :(
If you want the trailing slash to be optional, you have to exclude the file you are rewriting the request to. Otherwise you will have a nice infinite recursion.
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/a/index\.php$
RewriteRule ^/a/([^/]+)/?$ /a/index.php?id=$1 [L]
Here any request that starts with /a/… but it not /a/index.php is rewritten to /a/index.php.
But if the trailing slash is mandatory, there is no need to exclude the destination file:
RewriteEngine on
RewriteRule ^/a/([^/]+)/$ /a/index.php?id=$1 [L]
To start you off:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !index.php
RewriteRule ^/?a/([^/]+)/?$ /a/index.php?id=$1 [QSA,L]
If one rewrite tutorial doesn't work for you, try another.
Edit: excluded index.php as per Gumbo's suggestion
Maybe something along the lines of
RewriteEngine on
RewriteBase /a/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/?$ index.php?id=$1 [L,QSA]
would do the trick.
I suggest you take a look at this URL:
http://www.dracos.co.uk/code/apache-rewrite-problem/
The presented solutions will work, but there are some caveats explained in the URL, mainly regarding ? and # in the URLs themselves.