Forum Moderators: phranque
Options -Indexes<Files ~ "^(.*)\.(inc¦tpl¦sql)$">
Order deny,allow
Deny from all
</Files>
Options +FollowSymLinks
<IfModule mod_rewrite.c>
RewriteEngine on
#listings.php?action=view -> /listings/view/
RewriteRule ^listings/action/([^/\.]+)/?/$ listings.php?action=$1 [L]
#listings.php?id=x -> /listings/view/make/model/x/ where x is the listing id
RewriteRule ^listings/view/(.*)/(.*)/([0-9]+)/$ listings.php?id=$3 [L]
#listings.php?id=1&largeIMG=image where x is the listing id and image is the image path
RewriteRule ^listings/main/image/([0-9]+)/(.*)$ listings.php?id=$1&largeIMG=$2 [L]
#listings.php?sellerid=x -> /listings/seller/id/x/ where x is the seller id
RewriteRule ^listings/seller/id/([0-9]+)/$ listings.php?sellerid=$1 [L]
#listings.php?action=find&make=make -> listings/action/find/make/make/
RewriteRule ^listings/action/find/make/([^/\.]+)/?/$ listings.php?action=find&make=$1 [L]
#listings.php?action=sort&type=price&ASC=1 or listings.php?action=sort&type=price&DESC=1
RewriteRule ^sort/price/asc/$ listings.php?action=sort&type=price&ASC=1 [L]
RewriteRule ^sort/price/desc/$ listings.php?action=sort&type=price&DESC=1 [L]
#listings.php?action=sort&type=year&ASC=1 or listings.php?action=sort&type=year&DESC=1
RewriteRule ^sort/year/asc/$ listings.php?action=sort&type=year&ASC=1 [L]
RewriteRule ^sort/year/desc/$ listings.php?action=sort&type=year&DESC=1 [L]
#listings.php?action=sort&type=model&ASC=1 or listings.php?action=sort&type=model&DESC=1
RewriteRule ^sort/model/asc/$ listings.php?action=sort&type=model&ASC=1 [L]
RewriteRule ^sort/model/desc/$ listings.php?action=sort&type=model&DESC=1 [L]
#sort/page/start/next/x/ where x is the next page id
RewriteRule ^sort/(.*)/(.*)/next/([0-9]+)/$ listings.php?next=$3 [L]
#editlisting.php?id=2 -> listings/edit/id/x/ where x is listing id
RewriteRule ^listings/edit/id/([0-9]+)/$ editlisting.php?id=$1 [L]
#poster.php?id=x -> /poster/view/x/ where x is the listing id
RewriteRule ^poster/view/([0-9]+)/$ poster.php?id=$1 [L]
#paycalc.php?price=#*$!xx.xx -> /paycalc/amount/#*$!xx.xx/ where x is a number between 0-9
RewriteRule ^paycalc/amount/([0-9]+)(.[0-9][0-9])/$ paycalc.php?price=$1$2 [L]
#contact.php?seller=x&record=y -> /contact/seller/x/listing/y/ where x is the seller id and y is the listing id
RewriteRule ^contact/seller/([0-9]+)/listing/([0-9]+)/$ contact.php?seller=$1&record=$2 [L]
#contact.php?action=Tell-A-Friend&seller=x&record=y -> /tell-a-friend/x/listing/id/y/ where x is the seller id and y is the listing id
RewriteRule ^tell-a-friend/([0-9]+)/listing/id/([0-9]+)/$ contact.php?action=Tell-A-Friend&seller=$1&record=$2 [L]
</IfModule>
Everything above works as expected but maybe some of you gurus could give suggestions on how to better optimize this htaccess aswell.
Thanks for any help
Brandon
1) The code comments are all (or mostly-all) exactly backwards. Taking an example, the first rule internally rewrites an incoming HTTP client request for the URL "example.com/listings" view to the server filepath "/listings.php?action=view", and not the other way around... Misunderstanding this is common, and can cause mod_rewrite to appear to be quite mysterious, as well as causing actual coding or execution errors.
2) Never use "(.*)/(.*)/" when "([^/]+)/([^/]+)/" can be used. Using multiple ".* wildcard" subpatterns in the middle of a pattern results in dozens, hundreds or even thousands of "back-off-and-try-again" matching attempts by the regular-expressions pattern-matcher, and can slow a busy server to a crawl if over-used.
3) If you are looking to match <one or more digits><period><two digits> then a better pattern is "[0-9]+\.[0-9]{2}". Note that literal periods in patterns must be escaped with a preceding backslash, otherwise the period is taken as a regular-expressions token meaning "match any single character here."
Jim
Additionally, make sure that if anyone asks for a URL in the /listings.php?<some parameters> format that they are correctly redirected to the "folder-based" URL format and the www added at the same time too. Those redirects are listed first, before the main non-www to www redirect mentioned above.
Jim I have made the suggested changes.
g1 "if anyone asks for a URL in the /listings.php?<some parameters> format that they are correctly redirected to the "folder-based" URL format"
So redirect listings.php?id=x to /listings/view/make/model/x/ ? Wouldn't that cause an endless loop? Maybe I am not following what you mean. Could you give an example?
I also don't want to force this upon end users as I make it a choice for them to use sef links as an option they can turn on or off I have built a link parser that automatically formats a given url into the SEF styled link if turned on.
* Example Usage : Place the {parse_sef_links url="url"} in your existing <a href="<==>">links</a>
* <a href="{parse_sef_links url="listings.php?action=view&id=5&sort=asc"}">Link Text</a>
* returns -> listings/action/view/id/5/sort/asc/ if fancy links are turned on
* or
* returns -> listings.php?action=view&id=5&sort=asc if fancy links are turned off
I don't have the www redirect setup as I am on a testing server accessed via [server_name...] so a forced redirect to the www wouldn't show correctly. I know I can change that I am just lazy.
This section at the top is another concern.
<Files ~ "^(.*)\.(inc¦tpl¦sql)$">
Order deny,allow
Deny from all
</Files>
As you can see I block access to any .sql, .inc or .tpl file which works great when an htaccess file can be used. If no htaccess file is used anyone can just go to /some/path/listings.tpl and it prints out as a text file. I know those files should be outside of the web root but I distribute this as a complete package that end users can plop in and go, also just adding an index.html file to the tpl directory is only a partial stop since as an open source package all the file paths are documented or available to be downloaded and studied.
So that leads me to the other part of my question on some server setups you cannot place an htaccess file in a directory even a blank one or you will get a 500 error. As I understand it you cannot use htaccess files in a Windows environment either, right? Is there a way to get similar functionality without using an htaccess file?
Thanks again for your input, I really do appreciate it,
Best Regards,
Brandon
Nope.
Redirect URL example.com/listings.php?id=x to URL www.example.com/listings/view/make/model/x/
Redirect URL www.example.com/listings.php?id=x to URL www.example.com/listings/view/make/model/x/
Rewrite URL www.example.com/listings/view/make/model/x/ to filepath /listings.php?id=x
No loop will be created if you follow the many previous examples.
.
I hope that the /make/model/ parts of the URL are not wildcard words in the URL.
Those words should also be passed through to your script and checked against the database entry for the product.
That is, you refer to a product as
www.example.com/listings/view/harikaricorp/xyz789/123456/
and that results in content being pulled from database record 123456 in your database.
What would your site do if I requested, or posted a link to, a URL like
www.example.com/listings/view/pileofjunk/soldbycriminals/123456/
for example?
Would your site return a 404 error, or would it serve up the same content as the other URL had delivered?
If the latter, then you have a Duplicate Content problem on your hands, as well as leaving your site SERPs wide open to being "got at" by competitors.
A concrete example using the URLs posted in your question about this would be:
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /listings\.php\?id=([^\ ]+)\ HTTP/
RewriteRule ^listings\.php$ http://www.example.com/listings/view/make/model/%1/ [R=301,L]
This looping only takes place in .htaccess context, and it's not a problem if your code is in a server config-level files such as httpd.conf or conf.d
But here, the problem with the arbitrary "make" and "model" becomes quite clear: What are you going to put into those fields to build the URL to redirect to? The answer is that although mod_rewrite can get the "id=" value from the requested query string, it cannot get the "make" and "model" from the requested URL-path, because those values aren't present in the requested URL.
You could use a small PERL script called by a RewriteMap defined in the server config to access the database to find out. This is a workable solution, and can be used if necessary (for example if the original dynamic URL is obsolete or if it refers to an obsolete script no longer on the server) as long as you can define the RewriteMap in the server config, but it's often easier to simply pass this job to your existing script, since it is already set up to access the database, and this solution does not require getting access to the server config or asking your host to define the RewriteMap for you.
The only thing you need to do is to be sure that the script can and does also check the client request, just as done in the rule shown here, to make sure that the dynamic URL request came from the client, and not from a previously-executed internal rewrite. If for some reason it cannot, then you can use an additional internal rewrite to append a "flag" to the dynamic URL's query string to signal that it needs to be redirected.
So, as they say in The Hitchhiker's Guide to the Galaxy, "Don't Panic!" :)
Jim