.htaccess and SEO URLs - why is this an infinite loop? - .htaccess

I have a dirty URL like this: http://www.netairspace.com/photos/photo.php?photo=3392.
I want to do something like http://www.netairspace.com/photos/OH-LTU/Finnair_Airbus_330-202X/OUL_EFOU_Oulu/photo_3392/ (and later support short URLs like http://www.netairspace.com/pic/3392/ but I'll leave that out).
So I have a script photo_seo_url.php, which takes the photo ID, builds the SEO URL, and does a redirect (302 for testing, 301 when I'm happy with it). I then planned to add .htaccess mod_rewrite rules so that on calling the old URL:
the old URL would be rewritten internally to photo_seo_url.php
photo_seo_url.php would 301/302 redirect to the SEO URL
the SEO URL would be rewritten internally to the original photo.php
That way I would, in theory, get the benefits of the SEO URL while being able to retire the old ones at my leisure.
These are the rules I used:
RewriteEngine on
RewriteRule ^photos/.*/photo_([0-9]+)/?$ photos/photo.php?photo=$1 [NC,L]
RewriteCond %{QUERY_STRING} photo=([0-9]+)
RewriteRule ^photos/photo\.php$ photos/photo_seo_url.php?photo=%1 [NC,L]
But that goes into an infinite redirect loop. Why, if these two are doing internal rewrites rather than external redirects - or is that what I'm missing?
I've solved the problem adding a new file showphoto.php, which does nothing but include the original photo.php, and changing line 2:
RewriteEngine on
RewriteRule ^photos/.*/photo_([0-9]+)/?$ photos/showphoto.php?photo=$1 [NC,L]
RewriteCond %{QUERY_STRING} photo=([0-9]+)
RewriteRule ^photos/photo\.php$ photos/photo_seo_url.php?photo=%1 [NC,L]
But I'd still like to understand why the original version goes into an infinite loop. I've missed or misunderstood something. Is my approach sound?

To answer your question, why does this loop occur? This is what happens with an SEO URI, with a GET /photos/OH-LTU/Finnair_Airbus_330-202X/OUL_EFOU_Oulu/photo_3392/, say.
Rule 1 fires converting this to a GET /photos/photo.php?photo=3392 which triggers an internal redirect which then restarts the scan of the .htaccessfile.
Rule 2 then fires converting this to a GET photos/photo_seo_url.php?photo=339 which triggers an internal redirect which again restarts the scan of the .htaccessfile.
No further matches occur and hence this is passed to the script photos/photo_seo_url.php which then does a 302 to /photos/OH-LTU/Finnair_Airbus_330-202X/OUL_EFOU_Oulu/photo_3392/ and the browser detects a redirection loop.
What you need happen is for rule 1 firing to prevent rule 2 firing even after an internal redirect. One way to do this is to set an environment variable, say END (which gets converted to REDIRECT_END on the next pass) and to skip the rules if this is set:
RewriteEngine on
RewriteBase /
RewriteRule ^photos/.*/photo_([0-9]+)/?$ photos/photo.php?photo=$1 [NC,E=END:1,L]
RewriteCond %{ENV:REDIRECT_END}:%{QUERY_STRING} ^:photo=([0-9]+)$
RewriteRule ^photos/photo\.php$ photos/photo_seo_url.php?photo=%1 [NC,L]
An alternative approach is to add a dummy noredir parameter to the rewritten URI and add a:
RewriteCond %{QUERY_STRING} !\bnoredir
to the original second rule. However, photo.php would need to ignore this. Hope this helps :-)

RewriteEngine on
RewriteRule ^photos/.*/photo_([0-9]+)/?$ photos/photo.php?photo=$1&rewritten [NC,L]
RewriteCond %{QUERY_STRING} !rewritten
RewriteCond %{QUERY_STRING} photo=([0-9]+)
RewriteRule ^photos/photo\.php$ photos/photo_seo_url.php?photo=%1 [NC,L]

Related

is this .htaccess part vunerable to my site

in some Joomla installations I found this .htaccess in an administrator component. Can one explain what happens here and if it looks like vunerable code?
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^http://(www\.)? [NC]
RewriteRule .*\.(csv)$ [R,L,NC]
It looks a bit dirty to me, but it's not a security issue for sure.
RewriteCond %{HTTP_REFERER} !^http://(www\.)? [NC]
... this means that the proceeding rule is executed only if there's no referer starting with http://www.
The referer method might be used to process the rule only 1 time, but not in further redirects, triggered by the htaccess file, because redirects don't preserve the referer. The whole intention is difficult to guess without seeing the rest of the file.
RewriteRule .*\.(csv)$ [R,L,NC]
... this means that there should be no more processing of the htaccess file if the url ends in .csv
The [L] means - "last" rule, no further processing. As #adrianopolis said, the NC means case-insensitiv, so it will match to .CSV as well as to .Csv etc.
The [R] means redirect, but as there is no target URL, it won't do anything but prevent further processing.

Rewriting old and new urls to same page with .htaccess

Have a page currently with the URL /results-details.php?mls_number=stringofnumbers.
I want it to re-write to: /results-details/stringofnumbers
However I want that to basically resolve back to the original page.
I'm also changing all the URLs on the site internally to point to the URL. So I have two re-write rules:
RewriteCond %{QUERY_STRING} mls_number=([0-9]+)$
RewriteRule (.*) /new-homes/results-details/%1? [R=301,C]
RewriteRule ^results-details/([0-9]+)$ results-details.php?mls_number=$1
The second rule works fine on it's own with internal links in the /results-details/stringofnumbers form, but the first one doesn't chain properly to the second one and not sure what I'm doing wrong.
Basically trying to retain any links to the old URLs that might be out there but start using the new URS internally.
Suggestions?
YOu need to match against the actual request and not the URI, because the rewrite engine loops:
RewriteCond %{THE_REQUEST} \ /new-homes/results-details\.php?mls_number=([0-9]+)
RewriteRule ^ /new-homes/results-details/%1? [L,R=301]
RewriteRule ^results-details/([0-9]+)$ results-details.php?mls_number=$1

Using mod_rewrite to mask a directory/file name in a URL

I've taken my site down for some prolonged maintenance and am using mod_rewrite to send all requests to a single page: www.mysite.com/temp/503.php
This is my .htaccess file which works fine.
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !^/temp/503.php [NC]
RewriteRule .* /temp/503.php [R,L]
However, what I'd also like to be able to do is to hide /temp/503.php in the resulting URL from the visitor.
I know this is perhaps trivial and I'm sure fairly simple to achieve, but with my limited mod_rewrite skills I can't seem to get it to work.
Any help would be much appreciated.
Thanks.
Just get rid of the R flag in the rewrite rule, which tells the rule to redirect the request, thus changing the URL in the browser's location bar. So the rule would look like:
RewriteRule .* /temp/503.php [L]
which internally rewrites the requested URI instead of externally telling the browser that it's been moved to a new URL.

htaccess rewrite not working as expected just change my address in addressbar, no rewriting at all

I have folder/file structure as:
rootFolder/
lowRes/lowres.php
hiRes/hires.php
sys.php
Basically, I want to do rewrite such as that when user calls for page site.com/img_0001_hq.html, .htaccess to rewrite it to sys.php?1=img_0001_hq. Also, I want to limit acceptable emdings to ".html" and "/" and if ending like so is not present I want to call sys.php?1=p_404. Rewriting is doing as expected BUT when it comes to errors...
When I call page site.com/hiRes/hires.php or site.com/lowRes/lowres.php, rewriting is not working, scripts (hires.php and lowres.php) run, and report errors, normally in lack of variables from sys.php which is not triggered. Also, when I call pages site.com/hiRes or site.com/lowRes, sys.php runs, BUT, wrong. Also, when calling these addresses, address in browser changes to site.com/hiRes/?1=p_404 or site.com/lowRes/?1=p_404. What the heck is going on?! :D
Oh, yeah, my .htaccess looks like this:
IndexIgnore *
RewriteEngine on
RewriteRule ^(.*)(/|.html)$ sys.php?1=$1 [L]
RewriteRule ^(.*)$ sys.php?1=p_404 [L]
I am going nuts over this... :)
Try adding some conditions that exclude sys.php (and whatever else you don't want re-written). What's probably happening is that after the first rewrite, the URI becomes sys.php and is put back through the rewrite engine (mod_rewrite will do this until either the URI stops changing or it reaches the maximum number of internal redirects, causing 500 Server error):
IndexIgnore *
RewriteEngine on
RewriteCond %{REQUEST_URI} !sys\.php
RewriteRule ^(.*)(/|.html)$ sys.php?1=$1 [L]
RewriteCond %{REQUEST_URI} !sys\.php
RewriteRule ^(.*)$ sys.php?1=p_404 [L]

htacces redirect and mask

How would I redirect from the root folder to a sub folder and then mask that folder?
So instead of http://root.com/sub_folder
It would be just http://root.com
I have tried:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^root\.com$
RewriteRule (.*) http://root.com/$1 [R=301,L]
RewriteRule ^$ /sub [L]
However, that does not work. Any help will be welcome.
To clarify what I think you're looking for:
You want users who enter http://root.com with no trailing path to be rewritten silently to http://root.com/sub.
If a user directly enters http://root.com/sub, however, you want them to be redirected to http://root.com.
Any other path within root.com should be left alone.
The following two rules accomplish this. If you have more than one domain and only want this to apply to one domain, add your original RewriteCond in front of each RewriteRule.
RewriteRule ^sub/?$ http://root.com/ [R=301,L]
RewriteRule ^$ /sub [END]
First rule redirects /sub with or without trailing slash to root.com. Second rule rewrites base domain to /sub.
EDIT: Per Jon Lin's comment, below, the [L] flag only stops the current round of processing and internal rewrites are sent through the rules once more (I always forge that part). So, you can terminate the second line with [END] instead, which stops all rewrite processing. The catch is that [END] is only available in Apache 2.4 or higher, so if you're on an older version something trickier will need to be done.

Resources