<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Jeremy Tunnell</title>
	<atom:link href="http://www.jeremytunnell.com/feed" rel="self" type="application/rss+xml" />
	<link>http://www.jeremytunnell.com</link>
	<description>User Experience &#124; Project Management &#124;  SEO</description>
	<lastBuildDate>Sat, 30 Jul 2011 15:29:49 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>Usability lessons from neuroscience</title>
		<link>http://www.jeremytunnell.com/posts/usability-lessons-from-neuroscience</link>
		<comments>http://www.jeremytunnell.com/posts/usability-lessons-from-neuroscience#comments</comments>
		<pubDate>Sun, 17 Jul 2011 17:16:58 +0000</pubDate>
		<dc:creator>Jeremy Tunnell</dc:creator>
				<category><![CDATA[Usability Research]]></category>
		<category><![CDATA[User Experience (UX)]]></category>

		<guid isPermaLink="false">http://www.jeremytunnell.com/?p=130</guid>
		<description><![CDATA[I have just finished a wonderful book, Reading in the Brain: The New Science of How We Read, which ostensibly is about the origins and the neural underpinnings of the human ability to read. Dehaene not only takes on the conventional wisdom that reading is a sequential, letter by letter process, but he unwittingly sheds light on the foundations of many universally accepted usability practices.]]></description>
			<content:encoded><![CDATA[<p>I have just finished a wonderful book, <a href="http://www.amazon.com/gp/product/B004Q7E1TY/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;tag=rsiinf-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=B004Q7E1TY">Reading in the Brain: The New Science of How We Read</a><img style="border: none !important; margin: 0px !important;" src="http://www.assoc-amazon.com/e/ir?t=rsiinf-20&amp;l=as2&amp;o=1&amp;a=B004Q7E1TY&amp;camp=217145&amp;creative=399373" border="0" alt="" width="1" height="1" />, which ostensibly is about the origins and the neural underpinnings of the human ability to read. Dehaene not only takes on the conventional wisdom that reading is a sequential, letter by letter process, but he unwittingly sheds light on the foundations of many universally accepted usability practices.</p>
<h3>The big picture</h3>
<p>The major takeaway from the book is that, contrary to conventional wisdom, reading is not like a standard string search algorithm that one might program into a computer (e.g. to look up the word &#8220;time&#8221;, one might start with all words that begin with t, narrow down to words containing i as the second letter, and so on until there is only one word left).</p>
<p>Instead, reading is a massively parallel and hierarchical process whereby neurons at the bottom of the pyramid are allowed to vote &#8220;yes&#8221; or &#8220;no&#8221; to a neuron one level up the hierarchy. This aggregation neuron tallies the votes of all neurons that report to it, dutifully passing its findings further up the pyramid.</p>
<p>So how does this work in practice? Let&#8217;s take our example of the word &#8220;time&#8221;.</p>
<p>At the very bottom of the pyramid are neurons which respond to very basic elements in an image: vertical lines, horizontal lines, diagonal lines, intersections, right angles, etc. For our  &#8217;t&#8217; in  &#8221;time&#8221;, there is perhaps a neuron somewhere which detects the intersection of the vertical line and horizontal line in the letter &#8216;t&#8217;. This neuron then proceeds to vote &#8220;yes&#8221; in favor of every possible letter that contains this intersection. It also votes &#8220;no&#8221; for letters which do not contain this intersection, like &#8216;s&#8217;.</p>
<p>The aggregation neuron in charge of the letter &#8216;t&#8217; receives votes from below, tallies them, and then sends a vote to the next level in the pyramid that the word probably contains a &#8216;t&#8217;.  Meanwhile, this higher neuron is simultaneously receiving &#8220;no&#8221; votes for letters like &#8216;c&#8217;, &#8216;y&#8217;, and &#8216;u&#8217;.  Eventually, the tallied votes for &#8216;t&#8217;, &#8216;i&#8217;, &#8216;m&#8217;, and &#8216;e&#8217; win the election, and the chaotic process very quickly converges on the right word &#8211; somewhere near the top of the pyramid.</p>
<h3>What this means for usability</h3>
<p>I am certainly not suggesting that these new findings will turn the field of usability on its head. However, they do shed some light on some long-held usability best practices.</p>
<h4>The brain&#8217;s visual system is biased to the right of one&#8217;s focus</h4>
<p>Most of the text processing capabilities of the brain reside in the left hemisphere. This means that visual stimuli appearing on the right side of the visual field have a decided advantage.</p>
<p>In fact, information on the left side of the visual field has to enter the right hemisphere of the brain and be transferred through the corpus callosum to the left hemisphere, through two centimeters of callosal cable.  As a result, words on the left side of the visual field are recognized more slowly and are subject to more errors.</p>
<p>In the English-speaking world, our left to right reading style seems to be well adapted to this limitation. However, I think this idea could be generalized to more than just words.</p>
<p>It seems to follow that not only are pages optimally processed from left to right, but that actions regarding the current area of focus are best placed on the right.  This approach could certainly apply to context menus, action buttons, and error states.</p>
<h4>Word familiarity matters, length doesn&#8217;t</h4>
<p>Because of the massively parallel operation of the brain&#8217;s neural network, the brain processes all of the letters in a word at once, and common words receive stronger votes in the voting process.</p>
<p>This finding holds for words of up to eight letters, where presumably the eye has to move forward to process the rest of the letters.  Therefore, it is often better to use a longer and more familiar word than a shorter and less common one.</p>
<h4>Words are not recognized by their shape</h4>
<p>The image from the retina is initially processed in what is called the &#8220;letterbox&#8221; area of the left hemisphere, and it turns out that this area processes uppercase and lowercase letters in parallel.  Indeed, according to the book, the small difference in reading performance for the sentences &#8220;It was a dark and stormy night&#8221; and &#8220;It WaS a DaRk AnD sToRmY nIgHt&#8221; is due simply to the fact that capital letters are less familiar than mixed case.</p>
<p>It is not immediately clear how far this finding extends into font choices. How unusual must a font be before a lack of familiarity slows reading speed?  The book suggests that our text processing system is highly tolerant of errors, giving examples of situations where transposed letters, missing letters, or misshapen letters have no effect on reading performance.</p>
<p>So it seems usability best practices were right for the wrong reason. Yes, it is slightly slower to read all capital letters, but it is only because we see mixed case more often.</p>
<p>&#8212;&#8212;</p>
<p>As User Experience practitioners, we are always learning rules. Sometimes we are fortunate enough to know the &#8216;why&#8217; behind these rules, but often we do not.</p>
<p>Especially, now that eyetracking  and A/B testing is widely used, it is becoming commonplace to know with certainty the best design  for a task empirically without touching the why question at all.</p>
<p>However, with more research like we find in this book, I hope we can continue to make sense of these sometimes arbitrary, yet indisputable conclusions.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeremytunnell.com/posts/usability-lessons-from-neuroscience/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>watchparty.tv &#8211; A usability analysis</title>
		<link>http://www.jeremytunnell.com/posts/watchparty-tv-a-usability-analysis</link>
		<comments>http://www.jeremytunnell.com/posts/watchparty-tv-a-usability-analysis#comments</comments>
		<pubDate>Tue, 26 Apr 2011 13:38:50 +0000</pubDate>
		<dc:creator>Jeremy Tunnell</dc:creator>
				<category><![CDATA[User Experience (UX)]]></category>

		<guid isPermaLink="false">http://www.jeremytunnell.com/?p=76</guid>
		<description><![CDATA[Watchparty.tv is a site that allows users to host or join "watch parties" of popular television shows. During a watch party, users visit a webpage that aggregates their thoughts (blips), along with an opinion tracker and polls. The benefit of the watch party approach is allowing disparate users to watch TV shows "together".]]></description>
			<content:encoded><![CDATA[<p><a href="http://watchparty.tv">Watchparty.tv</a> is a site that allows users to host or join &#8220;watch parties&#8221; of popular television shows. During a watch party, users visit a webpage that aggregates their thoughts (blips), along with an opinion tracker and polls. The benefit of the watch party approach is allowing disparate users to watch TV shows &#8220;together&#8221;.</p>
<p>Upon visiting the site for the first time, one notices that the initial appearance is friendly,with a soft color scheme and edges.  The appearance is entirely appropriate for a site such as this. Normally, a media focused site would be sharper with bolder colors, but since watchparty is selling community, the friendly appearance is a big asset.</p>
<h3>Home page</h3>
<p><img class="alignright size-medium wp-image-91" title="Watch party homepage" src="http://www.jeremytunnell.com/wp-content/uploads/2011/04/003-e1303515056147-300x225.png" alt="" width="300" height="225" /></p>
<ul>
<li>The featured shows slider is a good focal point on the homepage for new users, however the hover menu should use a more readable version of the date, preferably the month spelled out with the day. The year is really not necessary here.</li>
<li>Auto complete would be nice in the search box (see Hulu)</li>
<li>Separating the bottom part of the homepage into current parties and upcoming parties is a little confusing because, essentially, they&#8217;re all points on the same timeline. A better solution would be to split the page into thirds, used two thirds for the left side to display currently active parties and upcoming parties in a scrollable format, and use the right third of the page to highlight the most popular parties at the moment. The idea here is to use the mental model of an online TV Guide.</li>
<li>The visual focal point of the listings is the &#8220;create private&#8221; button.  However,it is worth thinking about whether users would more likely be looking to join a public watch party. If so, a join button should be the primary call to action, with the create private button being a secondary action.</li>
<li>Regardless, simply turning the show name into linkable text is too subtle for a call to action. A button is needed here.</li>
<li>Also as a logged in user, the message link on the global navigation bar seems out of place and doesn&#8217;t actually live anywhere in the information architecture. The message section should actually live under the my profile section, and instead of a navigation button, there should be a new message identifier (see Gmail notifier).</li>
</ul>
<h3>Create Private Pop-up</h3>
<p>Clicking on the create private button results in a pop-up with two options: create a password and invite people.</p>
<ul>
<li>6 to 10 characters is a bit too secure for what amounts to a few people watching a TV show. A better option would be to auto generate a four digit pin instead of a password. This approach gives essentially 1000 combinations, and is  unlikely to be brute forced before the show is completed.</li>
<li>An even better option would be to just auto generate a short URL, ending in a four or five digit alphanumeric phrase. This URL could serve as both a bookmark and a password.</li>
<li>The invite people box should accept any delimiter that is not a valid character in an e-mail. This should be very easily done with the proper regular expression. At the very least, it should be able to handle commas, semicolons, spaces,  and new lines.</li>
</ul>
<h3>Register</h3>
<p><img class="alignright size-medium wp-image-95" title="Watch party register page" src="http://www.jeremytunnell.com/wp-content/uploads/2011/04/007-e1303515566990-300x225.png" alt="" width="300" height="225" /></p>
<ul>
<li>The registration process is nice and short, but could be made even shorter by removing the password confirmation blank. There will clearly be those who mistype their password, but an easy to use password recovery feature should mitigate any problems.</li>
<li>The line of action links at the bottom is duplicative and confusing. The sign in link is duplicated from the global menu, the forgot password link actually should not be on this page, and the Facebook and twitter logins are duplicated from just above. Also, the e-mail confirmation help link should be located on the register confirmation page and also the login confirmation page (only if they have not e-mail confirmed), but not this page.</li>
<li>After registering, the user is presented with an error message: (could not sign in, user is unconfirmed). This is not an error, because the user did nothing wrong. Instead, this should be presented as a normal step in the register process. Even better, auto log the user in and worry about e-mail confirmation at their second login.</li>
<li>My confirmation e-mail was sent to my spam folder (a common problem). <a title="E-mail sending tips" href="http://mikehillyer.com/email/how-to-send-one-billion-email-marketing-messages-per-month/">Have you ensured that your e-mail infrastructure has all the proper verifications?</a></li>
</ul>
<h3>Register confirm</h3>
<p><img class="alignright size-medium wp-image-93" title="Watch party confirm registration" src="http://www.jeremytunnell.com/wp-content/uploads/2011/04/0021-e1303515151579-300x225.png" alt="" width="300" height="225" /></p>
<ul>
<li>The phrase &#8220;must set up the following data&#8221; is technical sounding and unfriendly, and it is not true that one must fill out the data because the page also says that they can optionally log in.</li>
<li>Ideally, the user should have already been logged in, and this page simply asks them to select their time zone before proceeding. Also, the terms of service agreement should probably happen on the register page (It does, so why make the user do it twice?)</li>
<li>After clicking &#8220;save and accept terms&#8221;, there should be some sort of final confirmation that the register process completed successfully.Currently, the user is redirected to the home page. There are two solutions here: the first is to redirect the homepage but provide a nice confirmation message and call to action or redirect to the my profile page where the user can find  content specific to them.</li>
<li>As an additional note, after logging in the user is presented with a confirmation message  in orange. A less alarming color should be used for confirmations.</li>
</ul>
<h3>Create new private watch party</h3>
<p><img class="alignright size-medium wp-image-94" title="Watch party create new" src="http://www.jeremytunnell.com/wp-content/uploads/2011/04/004-e1303515202349-300x225.png" alt="" width="300" height="225" /></p>
<ul>
<li>The back button is in the wrong place. It should either be moved to the top left or replaced with the cancel button next to the confirm button at the bottom of the form.</li>
<li> The combined time and date input form elements are a bit daunting. In this case, it would be easier to comprehend two separate date and time input fields. The calendar could have the standard calendar pop-up, and the time input could be done iPhone style or with drop downs (think about limiting the options to either 15 min. intervals or 30 min. intervals).</li>
<li>After the start time is entered, the end times should automatically populate with 30 min. or one hour later. It is also unnecessary to say that the end time has to be after the start time, as this can be caught with a form check.</li>
<li>See note from above about the password field and the invite field.</li>
</ul>
<h3>Watchparty event page</h3>
<p><img class="alignright size-medium wp-image-90" title="Watch party main page" src="http://www.jeremytunnell.com/wp-content/uploads/2011/04/0061-e1303515004699-300x225.png" alt="" width="300" height="225" /></p>
<p>The first impressions when initially viewing this page are that there are a lot of options, there are some unfamiliar words, and the page feels quite a bit more static than it should.</p>
<p>&nbsp;</p>
<p>The eye begins in the top left and observes the name of the current watch party (good), which is followed by a rather large button to see the program details.  This button is perhaps a little bit large for what it does.  After the title, the eyes fall upon the top left box called &#8220;flips&#8221;.  It is immediately unclear what this word means, but using the context of the box contents one can deduce that they have something to do with expressing emotions.</p>
<p>The eye continues to the right from flips, landing on the &#8220;how do you feel&#8221; box, which is fairly clear as to its function. Moving down the page, the &#8220;blips&#8221; box does a fairly good job of communicating that it is some sort of short comment field. Finally, we move back to the left column to the &#8220;traks&#8221; box.  It is completely unclear what this box is for, especially if there  are no previous traks. Attendees is, of course, self-explanatory.</p>
<h4>Significant shortcomings</h4>
<ul>
<li>My initial expectation was that the page would be more dynamic. This, of course, is not due to bad design  but instead reflects the fact that the product is still in beta. Every effort should be made to Ajaxify all of the boxes on the page so that the page does not have to be refreshed for updates.</li>
<li>Boxes are not located correctly for their importance. For example, blips should be the most important thing on the page, and thus in the top left.</li>
<li>It is a little too ambitious to try to coin three new words. I was constantly experiencing varying degrees of cognitive dissonance trying to square the fact that a trak is really a poll, and a flip is really an emoticon.</li>
<li>It is not clear why one must be logged in to &#8220;attend&#8221; a watch party. One should be able to observe, without logging in or receiving an error message. The blip box could be replaced by a login box explaining that one must log in in order to contribute. I would go so far as to list anonymous observers in the &#8220;attendees&#8221; box, but listed after the registered users.</li>
</ul>
<h4>Minor shortcomings</h4>
<ul>
<li>The JavaScript character counter is misplaced, and really should be invisible until one is approaching the limit.</li>
<li>The &#8220;how do you feel&#8221; box should really be a dynamic graph  (see Frank Luntz&#8217;s debate feedback sessions for an example)</li>
<li>There are too many different types of buttons and links on the page.</li>
<li>Traks have constraints that don&#8217;t make sense. Why two character minimum; why not five or 10? Why does the trak have to have four options?</li>
</ul>
<h4>Design suggestions</h4>
<p>The wireframe below is a suggestion on how one might reorganize the page to overcome these shortcomings.</p>
<p style="text-align: center;">&nbsp;</p>
<div class="mceTemp mceIEcenter" style="text-align: left;">
<dl id="attachment_84" class="wp-caption aligncenter" style="width: 610px;">
<dt class="wp-caption-dt"><a href="http://www.jeremytunnell.com/wp-content/uploads/2011/04/watchparty-e1303506055468.png"><img class="size-full wp-image-84  " title="Watchparty UX wireframe" src="http://www.jeremytunnell.com/wp-content/uploads/2011/04/watchparty-e1303506055468.png" alt="Watchparty wireframe" width="600" height="452" /></a></dt>
<dd class="wp-caption-dd">Note: Not to scale. For layout and functional demonstration only.</dd>
</dl>
</div>
<ul>
<li>The words &#8220;trak&#8221; and &#8220;flip&#8221; have been removed completely.</li>
<li>Breadcrumbs have been added in place of the &#8220;leave watch party&#8221; link.</li>
<li>Blips have been moved &#8220;front and center&#8221; because they are the main focus of activity.</li>
<li>Flips have been integrated with the blip box, invoking the web HTML editor mental model.</li>
<li>The character counter has been moved to the top right of the text box, and should be invisible until one approaches the limit.</li>
<li>The motion tracking box in the upper right has been changed such that the slider is now vertical and the display is a dynamically changing graph.</li>
<li>The program details button is now a link.</li>
<li>Traks are now called polls, for less confusion, and are moved to the right. Past polls should still be visible and should move down when a new poll is created. There should be a hard limit on active polls to ensure that no active  poll falls below visibility.</li>
<li>The social networking features and invite features are moved to the attendees box which stretches across the bottom of the screen. This feature is important, but  sharing is provided immediately upon entering the page with a modal pop-up.</li>
<li>Creating a new emotion (previously a flip) can be accomplished with an in-line text field, or optionally hidden behind a &#8220;create new&#8221; link.  There is no need to label these at all, as they are self-explanatory.</li>
<li>For added simplicity, the blip button can be removed, and blips are simply published after pressing the enter key ( Facebook does this).</li>
<li>Black triangles now represent infinitely scrolling content boxes.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.jeremytunnell.com/posts/watchparty-tv-a-usability-analysis/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>123exchanges.com &#8211; A usability analysis</title>
		<link>http://www.jeremytunnell.com/posts/123exchanges-com-a-usability-analysis</link>
		<comments>http://www.jeremytunnell.com/posts/123exchanges-com-a-usability-analysis#comments</comments>
		<pubDate>Fri, 08 Apr 2011 20:49:59 +0000</pubDate>
		<dc:creator>Jeremy Tunnell</dc:creator>
				<category><![CDATA[User Experience (UX)]]></category>

		<guid isPermaLink="false">http://www.jeremytunnell.com/?p=57</guid>
		<description><![CDATA[123exchanges.com is an eBay type listing site based on the concept of selling through videos instead of written descriptions. The site provides a way for sellers to register and upload videos of things for sale, and it provides browsing and searching functionality for potential buyers. They are a startup based in the Washington DC area that is approximately 6 months old.]]></description>
			<content:encoded><![CDATA[<p><a href="http://123exchanges.com">123exchanges.com</a> is an eBay type listing site based on the concept of selling through videos instead of written descriptions. The site provides a way for sellers to register and upload videos of things for sale, and it provides browsing and searching functionality for potential buyers. They are a startup based in the Washington DC area that is approximately 6 months old.</p>
<div style="clear: both;"></div>
<h3>Home Page</h3>
<p><img class="pic-left" title="Homepage screenshot" src="/media/123_home_400.PNG" alt="Homepage screenshot" width="400" />The site has a coherent and appropriate color scheme, a good layout, and feels generally friendly, if a bit unpolished. The large promotional area in the center left is a good idea, and the limited browse functionality in the bottom half of the screen works well for users who aren&#8217;t sure what they&#8217;re looking for. I was able to find out very quickly what the site was about and what things I can do as a buyer or seller.</p>
<p>For the purpose of this analysis, I will be focusing only on areas of needed improvement:</p>
<ul>
<li> URL – The address bar shows the homepage address as being /default.aspx. The homepage should show only the domain name.</li>
<li> Logo – The main sans serif font is good, but the points on the two arrows are too sharp, and I would worry that the green (the color of tension) is not the right color for them. The font for the smaller tagline looks as though the text has been resized imperfectly (see the S in sell).</li>
<li> The blue text at the top in the header bar (Sell Your Used Stuff Today! It&#8217;s Free) is unnecessary and only serves to clutter the interface. The blue text on blue background lacks contrast, and the exclamation point is unnecessary.</li>
<li> Removing it and moving the search box up and to the right would improve the visibility of this important feature.</li>
<li> In the top right, the main call to action is &#8220;Upload Video&#8221;. I understand that the emphasis of the site is on video, but what the user is actually trying to do is sell an item, and the button label should perhaps reflect this.</li>
<li> The location drop-down at the very top of the site gets lost in the page. This feature should be moved down with the search.</li>
<li> As this is a fairly standard layout for this type of site, box labels like &#8220;promotion&#8221;, &#8220;what&#8217;s new&#8221;, etc. are unnecessary and clutter up the interface. &#8220;Sell your stuff in three easy steps&#8221; is important, but perhaps should be placed inside of the box instead of as a box header.</li>
<li> The social media buttons seem to have been placed arbitrarily. There is also some confusion about whether the like button and the tweet button apply to the video above or to the site itself. A better solution would be to group these together with the invite friends buttons.</li>
<li> The Starbucks coffee promotion looks like an advertisement instead of a promotion, and I would question the effectiveness of a free coffee on getting new users signed up (what do your numbers say?). Ads cheapen the look of your site, and I would try to avoid the appearance of them if possible.</li>
<li> Throughout the site, you use red text to emphasize prices. Red text is associated with danger or error, and I would highly recommend that you use a combination of font size and font weight (or use the color green) instead of the color red to point out prices.</li>
<li> There are a lot of social media buttons at the bottom, but some appear to be duplicates (even though they have different functions). The purpose of these buttons should be made more clear.</li>
<li> The community box at the bottom of the front page is confusing and ineffective. All of the posts are by &#8220;admin&#8221; which makes the section appear like an announcement section. Further, as a user I am not clear as to what I would use a community section for. For example, I just want to sell an iPod, and I have nothing in common with someone trying to sell a pair of jeans. It appears that there may be two different startups here: a marketplace and a general topic message board. Best to focus on the former.</li>
</ul>
<div style="clear: both;"></div>
<h3>Search Listing Pages</h3>
<p><img class="pic-left" title="Search listing screenshot" src="/media/123_searchlisting_400.PNG" alt="Search listingscreenshot" width="400" /></p>
<ul>
<li> It is unnecessary to repeat the category for each result. Either the user got this page by clicking on a category (in which case they will all be the same) or the user got here with a custom search in which case the category is irrelevant.</li>
<li> The item ID is also unnecessary.</li>
<li> The time format should be &#8220;X days ago&#8221; instead of the full timestamp. At minimum, there is no need for seconds to be listed.</li>
</ul>
<div style="clear: both;"></div>
<h3>Item Listing Page</h3>
<p><img class="pic-left" title="Item listing screenshot" src="/media/123_listing_400.PNG" alt="Item  listing screenshot" width="400" /></p>
<ul>
<li> Again, box headings are unnecessary. It is obvious what information appears in the &#8220;posting information box&#8221; and the &#8220;more info box&#8221;. Better to remove these and cleanup the interface.</li>
<li> The posting information box is cluttered with too much information. Cleanup the date and remove the item ID. The &#8220;view times&#8221; should also be removed. At this early stage, it only serves to work against you.</li>
<li> The condition rating system is confusing. I have no idea what &#8220;used 70%&#8221; means.</li>
<li> The blue text style for links and the styling for the item title are too similar, making the item title appear clickable.</li>
<li> Avatars in comments make the site appear MySpace-y.</li>
<li> Clicking on the respond button gave me a pop-up box. Better to just redirect the user to the login page with an explanation as to why they have been sent there.</li>
</ul>
<div style="clear: both;"></div>
<h3>Login Page</h3>
<p><img class="pic-left" title="Login screenshot" src="/media/123_login_400.PNG" alt="Login screenshot" width="400" /></p>
<ul>
<li> The phrase &#8220;welcome to 123 exchanges&#8221; is unnecessary.</li>
<li> The phrase &#8220;join our community now&#8221; appears to be a link to join the community, not a lead in to the sign-up link.</li>
<li> &#8220;Sign-up here&#8221; should be a button instead of a link with arrows on each side.</li>
</ul>
<div style="clear: both;"></div>
<h3>Sign-up Page</h3>
<p><img class="pic-left" title="Sign up screenshot" src="/media/123_signup_400.PNG" alt="Sign up screenshot" width="400" />This page is very important because it is the barrier between an interested user and a registered user. Every attempt should be made to make this page appear and be as simple and effortless as possible.</p>
<ul>
<li> According to Jakob Nielsen, a two column layout is less effective than a one column layout. Regardless, there is no reason why the last name field should be the only field in the right column.</li>
<li> There is no reason to have a country drop-down if there is only one country.</li>
<li> Eliminate the city field and state field, and instead pull those from the zip code.</li>
<li> Forcing the user to enter their e-mail twice, while helping to guard against typos, reduces your conversion rate. Furthermore, a great deal of users simply copy and paste what they had just typed. Better to remove the second e-mail address blank.  There is some controversy over this, but the number of people who mistyped their e-mail and do not correct it will be mitigated by the number of people now completing the form who would not have otherwise.</li>
<li> User id sounds like it should be a number. Better to label the field &#8220;username&#8221;, or even better remove it and auto generate a user name (while allowing the user to change it in his preferences).</li>
<li> Again, I would recommend the removal of the second password field. Ideally, the password recovery feature should be easy to use for those who mis-type the password initially.</li>
<li> Captchas should only be used when absolutely needed. While in such an early-stage, it is better to remove the captcha and either deal with the spam sign-ups or implement either the <a href="http://www.arraystudio.com/as-workshop/the-captcha-alternatives.html">dummy form elements method, GET request detection</a>, or separate the sign-up process into two steps.</li>
<li> Even better to implement a lazy registration process where you allow the user to upload a video and metadata first, and then ask them for e-mail and password as a last step.</li>
</ul>
<div style="clear: both;"></div>
<h3>Sign-up Confirmation Page</h3>
<p><img class="pic-left" title="Sign up confirm screenshot" src="/media/123_sign-upconfirm_400.PNG" alt="Sign up confirm screenshot" width="400" /></p>
<ul>
<li> There is no confirmation that my registration actually went through.</li>
<li> I would be curious to see numbers on whether the social media invite is used on this page or whether some other content would be better.</li>
<li> &#8220;Next Step&#8221; is not prominent enough.</li>
<li> There is no option to resend the confirmation e-mail if it was not received.</li>
<li> To cut friction, the user could be automatically logged in at this point, and the e-mail confirm could simply be required for the next login.</li>
<li> The confirmation e-mail is too wordy, and it leads with red text which says &#8220;danger&#8221;. There are also several typos. Ideally, this e-mail should contain the activation link in enough text to explain what it is and nothing more.</li>
<li> After clicking the activation link, congratulations is unneeded, and the phrase &#8220;wishing you the best&#8221; is unprofessional.</li>
<li> The user should ideally be automatically signed in and redirected to the my account home page, but if not at least the sign-up information should pre-seed.</li>
</ul>
<div style="clear: both;"></div>
<h3>My Account</h3>
<p><img class="pic-left" title="my account screenshot" src="/media/123_myaccount_400.PNG" alt="my account screenshot" width="400" /></p>
<ul>
<li> There is no link to logout. This link should be located near where the login button was.</li>
<li> The search function appears to be duplicated, and the drop-down for search type is unnecessary since it is easy to tell the difference between a product name and ID.</li>
<li> In general, there are too many menu items for the amount of things that one can do on this page. Messages should be integrated with the buy and sell list, home is unnecessary. Also, I would be careful about repurposing the main navigation for the my account section, while also having a my account navigation bar at the very top. It appears at first glance, that the new bar at the very top is navigation for the my account section, but in fact it duplicates navigation in the main nav.</li>
<li> There are several unnecessary columns, including product ID and view times.</li>
<li> The &#8220;view top 10 link&#8221;, from a user standpoint is useless. Why do I care who the top 10 users are?</li>
<li> &#8220;Request a Starbucks coffee&#8221; should be automatic, without having to request (send the coupon via e-mail)</li>
<li> Get rid of the refresh page button, all browsers have a refresh button.</li>
<li> Pagination is a little awkward (page count)</li>
<li> Upload video functionality is duplicated, but the second button is labeled &#8220;post video&#8221;.</li>
</ul>
<div style="clear: both;"></div>
<h3>Upload Page</h3>
<p><img class="pic-left" title="upload screenshot" src="/media/123_upload_400.PNG" alt="upload screenshot" width="400" /></p>
<ul>
<li> This page has far too much text, and the red text is jarring. Most of the text refers to troubleshooting steps, which the user should not be bothered with until they&#8217;re actually having trouble.</li>
<li> The choices on this page should be upload or cancel. &#8220;Back to selling list&#8221; is awkward phrasing, and there is no reason why the user would need to go to the homepage.</li>
<li> Above the video upload area, there is a sentence with buttons explaining that the user can use one of two video converting applications. What is a video converting application? Is it required? How do I know whether I need to use one or not? Best to place this in the troubleshooting section</li>
<li> The notice explains that the maximum video duration is 3 min., but a little bit later 3 min. is listed as a recommended length</li>
<li> This whole page is really unnecessary, as the video upload area could be fit into a box in the my account area with a small link below labeled &#8220;troubleshooting&#8221;, or &#8220;problems?&#8221;. After upload, the my account area would refresh the new video listed in an option to enter metadata.</li>
</ul>
<div style="clear: both;"></div>
<h3>Video Metadata Page</h3>
<p><img class="pic-left" title="metadata screenshot" src="/media/123_metadata_400.PNG" alt="metadata screenshot" width="400" /></p>
<ul>
<li> Blue is not a good color to use for the confirmation message at the top. It blends in with the background, and the user will skip over it straight to the input fields.</li>
<li> Too many fields crammed together, looks daunting. Use some white space to break up the fields.</li>
<li> It is unclear what the &#8220;call&#8221; checkbox does.</li>
<li> Again, city and state are not needed.</li>
<li> Tags are hard to explain to users, and there is no indication of what format is needed here, whether they should be separated spaces or commas, or whether multiple word tags are accepted. Due to the varied entry by users, this is not likely to be useful for navigation or searching (better to just emphasize a good item description)</li>
<li> Other information is deemphasized and would better be called &#8220;item description&#8221;.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.jeremytunnell.com/posts/123exchanges-com-a-usability-analysis/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PostGIS Basics &#8211; Part 2 &#8211; Hello World</title>
		<link>http://www.jeremytunnell.com/posts/postgis-basics-part-2-hello-world</link>
		<comments>http://www.jeremytunnell.com/posts/postgis-basics-part-2-hello-world#comments</comments>
		<pubDate>Fri, 06 Aug 2010 00:45:34 +0000</pubDate>
		<dc:creator>Jeremy Tunnell</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[PostGIS]]></category>

		<guid isPermaLink="false">http://www.jeremytunnell.com/?p=21</guid>
		<description><![CDATA[SELECT AddGeometryColumn('public', 'table','column', 4269, 'POINT', 2) This will add a new column to the table and add an entry to the metadata table (the 4269 specifies my reference system, more on that below). It will also add a column to &#8220;table&#8221; and several constraint checks on the new column. Next, you&#8217;ll need to know about [...]]]></description>
			<content:encoded><![CDATA[<div class="code">
<pre>
SELECT AddGeometryColumn('public', 'table','column', 4269, 'POINT', 2)
</pre>
</div>
<p>This will add a new column to the table and add an entry to the metadata table (the 4269 specifies my reference system, more on that below).  It will also add a column to &#8220;table&#8221; and several constraint checks on the new column.</p>
<p>Next, you&#8217;ll need to know about <a href="http://www.nationalatlas.gov/articles/mapping/a_projections.html">spacial reference systems</a>.  You&#8217;ll notice that the letters SRID are scattered throughout the documentation.  SRID stands for &#8220;Spacial Reference ID&#8221;, and it describes the system to use to transform a round world into a flat x,y coordinate system.  (Interestingly enough, Latitude and Longitude are not x,y coordinates but instead radians.)  There are literally thousands of them.</p>
<p>I chose to store my geocoded addresses in two formats:  SRID 4269 (Lat/Lon) and SRID 2163 (US National Atlas &#8211; meters).  That way I can do my distance calculations quickly using the x,y coordinates (for approximate accuracy) and i&#8217;ll have the lat/lon to feed to, say, Google Maps.</p>
<p>So now i&#8217;ll need to add the second column:</p>
<div class="code">
<pre>
SELECT AddGeometryColumn('public', 'table','column2', 2163, 'POINT', 2)
</pre>
</div>
<h4>Inserting Data</h4>
<p>My data is actually coming from the Yahoo geocoding api.  I&#8217;m feeding them an address and they are returning a latitude/longitude.  I used the following SQL to update my addresses table:</p>
<div class="code">
<pre>
UPDATE addresses SET
coordinates_ll = ST_SetSRID(ST_MakePoint(" . $point['longitude'] . "," . $point['latitude'] . "),4269),
coordinates_proj_m = ST_Transform(ST_SetSRID(ST_MakePoint(" . $point['longitude'] . "," . $point['latitude'] . "),4269), 2163)
WHERE id=" . $id;
</pre>
</div>
<p>What we are doing here is, from inside out:</p>
<ol>
<li>Create a point.</li>
<li>Set its SRID to 4269 (lat/lon)</li>
<li>AND for the second query, the point is converted to SRID 2163</li>
<li>Store it.</li>
</ol>
<p>Note, the longitude comes first in these functions.</p>
<h4>A quick distance query</h4>
<p>Show me the ids of records that are within 5 miles (8000 meters) of a point.</p>
<div class="code">
<pre>
SELECT id
 FROM addresses
 WHERE Distance(coordinates_proj_m, ST_SetSRID('POINT(-1952333 -571399)', 2163)) < 8000
</pre>
</div>
<p>To get this to work, you must transform your point into the same SRID as the column you're querying.</p>
<p>It also helps to put an index on the column we're querying on:</p>
<div class="code">
<pre>
CREATE INDEX idx_coordinates_proj_m
ON addresses
USING gist(coordinates_proj_m);
</pre>
</div>
<p>Note:  This does not scale. </p>
<h3>References</h3>
<ul>
<li><a href="http://www.bostongis.com/?content_name=postgis_tut02#21">http://www.bostongis.com/?content_name=postgis_tut02#21</a></li>
<li><a href="http://unserializableone.blogspot.com/2007/02/using-postgis-to-find-points-of.html">http://unserializableone.blogspot.com/2007/02/using-postgis-to-find-points-of.html</a></li>
<li><a href="http://forum.geonames.org/gforum/posts/list/727.page">http://forum.geonames.org/gforum/posts/list/727.page</a></li>
<li><a href="http://www.bostongis.com/PrinterFriendly.aspx?content_name=postgis_tut03">http://www.bostongis.com/PrinterFriendly.aspx?content_name=postgis_tut03</a></li>
<li><a href="http://postgis.refractions.net/support/wiki/index.php?ExamplesFindNearby">http://postgis.refractions.net/support/wiki/index.php?ExamplesFindNearby</a></li>
<p><!--[if IE]><iframe allowTransparency="true" class="addtoany_special_service facebook_like" src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-2-hello-world&amp;layout=button_count&amp;show_faces=false&amp;width=75&amp;action=like&amp;colorscheme=light&amp;height=20" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service facebook_like" src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-2-hello-world&amp;layout=button_count&amp;show_faces=false&amp;width=75&amp;action=like&amp;colorscheme=light&amp;height=20" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-2-hello-world&amp;counturl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-2-hello-world&amp;count=horizontal&amp;text=PostGIS%20Basics%20%26%238211%3B%20Part%202%20%26%238211%3B%20Hello%20World" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:55px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-2-hello-world&amp;counturl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-2-hello-world&amp;count=horizontal&amp;text=PostGIS%20Basics%20%26%238211%3B%20Part%202%20%26%238211%3B%20Hello%20World" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:55px;height:20px"></iframe><!--<![endif]--><a class="a2a_button_reddit" href="http://www.addtoany.com/add_to/reddit?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-2-hello-world&amp;linkname=PostGIS%20Basics%20%26%238211%3B%20Part%202%20%26%238211%3B%20Hello%20World" title="Reddit" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/reddit.png" width="16" height="16" alt="Reddit"/></a> <a class="a2a_button_linkedin" href="http://www.addtoany.com/add_to/linkedin?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-2-hello-world&amp;linkname=PostGIS%20Basics%20%26%238211%3B%20Part%202%20%26%238211%3B%20Hello%20World" title="LinkedIn" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/linkedin.png" width="16" height="16" alt="LinkedIn"/></a> <a class="a2a_button_stumbleupon" href="http://www.addtoany.com/add_to/stumbleupon?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-2-hello-world&amp;linkname=PostGIS%20Basics%20%26%238211%3B%20Part%202%20%26%238211%3B%20Hello%20World" title="StumbleUpon" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/stumbleupon.png" width="16" height="16" alt="StumbleUpon"/></a> <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-2-hello-world&amp;title=PostGIS%20Basics%20%26%238211%3B%20Part%202%20%26%238211%3B%20Hello%20World">Share/Bookmark</a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.jeremytunnell.com/posts/postgis-basics-part-2-hello-world/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PostGIS Basics &#8211; Part 1 &#8211; Installation</title>
		<link>http://www.jeremytunnell.com/posts/postgis-basics-part-1-installation</link>
		<comments>http://www.jeremytunnell.com/posts/postgis-basics-part-1-installation#comments</comments>
		<pubDate>Thu, 05 Aug 2010 00:44:54 +0000</pubDate>
		<dc:creator>Jeremy Tunnell</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[PostGIS]]></category>

		<guid isPermaLink="false">http://www.jeremytunnell.com/?p=19</guid>
		<description><![CDATA[My OS is CentOS, so I used yum to handle installs from the rpm database. The thing with CentOS is that it is purposefully one step behind the cutting edge, so the most recent version of certain applications are not available (PHP, Postgres, etc). To get around this limitation, you have to instruct CentOS to [...]]]></description>
			<content:encoded><![CDATA[<p>My OS is CentOS, so I used yum to handle installs from the rpm database.  The thing with CentOS is that it is purposefully one step behind the cutting edge, so the most recent version of certain applications are not available (PHP, Postgres, etc).  To get around this limitation, you have to instruct CentOS to look elsewhere for updated RPMs.</p>
<p>One location is the Postgresql repository: <a href='http://www.postgresql.org/download/linux'>http://www.postgresql.org/download/linux</a></p>
<p>Another location for these is <a href="http://dag.wieers.com/rpm/FAQ.php#B1">DAG</a>.  To set this as an additional rpm source, run this command as root (this works for RHEL 5 and CentOS):</p>
<div class="code">
<pre>
rpm -Uhv http://apt.sw.be/redhat/el5/en/i386/rpmforge/RPMS/rpmforge-release-0.3.6-1.el5.rf.i386.rpm
</pre>
</div>
<p>Now we have the ability to get more up-to-date rpms.</p>
<p>Next, we must work on getting all of the dependencies for PostGIS installed, which amount to:</p>
<ul>
<li><a href="http://proj.maptools.org/">ProJ4</a></li>
<li><a href="http://geos.refractions.net/">GEOS 3</a></li>
<li>The PL/pgSQL procedural language</li>
</ul>
<h4>Proj4</h4>
<p>Unfortunately, rpms for the proj-4 application still weren&#8217;t available from the repository, so I found an rpm here:  <a href="http://rpm.pbone.net/index.php3/stat/4/idpl/4817458/com/proj-4.5.0-1.el5.rf.i386.rpm.html">Proj-4 rpms</a>.  This installed with a quick rpm -U software-2.3.4.rpm</p>
<h4>GEOS</h4>
<p>Geos is thankfully available from Dag, so yum should find it and install it.  There may be some weird dependencies you will have to work through.  The below packages should help, but they&#8217;ll all have to be installed eventually, so you may as well go ahead and do it.</p>
<ul>
<li>php-pear</li>
<li>php-devel</li>
</ul>
<p>* At this point, if you are using PDO and haven&#8217;t installed the pgsql PDO drivers, you can do it now:  &#8220;pecl install pdo_pgsql&#8221;</p>
<h4>PL/pgSQL</h4>
<p>You&#8217;ll need to run the following commands from a command line (either as root or the postgres user, I can&#8217;t recall which one is needed by which).  Please note all of these paths seem to be unique to each installation, so yours might be different.</p>
<div class="code">
<pre>
/usr/bin/initdb -D /var/lib/pgsql/data_dir    //Create the database

psql create language plpgsql  

psql -d database_name -f /usr/share/pgsql/contrib/lwpostgis.sql
psql -d database_name -f /usr/share/pgsql/contrib/spatial_ref_sys.sql
</pre>
</div>
<p>The last two lines load the spacial functions into the database for use.</p>
<p><!--[if IE]><iframe allowTransparency="true" class="addtoany_special_service facebook_like" src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-1-installation&amp;layout=button_count&amp;show_faces=false&amp;width=75&amp;action=like&amp;colorscheme=light&amp;height=20" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service facebook_like" src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-1-installation&amp;layout=button_count&amp;show_faces=false&amp;width=75&amp;action=like&amp;colorscheme=light&amp;height=20" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-1-installation&amp;counturl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-1-installation&amp;count=horizontal&amp;text=PostGIS%20Basics%20%26%238211%3B%20Part%201%20%26%238211%3B%20Installation" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:55px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-1-installation&amp;counturl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-1-installation&amp;count=horizontal&amp;text=PostGIS%20Basics%20%26%238211%3B%20Part%201%20%26%238211%3B%20Installation" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:55px;height:20px"></iframe><!--<![endif]--><a class="a2a_button_reddit" href="http://www.addtoany.com/add_to/reddit?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-1-installation&amp;linkname=PostGIS%20Basics%20%26%238211%3B%20Part%201%20%26%238211%3B%20Installation" title="Reddit" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/reddit.png" width="16" height="16" alt="Reddit"/></a> <a class="a2a_button_linkedin" href="http://www.addtoany.com/add_to/linkedin?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-1-installation&amp;linkname=PostGIS%20Basics%20%26%238211%3B%20Part%201%20%26%238211%3B%20Installation" title="LinkedIn" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/linkedin.png" width="16" height="16" alt="LinkedIn"/></a> <a class="a2a_button_stumbleupon" href="http://www.addtoany.com/add_to/stumbleupon?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-1-installation&amp;linkname=PostGIS%20Basics%20%26%238211%3B%20Part%201%20%26%238211%3B%20Installation" title="StumbleUpon" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/stumbleupon.png" width="16" height="16" alt="StumbleUpon"/></a> <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fpostgis-basics-part-1-installation&amp;title=PostGIS%20Basics%20%26%238211%3B%20Part%201%20%26%238211%3B%20Installation">Share/Bookmark</a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.jeremytunnell.com/posts/postgis-basics-part-1-installation/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Transforming an address into Latitude and Longitude using PHP and curl</title>
		<link>http://www.jeremytunnell.com/posts/transforming-an-address-into-latitude-and-longitude-using-php-and-curl</link>
		<comments>http://www.jeremytunnell.com/posts/transforming-an-address-into-latitude-and-longitude-using-php-and-curl#comments</comments>
		<pubDate>Wed, 05 Aug 2009 00:44:04 +0000</pubDate>
		<dc:creator>Jeremy Tunnell</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[geocoding]]></category>

		<guid isPermaLink="false">http://www.jeremytunnell.com/?p=17</guid>
		<description><![CDATA[Step 2 &#8211; Construct the query Yahoo offers a REST interface to handle the conversion so we can use either a plain HTTP GET request, or if you want to do it inside of a script that is doing many other things you can use CURL, a set of very useful functions for querying and [...]]]></description>
			<content:encoded><![CDATA[<h3>Step 2 &#8211; Construct the query</h3>
<p>Yahoo offers a <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">REST</a> interface to handle the conversion so we can use either a plain HTTP GET request, or if you want to do it inside of a script that is doing many other things you can use <a href="http://us.php.net/curl">CURL</a>, a set of very useful functions for querying and &#8220;scraping&#8221; web pages and applications.</p>
<p>We must construct the url according to the api guidelines, which boils down to something like this:</p>
<div class="code">
<pre>
	$url =  "http://local.yahooapis.com/MapsService/V1/geocode";
	$args = "?appid=your_key_";
	$args .= "&#038;street=" . urlencode(street_address);  //We must urlencode variables that will have spaces/etc
	$args .= "&#038;city=" . urlencode(city);
	$args .= "&#038;state=" . state;
	$args .= "&#038;output=php";  //Optional parameter to return a php object
	$url = $url . $args;
</pre>
</div>
<p>The code above basically asks yahoo to use the current key to return the latitude and longitude as a serialized php object (the other option is xml, but I don&#8217;t like parsing it).</p>
<h3>Step 3 &#8211; Send the query</h3>
<p>Sending the query via CURL works something like this: </p>
<div class="code">
<pre>
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_TIMEOUT, 5000);
	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	$address_data = unserialize(curl_exec($ch));
	curl_close($ch);
</pre>
</div>
<p>
The script is doing the following:</p>
<ol>
<li>Initializing a CURL object.</li>
<li>Setting the timeout to 5 seconds.</li>
<li>Setting the url to query.</li>
<li>Setting CURL to return the results to a variable rather than displaying it to the screen.</li>
<li>Reading the results, unserializing them, and storing the results in our $address_data object, which is really just a bunch of nested arrays.</li>
</ol>
<h3>Step 4 &#8211; Get the latitude and longitude</h3>
<p>You can retrieve the latitude and longitude this way:</p>
<div class="code">
<pre>
	$latitude = $address_data['ResultSet']['Result']['Latitude'];
	$longitude = $address_data['ResultSet']['Result']['Longitude'];
</pre>
</div>
<p>That&#8217;s all there is to it.</p>
<p><!--[if IE]><iframe allowTransparency="true" class="addtoany_special_service facebook_like" src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Ftransforming-an-address-into-latitude-and-longitude-using-php-and-curl&amp;layout=button_count&amp;show_faces=false&amp;width=75&amp;action=like&amp;colorscheme=light&amp;height=20" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service facebook_like" src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Ftransforming-an-address-into-latitude-and-longitude-using-php-and-curl&amp;layout=button_count&amp;show_faces=false&amp;width=75&amp;action=like&amp;colorscheme=light&amp;height=20" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Ftransforming-an-address-into-latitude-and-longitude-using-php-and-curl&amp;counturl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Ftransforming-an-address-into-latitude-and-longitude-using-php-and-curl&amp;count=horizontal&amp;text=Transforming%20an%20address%20into%20Latitude%20and%20Longitude%20using%20PHP%20and%20curl" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:55px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Ftransforming-an-address-into-latitude-and-longitude-using-php-and-curl&amp;counturl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Ftransforming-an-address-into-latitude-and-longitude-using-php-and-curl&amp;count=horizontal&amp;text=Transforming%20an%20address%20into%20Latitude%20and%20Longitude%20using%20PHP%20and%20curl" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:55px;height:20px"></iframe><!--<![endif]--><a class="a2a_button_reddit" href="http://www.addtoany.com/add_to/reddit?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Ftransforming-an-address-into-latitude-and-longitude-using-php-and-curl&amp;linkname=Transforming%20an%20address%20into%20Latitude%20and%20Longitude%20using%20PHP%20and%20curl" title="Reddit" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/reddit.png" width="16" height="16" alt="Reddit"/></a> <a class="a2a_button_linkedin" href="http://www.addtoany.com/add_to/linkedin?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Ftransforming-an-address-into-latitude-and-longitude-using-php-and-curl&amp;linkname=Transforming%20an%20address%20into%20Latitude%20and%20Longitude%20using%20PHP%20and%20curl" title="LinkedIn" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/linkedin.png" width="16" height="16" alt="LinkedIn"/></a> <a class="a2a_button_stumbleupon" href="http://www.addtoany.com/add_to/stumbleupon?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Ftransforming-an-address-into-latitude-and-longitude-using-php-and-curl&amp;linkname=Transforming%20an%20address%20into%20Latitude%20and%20Longitude%20using%20PHP%20and%20curl" title="StumbleUpon" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/stumbleupon.png" width="16" height="16" alt="StumbleUpon"/></a> <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Ftransforming-an-address-into-latitude-and-longitude-using-php-and-curl&amp;title=Transforming%20an%20address%20into%20Latitude%20and%20Longitude%20using%20PHP%20and%20curl">Share/Bookmark</a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.jeremytunnell.com/posts/transforming-an-address-into-latitude-and-longitude-using-php-and-curl/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Really hairy problem with (seemingly) random CRLF and spaces inserted in emails</title>
		<link>http://www.jeremytunnell.com/posts/really-hairy-problem-with-seemingly-random-crlf-and-spaces-inserted-in-emails</link>
		<comments>http://www.jeremytunnell.com/posts/really-hairy-problem-with-seemingly-random-crlf-and-spaces-inserted-in-emails#comments</comments>
		<pubDate>Mon, 05 Jan 2009 01:42:38 +0000</pubDate>
		<dc:creator>Jeremy Tunnell</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[base64]]></category>
		<category><![CDATA[encoding]]></category>

		<guid isPermaLink="false">http://www.jeremytunnell.com/?p=15</guid>
		<description><![CDATA[Troubleshooting I isolated the process into three components: the email builder (my code), the mailer application, and the sending application (in this case, smtp through postfix). I followed the below process to troubleshoot: Changed the mailer application to use the built in PHP mail() function, and I also tried sending using a completely different SMTP [...]]]></description>
			<content:encoded><![CDATA[<h3>Troubleshooting</h3>
<p>I isolated the process into three components: the email builder (my code), the mailer application, and the sending application (in this case, smtp through postfix).   I followed the below process to troubleshoot:</p>
<ol>
<li>Changed the mailer application to use the built in PHP mail() function, and I also tried sending using a completely different SMTP box.  The problem was persistent no matter what process was used to send the mail.</li>
<li>I found the place in my code where the completed HTML was being handed off to the mailer application.  Adding in a file_put_contents, I could then examine the exact data before it went to the mailer.  Taking a look at it through a hex editor revealed that the body did not contain the offending characters</li>
<li>Finally, I found another mailer application (I was using phpmailer).  Swiftmailer is an alternative to phpmailer.  I figured that if it was obscure bug with phpmailer, changing the mailing application would clear it up.  This also did not solve the problem.</li>
</ol>
<p>So if everything was working correctly, where could the problem crop up?  The only place left to look was the encoding scheme for the emails.  Scouring the internet, I found <a href="http://framework.zend.com/issues/browse/ZF-1041">a few suggestions that the problem may be related to the message encoding</a>.  In this case, it appeared the problem stemmed from (possibly) a 75 character limit in quoted-printable encodings.  This didn&#8217;t help me, as my emails were being sent using 8-bit encoding.</p>
<h3>The solution</h3>
<p>Just to see what happened, I changed the encoding settings on phpmailer to use base64 encoding using $mail->Encoding=&#8221;base64&#8243;.  This solved my problem, though I don&#8217;t admit to knowing exactly why.</p>
<p><strong>Note:</strong> don&#8217;t confuse this with character set issues.  In the past I have seen situations where utf-8 text was being read into an email and sent as ISO-8859-1.  When having weird characters showing up in your emails, this is most often the problem (or vice versa).</p>
<h3>Archived Comments</h3>
<p>Hello,<br /> <br />
Your problem is rather similar to what I am having, here is an example of what my text might look like: &#8220;he would perf! orm his operation&#8221;.<br /> <br />
You see the &#8220;! &#8221; inserted in the middle of &#8220;perform&#8221;.  How odd.  It is messing up my html emails because it&#8217;ll interrupt the source code.<br /> <br />
I do not fully understand your solution- would you mind illustrating in some more detail what it was you did to fix this very similar problem you were having?<br /> <br />
I am only sending my html mails using the mail() function built into PHP, and I am encoding that email using charset=iso-8859-1 though it doesn&#8217;t seem to matter if I use utf-8.</p>
<p>Very hopefully in SLC,<br /> <br />
Nik</p>
<p>Posted by <a rel="nofollow"  href='http://www.kued.org/'>Nik</a> on January 18th, 2008</p>
<hr class="soft" />Nik,</p>
<p>I think you&#8217;re confusing character encoding with mime content transfer encoding.</p>
<p>First, if you&#8217;re sending using ISO-8859-1, you need to make sure your database or wherever you&#8217;re getting the text from is delivering it is in the same encoding format (see my earlier posts). </p>
<p>If so, try looking at the mime transfer encoding (base64, 8-bit, quoted-printable, etc).  I use phpmailer (http://phpmailer.codeworxtech.com/) to send emails, and i&#8217;d recommend it.  </p>
<p>A quick look at the mail() php manual page, it appears that the following setting may help you:</p>
<p>&#8220;Apparently if using the mbstring library, and using overriden functions, the &#8220;mail&#8221; command appears to use &#8220;Content-Transfer-Encoding: BASE64&#8243; by default.  Which if you combine it with PEAR Mail_Mime you&#8217;ll get mails that, although they appear RFC compliant, not mailer can read correctly.</p>
<p>To fix this it appears you should add a fixed header in the mail command (this one assumes the pear mime module is 7bit clean, perhaps 8bit would also be fine)<br /> <br />
    $headers['Content-Transfer-Encoding'] = &#8217;7bit&#8217;;&#8221;</p>
<p>Good luck,<br /> <br />
Jeremy</p>
<p>Posted by Jeremy on February 04th, 2008</p>
<hr class="soft" />Nik,</p>
<p>Also, you might take a look at the email content in a hex editor to figure out whether the exclamation point is really an exclamation point or just confusion over the text encoding of the email.</p>
<p>Posted by Jeremy on February 04th, 2008</p>
<hr class="soft" />Have you tried inserting your own line breaks?  How long of an email are we talking about?  The SMTP server may be inserting it&#8217;s own line breaks at will to keep any single line from being over a certain limit.  Base64 has a limit of 76 characters per line, so if you look at the character output you should see a nicely aligned block of text.</p>
<p>Posted by James on February 28th, 2008</p>
<hr class="soft" />rtyey</p>
<p>Posted by Anonymous on June 02nd, 2008</p>
<hr class="soft" />Hi guys,</p>
<p>I also had the rogue &#8220;!&#8221; problem Nik was having, i.e. &#8220;perform&#8221; comes out as &#8220;per !form&#8221;</p>
<p>It was driving me crazy until I googled and found this.</p>
<p>I am using phpmailer as Jeremy is (it&#8217;s good I recommend it &#8211; no pont re-inventing the wheel) and my problems were solved by adding the suggested fix:</p>
<p>$mail->Encoding=&#8221;base64&#8243;;</p>
<p>Thanks guys, you saved my weekend and health!</p>
<p>cheers</p>
<p>Alex</p>
<p>Posted by Alex Seymour on February 22nd, 2009</p>
<hr class="soft" />I think the reason setting $phpmailer->Encoding = &#8220;base64&#8243;; cures the random spaces is because it causes the data to get encoded into a form which adheres to the 998 octets per line limit. For me the problem was happening when the HTML in the email had lines which exceeded 998 chars before a line break. See http://en.wikipedia.org/wiki/MIME#Content-Transfer-Encoding</p>
<p>Posted by Jon Nott on June 17th, 2009</p>
<hr class="soft" />Thanks a mil! Worked perfectly!</p>
<p>Posted by <a  rel="nofollow"   href='http://jeffgardner.org'>Jeff</a> on August 28th, 2009</p>
<hr class="soft" />Absolutely genius &#8211; just the problem I was having. A white space being inserted in phpMailer scripts randomly after a certain char count. I had tried to resolve this for AGES! This should be documented in the phpMailer files. Pat on back to all.</p>
<p>Posted by Lewis on December 15th, 2009</p>
<hr class="soft" />Awesome, thanks for the solution. I did change phpmailer class from 8bit to base64 and it worked like a charm. I&#8217;d been changing all sorts of variables for the past few hours trying to get those exclamation marks to go away. </p>
<p>Posted by <a href='http://www.barrelofcrafts.com'  rel="nofollow"  >Victor</a> on January 13th, 2010</p>
<hr class="soft" />I had this same problem using the Pear Mail_Mime class. By using base64 encoding when preparing the email the problem was fixed. You need to set the encoding with the $mime->get() method like so.. $body = $mime->get(array(&#8216;html_encoding&#8217;=>&#8217;base64&#8242;));</p>
<p>Hope this helps</p>
<p>Posted by Freed on March 30th, 2010</p>
<hr class="soft" />This was very helpful.  I dropped in the line of code with the base64 encoding change and it fixed my problem.  Thank you very much for posting.</p>
<p>Posted by L on July 13th, 2010</p>
<hr class="soft" />Adding a /n/r into your PHP code at every 990 characters or less fixes the problem if you&#8217;re using PHP&#8217;s standard mail() function. The extra space (which in reality is a linebreak and a space was breaking longs links in my messages. Not anymore! Thanks for the posts everyeone!</p>
<p>Posted by Zoltan on August 05th, 2010</p>
<hr class="soft" />I have exactly the same problem. Sometimes it a space in the middle of the word, sometimes it messes up the html syntax (eg. doesn&#8217;t close a )&#8230;</p>
<p>adding /n/r does not seem to help, and I am not quite sure where/how to add $mail->Encoding=&#8221;base64&#8243;;.</p>
<p>Using the standard php mail command, in this syntax:</p>
<p>if (mail($to,$subject,$msg,$headers)) {<br /> <br />
     header(&#8216;Location: complete.php&#8217;);<br /> <br />
  } else<br /> <br />
  {<br /> <br />
     header(&#8216;Location: incomplete.php&#8217;);<br /> <br />
  }</p>
<p>NB. These are the headers:</p>
<p>$headers  = &#8220;MIME-Version: 1.0\r\n&#8221;;<br /> <br />
    $headers .= &#8220;Content-type: text/html; charset=iso-8859-1\r\n&#8221;; </p>
<p>Any help would be truly appreciated!</p>
<p>Posted by Richard Crampton on October 27th, 2010</p>
<hr class="soft" />Thankyou, thankyou, thankyou. Saved my day and a lot of debugging with a lot of potential error sources! Thanks for taking the time to write this up.</p>
<p>Posted by Kristian on October 27th, 2010</p>
<hr class="soft" />Thnx for the tip, it works 100%</p>
<p>Posted by Marcel on November 06th, 2010</p>
<p><!--[if IE]><iframe allowTransparency="true" class="addtoany_special_service facebook_like" src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Freally-hairy-problem-with-seemingly-random-crlf-and-spaces-inserted-in-emails&amp;layout=button_count&amp;show_faces=false&amp;width=75&amp;action=like&amp;colorscheme=light&amp;height=20" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service facebook_like" src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Freally-hairy-problem-with-seemingly-random-crlf-and-spaces-inserted-in-emails&amp;layout=button_count&amp;show_faces=false&amp;width=75&amp;action=like&amp;colorscheme=light&amp;height=20" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Freally-hairy-problem-with-seemingly-random-crlf-and-spaces-inserted-in-emails&amp;counturl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Freally-hairy-problem-with-seemingly-random-crlf-and-spaces-inserted-in-emails&amp;count=horizontal&amp;text=Really%20hairy%20problem%20with%20%28seemingly%29%20random%20CRLF%20and%20spaces%20inserted%20in%20emails" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:55px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Freally-hairy-problem-with-seemingly-random-crlf-and-spaces-inserted-in-emails&amp;counturl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Freally-hairy-problem-with-seemingly-random-crlf-and-spaces-inserted-in-emails&amp;count=horizontal&amp;text=Really%20hairy%20problem%20with%20%28seemingly%29%20random%20CRLF%20and%20spaces%20inserted%20in%20emails" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:55px;height:20px"></iframe><!--<![endif]--><a class="a2a_button_reddit" href="http://www.addtoany.com/add_to/reddit?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Freally-hairy-problem-with-seemingly-random-crlf-and-spaces-inserted-in-emails&amp;linkname=Really%20hairy%20problem%20with%20%28seemingly%29%20random%20CRLF%20and%20spaces%20inserted%20in%20emails" title="Reddit" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/reddit.png" width="16" height="16" alt="Reddit"/></a> <a class="a2a_button_linkedin" href="http://www.addtoany.com/add_to/linkedin?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Freally-hairy-problem-with-seemingly-random-crlf-and-spaces-inserted-in-emails&amp;linkname=Really%20hairy%20problem%20with%20%28seemingly%29%20random%20CRLF%20and%20spaces%20inserted%20in%20emails" title="LinkedIn" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/linkedin.png" width="16" height="16" alt="LinkedIn"/></a> <a class="a2a_button_stumbleupon" href="http://www.addtoany.com/add_to/stumbleupon?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Freally-hairy-problem-with-seemingly-random-crlf-and-spaces-inserted-in-emails&amp;linkname=Really%20hairy%20problem%20with%20%28seemingly%29%20random%20CRLF%20and%20spaces%20inserted%20in%20emails" title="StumbleUpon" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/stumbleupon.png" width="16" height="16" alt="StumbleUpon"/></a> <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Freally-hairy-problem-with-seemingly-random-crlf-and-spaces-inserted-in-emails&amp;title=Really%20hairy%20problem%20with%20%28seemingly%29%20random%20CRLF%20and%20spaces%20inserted%20in%20emails">Share/Bookmark</a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.jeremytunnell.com/posts/really-hairy-problem-with-seemingly-random-crlf-and-spaces-inserted-in-emails/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to configure your web application to correctly deal with character set/encoding issues</title>
		<link>http://www.jeremytunnell.com/posts/how-to-configure-your-web-application-to-correctly-deal-with-character-setencoding-issues</link>
		<comments>http://www.jeremytunnell.com/posts/how-to-configure-your-web-application-to-correctly-deal-with-character-setencoding-issues#comments</comments>
		<pubDate>Wed, 05 Nov 2008 01:41:48 +0000</pubDate>
		<dc:creator>Jeremy Tunnell</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[encoding]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.jeremytunnell.com/?p=13</guid>
		<description><![CDATA[Background I&#8217;ll just link to the best places i&#8217;ve found to read up on the background. Read these first if you want to understand whats going on: Excellent intro to character encodings Joel On Software, on Unicode The Details In order to get your website working harmoniously with one character set, you first have to [...]]]></description>
			<content:encoded><![CDATA[<h3>Background</h3>
<p>I&#8217;ll just link to the best places i&#8217;ve found to read up on the background.  Read these first if you want to understand whats going on:</p>
<ul>
<li><a href="http://www.sitepoint.com/blogs/2006/03/15/do-you-know-your-character-encodings/">Excellent intro to character encodings</a></li>
<li><a href="http://www.joelonsoftware.com/articles/Unicode.html">Joel On Software, on Unicode</a></li>
</ul>
<h3>The Details</h3>
<p>In order to get your website working harmoniously with one character set, you first have to pick one.  I picked ISO-8859-1 (sometimes referred to as latin1).  It&#8217;s the most popular English (Latin) language set, though it doesn&#8217;t display many foreign characters.
</p>
<p>
Unfortunately, despite the fact that Unicode is the end-and-be-all <a href="http://www.phpwact.org/php/i18n/charsets">PHP is really horrible at dealing with Unicode</a> (specifically multi-byte strings).  Since I&#8217;ve got enough to worry about without having to also check every function i&#8217;m using for multi-byte compatibility, ISO-8859-1 is right for me, for now.  I hear PHP6 will fully support mb strings.
</p>
<p>In order to get your web application working correctly with one character set, there are basically three parts you must take care of:</p>
<ol>
<li>The database</li>
<li>The web server</li>
<li>The web page itself</li>
</ol>
<h4>Database config</h4>
<p>In a perfect world, you would compile your database to default to your preferred character set.  I won&#8217;t cover that here.</p>
<p>Assuming you cannot do that,  you need to create your tables using the correct set.  Keep in mind, at least on MySQL, the character set can be configured all the way down to the column level.  Here we will just set it at a database level. <a href="http://www.alberton.info/dbms_charset_settings_explained.html">(See here for much more detail)</a>:</p>
<div class="code">
<pre>
CREATE DATABASE database CHARACTER SET utf8 COLLATE utf8_general_ci;
</pre>
</div>
<p>Next, we need to configure how the database delivers the results of queries to the calling application.  Assuming you don&#8217;t (or can&#8217;t) ensure this is done at compile time, you can use the following command before sending a query:</p>
<div class="code">
<pre>
SET NAMES charset
</pre>
</div>
<p>According to the linked article above, this is shorthand for setting the character_set_client, character_set_results, and collation_connection variables in MySQL.  A good place to put this query is in the constructor of your database access class.</p>
<h4>Web Server</h4>
<p>Assuming you are using apache, you need to edit a setting in your httpd.conf file (the primary apache config file).  </p>
<div class="code">
<pre>
AddDefaultCharSet charset
</pre>
</div>
<p>Set this to be what you prefer apache to tell the client that the default character set is in case one is not specified.  (This is important, as in some cases the client will trust this even if one is specified in the document.)</p>
<p>Also, there are options in whatever server side language you&#8217;re using to set this variable in outgoing headers.  In PHP you use the header() function.  See the PHP documentation for details.</p>
<h4>The web page</h4>
<p>Finally, you should specify the character set of the page you&#8217;re serving with a meta tag at the top below the <html> tag.  It looks like this:</p>
<div class="code">
<pre><code>
&lt;meta http-equiv="Content-Type" content="text/html; charset=charset" /&gt;
</code></pre>
</div>
<h4>Getting obsessive</h4>
<p>Most browsers support specifying the character set that a form should accept (and what the browser will convert the text to if it is not correct).  To manually set this, include the following attribute in the<br />
<form> tag:</p>
<div class="code">
<pre>
 accept-charset='ISO-8859-1'
</pre>
</div>
<p>Doing the above should ensure that you operate using the same character set throughout your web application, and hopefully garbage characters and question marks will be forever in the past.</p>
<h3>Reference</h3>
<ul>
<li><a href="http://www.alberton.info/dbms_charset_settings_explained.html">DBMS and charsets</a> &#8211; Settings for various databases.</li>
<li><a href="http://confluence.atlassian.com/display/DOC/Configuring+Database+Character+Encoding"> More charset settings for databases.</a></li>
<li><a href="http://ljmu.ac.uk/cis/webpublishing/81434.htm">MS Word and Web Development</a> &#8211; Short and specific to MS Word.</li>
<li><a href="http://www.oreillynet.com/onlamp/blog/2006/01/turning_mysql_data_in_latin1_t.html">Turning MySQL data in latin1 to utf8</a> &#8211; Case study that gets down to the minute details.</li>
<li><a href="http://directory.fsf.org/project/recode/">Recode:  Character set conversion tool</a></li>
<li><a href="http://www.orthogonalthought.com/blog/index.php/2007/05/mysql-database-migration-and-special-characters/">Fixing MYSQL charset issues on existing data.</a></li>
</ul>
<p><!--[if IE]><iframe allowTransparency="true" class="addtoany_special_service facebook_like" src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fhow-to-configure-your-web-application-to-correctly-deal-with-character-setencoding-issues&amp;layout=button_count&amp;show_faces=false&amp;width=75&amp;action=like&amp;colorscheme=light&amp;height=20" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service facebook_like" src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fhow-to-configure-your-web-application-to-correctly-deal-with-character-setencoding-issues&amp;layout=button_count&amp;show_faces=false&amp;width=75&amp;action=like&amp;colorscheme=light&amp;height=20" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fhow-to-configure-your-web-application-to-correctly-deal-with-character-setencoding-issues&amp;counturl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fhow-to-configure-your-web-application-to-correctly-deal-with-character-setencoding-issues&amp;count=horizontal&amp;text=How%20to%20configure%20your%20web%20application%20to%20correctly%20deal%20with%20character%20set%2Fencoding%20issues" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:55px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fhow-to-configure-your-web-application-to-correctly-deal-with-character-setencoding-issues&amp;counturl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fhow-to-configure-your-web-application-to-correctly-deal-with-character-setencoding-issues&amp;count=horizontal&amp;text=How%20to%20configure%20your%20web%20application%20to%20correctly%20deal%20with%20character%20set%2Fencoding%20issues" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:55px;height:20px"></iframe><!--<![endif]--><a class="a2a_button_reddit" href="http://www.addtoany.com/add_to/reddit?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fhow-to-configure-your-web-application-to-correctly-deal-with-character-setencoding-issues&amp;linkname=How%20to%20configure%20your%20web%20application%20to%20correctly%20deal%20with%20character%20set%2Fencoding%20issues" title="Reddit" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/reddit.png" width="16" height="16" alt="Reddit"/></a> <a class="a2a_button_linkedin" href="http://www.addtoany.com/add_to/linkedin?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fhow-to-configure-your-web-application-to-correctly-deal-with-character-setencoding-issues&amp;linkname=How%20to%20configure%20your%20web%20application%20to%20correctly%20deal%20with%20character%20set%2Fencoding%20issues" title="LinkedIn" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/linkedin.png" width="16" height="16" alt="LinkedIn"/></a> <a class="a2a_button_stumbleupon" href="http://www.addtoany.com/add_to/stumbleupon?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fhow-to-configure-your-web-application-to-correctly-deal-with-character-setencoding-issues&amp;linkname=How%20to%20configure%20your%20web%20application%20to%20correctly%20deal%20with%20character%20set%2Fencoding%20issues" title="StumbleUpon" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/stumbleupon.png" width="16" height="16" alt="StumbleUpon"/></a> <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fhow-to-configure-your-web-application-to-correctly-deal-with-character-setencoding-issues&amp;title=How%20to%20configure%20your%20web%20application%20to%20correctly%20deal%20with%20character%20set%2Fencoding%20issues">Share/Bookmark</a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.jeremytunnell.com/posts/how-to-configure-your-web-application-to-correctly-deal-with-character-setencoding-issues/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>More ModRewrite &#8211; Using a dbm file instead of a txt file</title>
		<link>http://www.jeremytunnell.com/posts/more-modrewrite-using-a-dbm-file-instead-of-a-txt-file</link>
		<comments>http://www.jeremytunnell.com/posts/more-modrewrite-using-a-dbm-file-instead-of-a-txt-file#comments</comments>
		<pubDate>Fri, 05 Sep 2008 00:41:14 +0000</pubDate>
		<dc:creator>Jeremy Tunnell</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[mod_rewrite]]></category>

		<guid isPermaLink="false">http://www.jeremytunnell.com/?p=11</guid>
		<description><![CDATA[The most confusing thing is when you use the perl script on the official apache site here it&#8217;s written for the NDBM format (which isn&#8217;t available on my box). Here&#8217;s the perl script: #!/path/to/bin/perl ## ## txt2dbm -- convert txt map to dbm format ## use NDBM_File; use Fcntl; ($txtmap, $dbmmap) = @ARGV; open(TXT, "]]></description>
			<content:encoded><![CDATA[<p>
The most confusing thing is when you use the perl script on the official apache site <a href="http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html">here</a> it&#8217;s written for the NDBM format (which isn&#8217;t available on my box).
</p>
<p>
Here&#8217;s the perl script:</p>
<div class="code">
<pre>
#!/path/to/bin/perl
##
##  txt2dbm -- convert txt map to dbm format
##

use NDBM_File;
use Fcntl;

($txtmap, $dbmmap) = @ARGV;

open(TXT, "<$txtmap") or die "Couldn't open $txtmap!\n";
tie (%DB, 'NDBM_File', $dbmmap,O_RDWR|O_TRUNC|O_CREAT, 0644)
  or die "Couldn't create $dbmmap!\n";

while (<TXT>) {
  next if (/^\s*#/ or /^\s*$/);
  $DB{$1} = $2 if (/^\s*(\S+)\s+(\S+)/);
}

untie %DB;
close(TXT);
</pre>
</div>
<p>
So after some trial and error, I found out that my version of apache works with SDBM, and it appears that if you just change NDBM to SDBM it works&#8230;
</p>
<div class="code">
<pre>
#!/usr/bin/perl -w
##
##  txt2dbm -- convert txt map to dbm format
##

use SDBM_File;
use Fcntl;

($txtmap, $dbmmap) = @ARGV;

open(TXT, "<$txtmap") or die "Couldn't open $txtmap!\n";
tie (%DB, 'SDBM_File', $dbmmap,O_RDWR|O_TRUNC|O_CREAT, 0644)
  or die "Couldn't create $dbmmap!\n";

while (<TXT>) {
  next if (/^\s*#/ or /^\s*$/);
  $DB{$1} = $2 if (/^\s*(\S+)\s+(\S+)/);
}

untie %DB;
close(TXT);
</pre>
</div>
<p>
So problem 1 fixed.  Then I find out the output of this thing is two files instead of one&#8230;wtf?  The files are named:  rewritemap.dbm.dir and rewritemap.dbm.pag
</p>
<p>
Here&#8217;s the short answer:  If you just ignore the additional extensions, it will work.  Here&#8217;s the httpd.conf line:
</p>
<div class="code">
<pre>
RewriteMap redirects dbm:/.../.../.../rewrite/rewritemap.dbm
</pre>
</div>
<h3>Archived Comments</h3>
<p>Great article!  Thanks for clearing up this otherwise poorly-documented issue.</p>
<p>Posted by <a rel="nofollow" href='http://www.projectplaylist.com'>Nick</a> on October 18th, 2007</p>
<hr class="soft" />Yes, thank you very much.  I ran in to the exact same problem.  From what I gather you can only use </p>
<p>use NDBM_File;</p>
<p>With Perl 5.10</p>
<p>And I couldn&#8217;t upgrade my system to this version.</p>
<p>Many thanks!</p>
<p>Posted by Kevin Smith on July 31st, 2008</p>
<hr class="soft" />One small typo.  </p>
<p><tt>while ()</tt></p>
<p>Should be:</p>
<p><tt>while (&lt;TXT&gt;)</tt></p>
<p>-Peter</p>
<p>Posted by <a  rel="nofollow" href='www.pburkholder.com'>Peter Burkholder</a> on April 09th, 2009</p>
<p><!--[if IE]><iframe allowTransparency="true" class="addtoany_special_service facebook_like" src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmore-modrewrite-using-a-dbm-file-instead-of-a-txt-file&amp;layout=button_count&amp;show_faces=false&amp;width=75&amp;action=like&amp;colorscheme=light&amp;height=20" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service facebook_like" src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmore-modrewrite-using-a-dbm-file-instead-of-a-txt-file&amp;layout=button_count&amp;show_faces=false&amp;width=75&amp;action=like&amp;colorscheme=light&amp;height=20" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmore-modrewrite-using-a-dbm-file-instead-of-a-txt-file&amp;counturl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmore-modrewrite-using-a-dbm-file-instead-of-a-txt-file&amp;count=horizontal&amp;text=More%20ModRewrite%20%26%238211%3B%20Using%20a%20dbm%20file%20instead%20of%20a%20txt%20file" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:55px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmore-modrewrite-using-a-dbm-file-instead-of-a-txt-file&amp;counturl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmore-modrewrite-using-a-dbm-file-instead-of-a-txt-file&amp;count=horizontal&amp;text=More%20ModRewrite%20%26%238211%3B%20Using%20a%20dbm%20file%20instead%20of%20a%20txt%20file" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:55px;height:20px"></iframe><!--<![endif]--><a class="a2a_button_reddit" href="http://www.addtoany.com/add_to/reddit?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmore-modrewrite-using-a-dbm-file-instead-of-a-txt-file&amp;linkname=More%20ModRewrite%20%26%238211%3B%20Using%20a%20dbm%20file%20instead%20of%20a%20txt%20file" title="Reddit" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/reddit.png" width="16" height="16" alt="Reddit"/></a> <a class="a2a_button_linkedin" href="http://www.addtoany.com/add_to/linkedin?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmore-modrewrite-using-a-dbm-file-instead-of-a-txt-file&amp;linkname=More%20ModRewrite%20%26%238211%3B%20Using%20a%20dbm%20file%20instead%20of%20a%20txt%20file" title="LinkedIn" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/linkedin.png" width="16" height="16" alt="LinkedIn"/></a> <a class="a2a_button_stumbleupon" href="http://www.addtoany.com/add_to/stumbleupon?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmore-modrewrite-using-a-dbm-file-instead-of-a-txt-file&amp;linkname=More%20ModRewrite%20%26%238211%3B%20Using%20a%20dbm%20file%20instead%20of%20a%20txt%20file" title="StumbleUpon" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/stumbleupon.png" width="16" height="16" alt="StumbleUpon"/></a> <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmore-modrewrite-using-a-dbm-file-instead-of-a-txt-file&amp;title=More%20ModRewrite%20%26%238211%3B%20Using%20a%20dbm%20file%20instead%20of%20a%20txt%20file">Share/Bookmark</a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.jeremytunnell.com/posts/more-modrewrite-using-a-dbm-file-instead-of-a-txt-file/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mod_rewrite: Attempting to bend RewriteMap, RewriteCond, and RewriteRule to my will&#8230;</title>
		<link>http://www.jeremytunnell.com/posts/mod_rewrite-attempting-to-bend-rewritemap-rewritecond-and-rewriterule-to-my-will</link>
		<comments>http://www.jeremytunnell.com/posts/mod_rewrite-attempting-to-bend-rewritemap-rewritecond-and-rewriterule-to-my-will#comments</comments>
		<pubDate>Fri, 22 Aug 2008 00:39:10 +0000</pubDate>
		<dc:creator>Jeremy Tunnell</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[mod_rewrite]]></category>
		<category><![CDATA[rewritecond]]></category>
		<category><![CDATA[rewritemap]]></category>
		<category><![CDATA[rewriterule]]></category>

		<guid isPermaLink="false">http://www.jeremytunnell.com/?p=6</guid>
		<description><![CDATA[RewriteEngine On RewriteMap redirects txt:/home/.../.../rewriterules.map RewriteRule ^(.*)$ ${redirects:$1&#124;$1} [R,L,NC] How does it work? (See here for details.) The first line turns on mod_rewrite. The next line sets the location of the map file (the two column list of source/destinations). The third line sets a RewriteRule that says &#8220;take everything in the request uri&#8221; (.*), and [...]]]></description>
			<content:encoded><![CDATA[<div class="code">
<pre>
RewriteEngine On
RewriteMap redirects txt:/home/.../.../rewriterules.map
RewriteRule ^(.*)$ ${redirects:$1|$1} [R,L,NC]
</pre>
</div>
<p>How does it work?  (See <a href="http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html#RewriteMap">here</a> for details.) </p>
<p>The first line turns on mod_rewrite.  The next line sets the location of the map file (the two column list of source/destinations).  The third line sets a RewriteRule that says &#8220;take everything in the request uri&#8221; (.*), and search the RewriteMap redirects for a match.  If we have a match, the user&#8217;s browser gets a redirect and is forwarded to the new uri.  If we don&#8217;t get a match, i&#8217;ve specified with the $1 backreference that the user is to be transparently passed on to the uri he requested.</p>
<p>The problem is that when Apache doesn&#8217;t find a match in the rewritemap, we get a new request for the same uri&#8230;which runs through the process, ending in a request for the same uri&#8230;and so on.  Because I want to redirect the user instead of handling the change transparently, I keep running into an infinite loop problem.
<p>So we use a RewriteCond.</p>
<div class="code">
<pre>
RewriteEngine On
RewriteMap redirects txt:/home/.../.../rewriterules.map
RewriteCond ${redirects:$1}   >"" [NC]
RewriteRule ^(.*)$ ${redirects:$1|$1} [R,L,NC]
</pre>
</div>
<p>We basically say &#8220;Look up the uri from the following RewriteRule ($1 means look ahead to the next RewriteRule.  We could look behind to the last RewriteCond by using %1.) and if it is lexically greater than the empty string then do the Rewrite.  Otherwise, skip it.</p>
<h3>Version 2</h3>
<p>I never got the [NC] switches to work so I just converted everything to lowercase before I do the comparisons (You must make sure your map is all lowercase).</p>
<div class="code">
<pre>
RewriteEngine On
RewriteMap redirects txt:/home/.../.../rewriterules.map
RewriteMap lowercase int:tolower
RewriteCond ${lowercase:%{REQUEST_URI}|NONE} ^(.+)$
RewriteCond ${redirects:%1}   >""
RewriteRule ^(.*)$ ${redirects:%1} [R,L]
</pre>
</div>
<h3>Links</h3>
<ul>
<li><a href="http://wiki.osuosl.org/display/LNX/Scalable+Top-level+Apache+Rewrites">Check out here for more good mod_rewrite explanations</a></li>
<li><a href="http://www.sitepoint.com/article/guide-url-rewriting">Mod Rewrite Tutorial</a></li>
<li><a href="http://www.sitepoint.com/article/mod_rewrite-no-endless-loops">No more endless loops</a></li>
<li><a href="http://httpd.apache.org/docs/2.0/misc/rewriteguide.html">Lots of rewrite examples</a></li>
</ul>
<h3>Archived Comments</h3>
<p>Thanks for this tip, was having a problem with an infinite loop on a rewrite map &#8211; this helped.</p>
<p>Posted by James on September 14th, 2007</p>
<hr class="soft" />Found this via Google.  Thanks for the tip!</p>
<p>Posted by foo on February 10th, 2008</p>
<hr class="soft" />Thank you for sharing this missing part of the Apache documentation. Worked great for me. </p>
<p>Posted by <a href='http://networkers.se'>Fredrik Nygren</a> on March 17th, 2008</p>
<hr class="soft" />Thank you very much </p>
<p>Posted by <a href='http://www.sohbet15.com'>sohbet</a> on December 13th, 2008</p>
<hr class="soft" />thx for this great article, i searched for hours!</p>
<p>Posted by <a href='http://www.checkpointmedia.com'>Felix</a> on January 23rd, 2009</p>
<hr class="soft" />Thanks for this article, solved a little typo in my script and only noticed it after looking at this article.</p>
<p>Posted by <a href='http://www.freehillmedia.com'>Web Design Sydney Melbourne Brisbane</a> on March 17th, 2009</p>
<hr class="soft" />Oh, can I kiss your toes?  </p>
<p>Seriously, I didn&#8217;t grok the bit about using rewritemaps in a RewriteCond before.  Thanks!</p>
<p>Peter</p>
<p>Posted by <a href='www.pburkholder.com'>Peter Burkholder</a> on July 14th, 2009</p>
<hr class="soft" />Thanks for this!</p>
<p>Just one thing &#8211; the syntax for the &#8220;greater than the empty string&#8221; is wrong &#8211; >&#8221;" fails to match certain things (for example, if the result of your rewritemap is the number 9).  The correct syntax is &#8220;> &#8221; (note the order of the quotes), which matches any ascii value lexically greater than space (char(32)).</p>
<p>Posted by <a href='http://www.isotoma.com/'>Andy Theyers</a> on July 20th, 2009</p>
<hr class="soft" />Here&#8217;s a little solution I came up with for making my URLs prettier and getting search engines to repoint to the new URL. I have a products db that has uppercase word keys for each product that points to the numeric product id. Then I have a reverse db that contains the same in the opposite order. So far this seems to work..</p>
<p> <br />
 RewriteMap uppercase int:toupper<br /> <br />
 RewriteMap products dbm:conf/products.dbm<br /> <br />
 RewriteMap rproducts dbm:conf/rproducts.dbm</p>
<p> # 301 redirect ugly product URL to user-friendly word based URL.<br /> <br />
 RewriteCond %{QUERY_STRING} ^partNumber=(\d*)$<br /> <br />
 RewriteCond ${rproducts:%1} >&#8221;"<br /> <br />
 RewriteRule ^/product\.html$ /product/${rproducts:%1|%1}? [R=301,L]</p>
<p> # Convert user-friendly word based product URL internally to ugly URL with part number.<br /> <br />
 RewriteRule ^/product/(\D.*)$ /product.html?partNumber=${products:${uppercase:$1}} [E=PAGE:product.html]</p>
<p>Posted by <a href='https://www.plumbersstock.com/'>MikeFM</a> on July 28th, 2009</p>
<hr class="soft" />Hi, I am working on the rewritemap and rewriterule for my website. actually requirement is like i have one website whose address is http://www.myside1.com now since i am going to retire this website so  i need to redirect most of the pages to new website. i want to use map file for this. i have created this mapping file where i want to keep maping like /folder1/page1.html http://newwebsite.com/content/view/hello.html in this way i want to use the redirection. i dont want to hardcode the each redirect rule. I can have /folder2/page1.html also. Could you please help me to have the correct rule.</p>
<p>Posted by yashjimmy on July 09th, 2010</p>
<p><!--[if IE]><iframe allowTransparency="true" class="addtoany_special_service facebook_like" src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmod_rewrite-attempting-to-bend-rewritemap-rewritecond-and-rewriterule-to-my-will&amp;layout=button_count&amp;show_faces=false&amp;width=75&amp;action=like&amp;colorscheme=light&amp;height=20" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service facebook_like" src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmod_rewrite-attempting-to-bend-rewritemap-rewritecond-and-rewriterule-to-my-will&amp;layout=button_count&amp;show_faces=false&amp;width=75&amp;action=like&amp;colorscheme=light&amp;height=20" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmod_rewrite-attempting-to-bend-rewritemap-rewritecond-and-rewriterule-to-my-will&amp;counturl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmod_rewrite-attempting-to-bend-rewritemap-rewritecond-and-rewriterule-to-my-will&amp;count=horizontal&amp;text=Mod_rewrite%3A%20Attempting%20to%20bend%20RewriteMap%2C%20RewriteCond%2C%20and%20RewriteRule%20to%20my%20will%26%238230%3B" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:55px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmod_rewrite-attempting-to-bend-rewritemap-rewritecond-and-rewriterule-to-my-will&amp;counturl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmod_rewrite-attempting-to-bend-rewritemap-rewritecond-and-rewriterule-to-my-will&amp;count=horizontal&amp;text=Mod_rewrite%3A%20Attempting%20to%20bend%20RewriteMap%2C%20RewriteCond%2C%20and%20RewriteRule%20to%20my%20will%26%238230%3B" frameborder="0" scrolling="no" style="border:none;overflow:hidden;width:55px;height:20px"></iframe><!--<![endif]--><a class="a2a_button_reddit" href="http://www.addtoany.com/add_to/reddit?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmod_rewrite-attempting-to-bend-rewritemap-rewritecond-and-rewriterule-to-my-will&amp;linkname=Mod_rewrite%3A%20Attempting%20to%20bend%20RewriteMap%2C%20RewriteCond%2C%20and%20RewriteRule%20to%20my%20will%26%238230%3B" title="Reddit" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/reddit.png" width="16" height="16" alt="Reddit"/></a> <a class="a2a_button_linkedin" href="http://www.addtoany.com/add_to/linkedin?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmod_rewrite-attempting-to-bend-rewritemap-rewritecond-and-rewriterule-to-my-will&amp;linkname=Mod_rewrite%3A%20Attempting%20to%20bend%20RewriteMap%2C%20RewriteCond%2C%20and%20RewriteRule%20to%20my%20will%26%238230%3B" title="LinkedIn" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/linkedin.png" width="16" height="16" alt="LinkedIn"/></a> <a class="a2a_button_stumbleupon" href="http://www.addtoany.com/add_to/stumbleupon?linkurl=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmod_rewrite-attempting-to-bend-rewritemap-rewritecond-and-rewriterule-to-my-will&amp;linkname=Mod_rewrite%3A%20Attempting%20to%20bend%20RewriteMap%2C%20RewriteCond%2C%20and%20RewriteRule%20to%20my%20will%26%238230%3B" title="StumbleUpon" rel="nofollow" target="_blank"><img src="http://www.jeremytunnell.com/wp-content/plugins/add-to-any/icons/stumbleupon.png" width="16" height="16" alt="StumbleUpon"/></a> <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.jeremytunnell.com%2Fposts%2Fmod_rewrite-attempting-to-bend-rewritemap-rewritecond-and-rewriterule-to-my-will&amp;title=Mod_rewrite%3A%20Attempting%20to%20bend%20RewriteMap%2C%20RewriteCond%2C%20and%20RewriteRule%20to%20my%20will%26%238230%3B">Share/Bookmark</a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.jeremytunnell.com/posts/mod_rewrite-attempting-to-bend-rewritemap-rewritecond-and-rewriterule-to-my-will/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

