I am implementing a caching system for dynamically generated images. The script is called via /img/type/param1/param2.png, where multiple types are possible and the number of parameters are variable. The script generates the image and dumps it to disk.
I would like .htaccess rules, which when requesting the image generation script:
checks to see if a cached file exists
if so, mod_rewrite to the cached file
if not, don't do anything so that the script runs
What I have so far is a slightly modified logic:
mod_rewrite to where the cached file would be
check to see if the file exists
if not, mod_rewrite the request back again
If there's a better way to do this, I'd love to hear it. In any case, the relevant part of my .htaccess file:
RewriteRule ^img/(type1|type2)/(.*)$ /images/cache/$1/$2
RewriteCond /^(.*)$ !-f
RewriteRule images/cache/(.*) /img/$1
This doesn't seem to work quite right. To debug it, I inserted the following after the first RewriteRule (the target page just dumps its input):
RewriteRule ^(.*)$ /htaccess.php?url=$1 [END]
As a result, I get:
Array
(
[url] => /images/cache/a/l/300.png/a/l/300.png
)
I don't understand why $2 contains l/300.png/a/l/300.png instead of just l/300.png.
If I change first RewriteRule to include an [L], I get the expected result. However, I experience the exact same "double-matching" issue on the second RewriteRule which reverts the request back into the non-cache version. However, adding [L] to this second RewriteRule:
RewriteRule ^img/(type1|type2)/(.*)$ /images/cache/$1/$2 [L]
RewriteCond /^(.*)$ !-f
RewriteRule images/cache/(.*) /img/$1 [L]
yields an Internal Server Error.
What am I doing wrong, and how do I fix this issue?
The first logic that you have is what you want to be doing, that bypasses the possible looping issues. You just need to extract the relevant bits from the %{REQUEST_URI} then backreference them using % references. So for example:
RewriteCond %{REQUEST_URI} ^/img/(.*)$
RewriteCond %{DOCUMENT_ROOT}/images/cache/%1 -f
RewriteRule ^img/(.*)$ /images/cache/$1 [L]
or using the regex patterns that you had:
RewriteCond %{REQUEST_URI} ^/img/(type1|type2)/(.*)$
RewriteCond %{DOCUMENT_ROOT}/images/cache/%1/%2 -f
RewriteRule ^img/(.*)$ /images/cache/$1 [L]
Related
I have a simple .htaccess file which is supposed to redirect users from /listing/$id to /listing?id=$id. I've tried and tested this script on another domain and it works, yet for some reason it does not work here. I had to alter a couple of things in the scripts, but the logic is almost exactly the same to the original. Maybe I've missed something, but here is the final .htaccess file:
Options +FollowSymLinks -Indexes -MultiViews
RewriteEngine On
# remove php extension
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule !.*\.php$ %{REQUEST_FILENAME}.php [QSA,L]
# only allow rewriting to paths that don't exist
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.+) - [PT,L]
# /listing/$id
RewriteRule ^listing/([\w-]+)/?$ listing.php?id=$1 [L,QSA,NC]
And then when I go ahead and try and retrieve the data on my server side, an empty array is returned. listing.php:
// will return array(0){ }
die(var_dump($_GET));
All help is appreciated, cheers.
I am able to replicate the problem and found it is because of the # remove php extension condition and rule. If I delete those 2 lines then it works as expected. It seems to me as though that rule is counter to the comment above it, i.e. it looks like the rule is adding the php extension not removing it as the comment suggests.
It seems as though REQUEST_FILENAME is being set to "listing" from the url, so if the php file is called listing.php then it will match the first condition but the rule can't be applied because the pattern doesn't then match.
If I keep all your conditions and rules as they are except change the php filename to "listingTEST.php" and the last rule points to that file then it also works because in this case the first condition is no longer met. e.g.
RewriteRule ^listing/([\w-]+)/?$ listingTEST.php?id=$1 [L,QSA,NC]
I'm working on a .htaccess file and have come across some curious behavior with REQUEST_FILENAME that I'd love some clarification about. I have two rules I'm testing out which are like so:
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^.*$ /index.php [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/index.php$ /other_page.php [L]
When I try to go to the address site.com/this_file_exists.php I seem to be getting to other_page.php, which means that
REQUEST_FILENAME was a file in the first RewriteCond but not a file
by the time mod_rewrite processed the second RewriteCond.
After changing the second RewriteRule's flags to [L,E=RF:%{REQUEST_FILENAME}], and echoing $_SERVER['REDIRECT_RF'] on other_page.php, I find that the request filename was just /index.php, as opposed to the original filename, which was /full/path/to/this_file_exists.php.
Does mod_rewrite consistently overwrite the REQUEST_FILENAME in this way after matching a RewriteRule? If so, is there a documented way in which it does that?
These lines in mod_rewrite.c
/* Now adjust API's knowledge about r->filename and r->args */
r->filename = newuri;
seem to suggest that the new REQUEST_FILENAME truly is
the rewritten URI.
Before anyone comments, I know there are a lot of posts created on this topic, but none of them seem to solve my problem, that is why I have started this thread.
So, I have a page in my website called project.php which is used in GET query like so: project.php?id=12 I want to have a .htaccess file that converts the given URL into localhost/MyWeb/project/id/12/. I've literally followed every single post regarding that topic but none of them seem to work.
Also, along with that, I want all my .php and .html files to be shown just with their names, i.e localhost/MyWeb/index.php/ becomes localhost/MyWeb/index/ and localhost/MyWeb/sub1/sub2.php becomes localhost/MyWeb/sub1/sub2/.
EDIT:
The reason why I did not add my work in first place was because I didn't think it would be any helpful. But here it is:
RewriteEngine On
RewriteRule ^([0-9]+)$ project.php?id=$1
RewriteRule ^([0-9]+)/$ project.php?page=$1
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
RewriteRule ^([^\.]+)$ $1.html [NC,L]
Firstly, you are operating out of a sub-directory (MyWeb), which means you need to set a RewriteBase. Also, you need to ensure that your .htaccess file is placed inside that sub-directory, and not in the localhost document root.
So, below RewriteEngine on, insert the folloeing line:
RewriteBase /MyWeb/
Next, you stated that you want to convert project.php?id={id} to project/id/{id}, but your code omits the /id/ segment. I also noticed that you have two rules, and that the second one contradicts your question, so I am only going to show you the change you need to make for the first rule, until such time as you clarify what the second rule is for.
To make the project URI work, change the very first rule to:
RewriteRule ^project/id/([0-9]+)/?$ project.php?id=$1 [QSA,L]
This will match the URI you want, with an optional trailing slash. I've also added the QSA flag which appends any extra query string parameters to the rewitten URI, as well as the L flag which stops processing if the rule is matched.
Next, to omit the .php or .html from your URIs, change the last three lines to the following:
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^([^\.]+)$ $1.php [L]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^([^\.]+)$ $1.html [L]
When you make a request to localhost/MyWeb/index, Apache will check to see if localhost/MyWeb/index.php or localhost/MyWeb/index.html exist, and will then serve whichever one it finds first.
If you have both the PHP and HTML files, then the PHP one will be served, and not the HTML one. If you prefer to serve HTML files, then swap the two blocks around.
Unfortunately, I don't know of a good way to force a trailing slash for these, specifically because of the condition that checks for their existence. In other words, it won't work if you request sub2/, with the trailins slash because it would need to check if sub2/.php exists, which it does not.
Update: For added benefit, place these two blocks just below the new RewriteBase you set earlier to redirect the old URIs to the new ones whilst allowing the rewrites to the new URIs to still work:
RewriteCond %{THE_REQUEST} \/project\.php\?id=([0-9]+) [NC]
RewriteRule ^ project/id/%1/ [R=302,L,QSD]
RewriteCond %{THE_REQUEST} \/MyWeb/(.+)\.(php|html)
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ %1 [R=302,L]
For reference, here's the complete file: http://hastebin.com/gacapesoqe.rb
I have a URL i.e "www.mysite.com". I want to send parameters via url in following ways:
www.mysite.com/count
www.mysite.com/search_caption?query=huha
www.mysite.com/page=1
www.mysite.com/search_caption?query=huha&page=1
In each of these cases I want to load index.php page with parameters as follows for each case:
var_dump($_REQUEST) results into [count]
var_dump($_REQUEST) results into [query="huha"]
var_dump($_REQUEST) results into [page=1]
var_dump($_REQUEST) results into [query="huha",page=1]
How do I write .htaccess file to achieve this?
I am using this code but it is capturing only params after "?" and not everything after first slash
Options +FollowSymLinks
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
#RewriteRule ^([^/]+)/?$ index.php?{REQUEST_FILENAME}=$1 [L,QSA]
RewriteRule .* /index.php [L]
Something like that should get close, though you really should think about those strange URL patterns instead of trying to fix them afterwards with rewriting...
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L,QSA]
RewriteRule ^count index.php?count=1 [L]
RewriteRule ^page/(.*)$ index.php?page=1 [L]
RewriteRule ^ index.php [L,QSA]
Some notes:
the first three RewriteRules are exceptions necessary because your given requests do not follow a sane and common pattern. They appear somewhat chaotically chosen.
this certainly is not free of issues, I did not test it, only typed it down.
this assumes the "page" example to be requested like as discussed in the comments.
index.php actually has to exist as a file, otherwise this will result in a rewrite loop
Given all that these rewritings should happen:
www.mysite.com/count => index.php?count=1
www.mysite.com/search_caption?query=huha => index.php?query=huha
www.mysite.com/page/1 => index.php?page=1
www.mysite.com/search_caption?query=huha&page=1 => index.php?query=huha&page=1
Also note that the rules above are written for .htaccess style files. To be used as normal rules, so inside the http servers host configuration, they would have to be written slightly different. You should only use .htaccess style files if you really, really have to, so if you have no access to the configuration files. You should always try to avoid those files if somehow possible. They are notoriously error prone, hard to setup and debug and really slow the server down. So if you have access to the http server configuration, then defines such rules in there instead.
The real content is at domain.com/view.php?id=image_id
I want to have it be accessible with domain.com/view/image_id
The following is currently there to get the .php file extensions out.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
Appending the following to the htaccess doesn't work:
RewriteRule ^view/([A-Za-z0-9]+). /view.php?id=$1 [L, QSA]
Also, I am fine with having everything after view.php? (view.php?id=) get taken into the php file and from there I can separate everything out by slashes and implement their data.
I have looked at many solutions here on stackoverflow and elsewhere but either they do not apply to me or something is wrong with my server. Either way, I get an internal 500 server error. Thanks.
You need to place the view rule before the more general php extension rule:
RewriteEngine On
RewriteRule ^view/([A-Za-z0-9]+)$ /view.php?id=$1 [L,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
Also, you don't want that space after the L,.
^view/([A-Za-z0-9]+).
^---single character wildcard
That . at the end there is matching/consuming one of your ID values, so if the url is
/view/foobarbaz
Your capture group will actually be foobarba, and the z gets chopped off, producing
/view.php?id=foobarba
Your 500 Internal Server Error is the result of a redirect loop.
This is because your rule will always be true, because you are redirecting back to the same page.
You need to exclude the resultant link by adding a rule with ^! before all the rest.