<?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>Coffee on the Keyboard &#187; PHP</title>
	<atom:link href="http://coffeeonthekeyboard.com/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://coffeeonthekeyboard.com</link>
	<description>by James Socol</description>
	<lastBuildDate>Fri, 20 Apr 2012 22:17:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com"/>		<item>
		<title>The Problem with TodaysMeet</title>
		<link>http://coffeeonthekeyboard.com/the-problem-with-todaysmeet-550/</link>
		<comments>http://coffeeonthekeyboard.com/the-problem-with-todaysmeet-550/#comments</comments>
		<pubDate>Sat, 29 Jan 2011 16:35:42 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[architecture]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[todaysmeet]]></category>
		<category><![CDATA[webdev]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=550</guid>
		<description><![CDATA[TodaysMeet is a project I started in 2008 to help my father solve a problem in one of his classes. The fact that it&#8217;s as popular as it is—mostly in education—never ceases to amaze me. Unfortunately, I don&#8217;t give TodaysMeet the attention it, and more importantly its users, deserve. This is because TodaysMeet has two [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://todaysmeet.com/">TodaysMeet</a> is a project I started in 2008 to help <a href="http://speedchange.blogspot.com">my father</a> solve a problem in one of his classes. The fact that it&#8217;s as popular as it is—mostly in education—never ceases to amaze me.</p>
<p>Unfortunately, I don&#8217;t give TodaysMeet the attention it, and more importantly its users, deserve. This is because TodaysMeet has two fatal flaws that, if they haven&#8217;t crippled it yet, will someday.</p>
<ul>
<li>The UI is based on proof-of-concept JavaScript.</li>
<li>The back-end is based on <a href="http://svn.jamessocol.com/maveric">my own framework</a>.</li>
</ul>
<p>What follows is the sad history of TodaysMeet development.</p>
<h3>Origin Story</h3>
<p>TodaysMeet came out of a conversation between my father and I, but it&#8217;s origins are slightly older. In some downtime in late 2007 I was trying to familiarize myself with various JavaScript frameworks by writing a UI for the same back-end in each of them. It was a pretty basic Ajax comment system. I believe it polled the server every minute. If I remember correctly, I got busy and abandoned it after creating <a href="http://www.prototypejs.org/">Prototype</a> and <a href="http://jquery.com/">jQuery</a> versions.</p>
<p>Around the same time I was enamored of <a href="http://rubyonrails.org/">Rails</a>, and trying to round out <a href="http://svn.jamessocol.com/maveric">Maveric</a> into a decent Rails-inspired PHP framework.</p>
<p>So when my father said he wanted something like Twitter for a single classroom, that he could project on a wall, and wouldn&#8217;t require signing up, I put these things together in my head. TodaysMeet is basically the proof-of-concept Prototype JS running on top of an old version of Maveric.</p>
<h3>The Situation Now</h3>
<p><a href="http://www.brandonsavage.net/why-every-developer-should-write-their-own-framework/">Every developer should write a framework</a>, I think it&#8217;s a fantastic learning experience. But they should never build a production website out of it.</p>
<p>Even though Maveric got a little better after I created TodaysMeet, it&#8217;s still based on an untested, unsupported framework with no support for basic things like storage back-ends or caching.</p>
<p>The UI is still based on Prototype, which I haven&#8217;t used in years, and the fundamental client-server interactions are still that original &#8220;learning the library&#8221; code.</p>
<p>Essentially, TodaysMeet is a prototype masquerading as a production-ready product.</p>
<p>The result is that working on it is slow, difficult, and frankly unpleasant. Adding features—like the long-promised password protected rooms—is painful and, with no test suite, dangerous. The one real feature I added, Twitter integration, barely works when it works at all.</p>
<p>But users don&#8217;t care about any of that. They see that it works, mostly. They might see that it doesn&#8217;t get much attention and the UI feels three years old (because it is, of course).</p>
<h3>Where Do We Go From Here?</h3>
<p>TodaysMeet <em>could</em> be awesome, but it needs to go all the way down to the basic stack and get rebuilt. TodaysMeet is an absolutely perfect candidate for all sorts of new, exciting tools and techniques. To use any of them means starting over.</p>
<p>This is the first of a two-part post. In the next part, I&#8217;m going to outline the architecture I <em>want</em>, instead of the architecture I <em>have</em>.</p>
<p>Hopefully, some social aspect of talking about this will lead to me actually doing something about it.</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/the-problem-with-todaysmeet-550/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>The Evolution of SUMO</title>
		<link>http://coffeeonthekeyboard.com/the-evolution-of-sumo-339/</link>
		<comments>http://coffeeonthekeyboard.com/the-evolution-of-sumo-339/#comments</comments>
		<pubDate>Tue, 23 Feb 2010 22:39:21 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[kitsune]]></category>
		<category><![CDATA[mozilla]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[sumo]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=339</guid>
		<description><![CDATA[When I joined the SUMO team six months ago, the team was just starting a discussion of &#8220;where do we go from here?&#8221;  SUMO was built on a CMS called TikiWiki, and had diverged pretty significantly in two years. (David Tenser wrote a more detailed history if you&#8217;re interested.) After a few months of talking [...]]]></description>
			<content:encoded><![CDATA[<p>When I joined the <a title="SUpport dot MOzilla dot com" href="http://support.mozilla.com/" target="_blank">SUMO</a> team six months ago, the team was just starting a discussion of &#8220;where do we go from here?&#8221;  SUMO was built on a <abbr title="Content Management System">CMS</abbr> called <a href="http://tikiwiki.org/" target="_blank">TikiWiki</a>, and had diverged pretty significantly in two years. (David Tenser wrote <a href="http://blog.mozilla.com/sumo/2010/02/18/the-bright-future-of-the-sumo-platform/" target="_blank">a more detailed history</a> if you&#8217;re interested.)</p>
<p>After a few months of talking and testing—and a few changes of direction—we&#8217;ve decided that SUMO will follow our colleagues on <a title="Addons dot Mozilla dor Org" href="https://addons.mozilla.org/" target="_blank">AMO</a> and move to a custom web application, built on <a href="http://www.djangoproject.com/">Django</a>, a development framework in Python.</p>
<p>Why are we committing to such a dramatic new direction? Three major reasons. <span id="more-339"></span><em>Keep in mind that SUMO was built on TikiWiki 1.10, a little more than two years out of date.</em></p>
<h3>Performance</h3>
<p>TikiWiki is a very feature-rich application. An unfortunate trade-off for us is performance, especially on a site serving 16 million users every week. <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=532498" target="_blank">As our European users</a> in particular know, SUMO can be unacceptably slow at times, especially when editing articles. Many of the changes we made to the platform—most of which were contributed back over the past few months—were to improve performance via tools like output caching, database replication, and just refactoring. When we evaluated the latest version of TikiWiki, we found that performance was around the same, on average.</p>
<p>In the new platform, we&#8217;ll be taking advantage of techniques now available, including query and template/fragment caching and expect to see dramatic performance improvements. We&#8217;ll also be avoiding some of the performance pitfalls that TikiWiki fell into over the years with improvements to the security, database, and templating layers, among others.</p>
<p>But the biggest performance impact—I expect—will be moving from a general-purpose CMS to a dedicated web application, focused on providing the SUMO experience.</p>
<h3>Hackability</h3>
<p>To work on SUMO, you have to overcome a steep learning curve. Components tend to be tightly-coupled, or grouped in unintuitive ways, and are not as extensible as we&#8217;d like. The lack of a comprehensive test suite leaves changes to important sections of code open to introducing regressions in otherwise unrelated, dependent areas. SUMO 1.x also fails to function without a relatively complete copy of its database, which makes it difficult for community members outside the company to contribute.</p>
<p>With the new platform, and some discipline from the team, our goal is to improve all of these and make it easier for someone to get started hacking on SUMO.</p>
<ul>
<li>We&#8217;ll be striving to keep code loosely-coupled and extensible—including using existing or external libraries whenever possible, and turning our own contributions into external libraries where possible.</li>
<li>We&#8217;re adopting a test-driven development workflow to ensure that our components are easier to safely hack, and lighten the load on our <abbr title="Quality Assurance">QA</abbr> team by reducing regressions.</li>
<li><abbr title="Test-Driven Development">TDD</abbr> and Django will make it easier to work without a copy of the database, using fixtures and migrations to minimize the dependence on real data.</li>
</ul>
<p>The net effect of these decisions will be to lower the barrier to entry to SUMO development, and hopefully make useful code available to other projects. Wil Clouser <a href="http://micropipes.com/blog/2009/11/17/amo-development-changes-in-2010/" target="_blank">listed more strengths</a> of Django as a platform when the AMO team decided to switch.</p>
<h3>Strength in Numbers</h3>
<p>By using the same platform as AMO, both teams will benefit from sharing code and resources. We&#8217;re already using the same template adapter, database router, caching layer, and HTML sanitizer. As open source developers often say: &#8220;with enough eyes, all bugs are shallow,&#8221; and by sharing code we get more eyes on it. We&#8217;ll benefit from insights the AMO team has gleaned by starting the process of moving from a PHP framework to Python just ahead of us. We&#8217;ll even be able to send code reviews across teams and benefit from deeper knowledge of the various problem domains we share: have a question about localization? Both teams can share expertise and best-practices.</p>
<p>Solving problems once and sharing the solution directly reduces the amount of work both teams have to do. And when SUMO writes code in such a way that AMO can use it, we can also release it separately so others can benefit from our solutions—and point out flaws and contribute improvements.</p>
<h3>Other Changes</h3>
<p>Also among the changes coming in the next year:</p>
<ul>
<li><strong>Version Control System. </strong>Though we don&#8217;t have a specific plan in place, it seems likely that SUMO will be moving from SVN to Git for source control. Because Git is distributed, it allows us to use a more <a href="http://nvie.com/archives/323" target="_blank">collaborative workflow</a>, and it&#8217;s easier for us to push our code to public repositories like <a href="http://github.com/">Github</a>.</li>
<li><strong>Continuous Integration.</strong> We&#8217;ll be using <a href="https://hudson.dev.java.net/">Hudson</a> for continuous integration, which will automate our tests and alert us to potential issues and regressions. The web QA team has also been working to make sure our <a href="http://seleniumhq.org/">Selenium</a> tests can run through Hudson, greatly increasing test coverage for a web application like SUMO.</li>
<li><strong>Interface Localization</strong>. One of the ways we plan to improve the SUMO experience this year is by moving our interface localization to <a href="http://www.gnu.org/software/gettext/">gettext</a>, which is an industry-standard tool for localization. As we move parts of the site from TikiWiki to Django, those new sections will be localized via gettext, which helps us take advantage of our great community with tools like <a href="http://localize.mozilla.org/">Verbatim</a>.</li>
</ul>
<h3>A Foundation for the Future</h3>
<p>The goal of all of this work—and it will be a lot of work—is to put SUMO on a solid foundation for future growth and, at the same time, improve the experience for everyone—from developers to contributors to localizers to visitors. We have a daunting and aggressive road ahead of us, but I&#8217;m confident that we&#8217;ll emerge in a better place.</p>
<p>SUMO 2 is codenamed <a href="https://wiki.mozilla.org/Support/Kitsune">Kitsune</a>, and is already <a href="http://github.com/jsocol/kitsune">up on Github</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/the-evolution-of-sumo-339/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>WP: Better Search Widget 1.1</title>
		<link>http://coffeeonthekeyboard.com/wp-better-search-widget-1-1-232/</link>
		<comments>http://coffeeonthekeyboard.com/wp-better-search-widget-1-1-232/#comments</comments>
		<pubDate>Thu, 02 Jul 2009 17:05:05 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[l10n]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[release]]></category>
		<category><![CDATA[widget]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=232</guid>
		<description><![CDATA[Better Search Widget 1.1 is a significant upgrade to Better Search Widget that adds new features and fixes an old bug with internationalization. Features (New features in bold.) Optional default value. Optional, custom widget title. Optional onfocus and onblur listeners. Optional, customizable focus and blur colors. Custom button value. Custom field size. The built-in search [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://coffeeonthekeyboard.com/wp-content/uploads/2009/07/better-search-widget.zip">Better Search Widget 1.1</a> is a significant upgrade to <a href="http://coffeeonthekeyboard.com/wp-plugin-better-search-widget-113/" title="Better Search Widget">Better Search Widget</a> that adds new features and fixes an old bug with internationalization.</p>
<h3>Features</h3>
<p>(New features in bold.)</p>
<ul>
<li><strong>Optional default value</strong>.</li>
<li><strong>Optional,</strong> custom widget title<strong>.</strong></li>
<li><strong>Optional onfocus and onblur listeners.</strong></li>
<li><strong>Optional, customizable focus and blur colors.</strong></li>
<li>Custom button value.</li>
<li>Custom field size.</li>
</ul>
<p>The built-in search widget has only one of these features, the optional, custom title.</p>
<h4>Onfocus and Onblur</h4>
<p>In order to use the blur and focus colors, you must enable the onfocus and onblur event listeners. In order to use the listeners, you must specify a default value (otherwise none of this makes sense). Here&#8217;s an example:</p>
<div style="border: 1px solid #333; margin: 0.5em auto; padding: 0.7em 0; width: 50%; text-align: center;">
<form>
<input style="color: #999; width: 80%;" type="text" value="Default" onfocus="this.style.color='#333';if('Default'==this.value)this.value='';" onblur="if(''==this.value){this.style.color='#999';this.value='Default'}" /></form>
</div>
<h3>Bug Fixes</h3>
<p>A pretty serious typo meant that none of the internationalization code worked correctly. This has been fixed, and en_US, en_GB, and fr_FR localizations are available. de_DE is coming. If you&#8217;d like to translate, there is a .pot file included in the languages directory.</p>
<h3>License</h3>
<p>Better Search Widget is released under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT License</a>. If you use it, or have suggestions for new features or bug fixes, let me know!</p>
<h3>Getting It</h3>
<p>You can download <a href="http://coffeeonthekeyboard.com/wp-content/uploads/2009/07/better-search-widget.zip">Better Search Widget 1.1</a> now in a Zip file. Or, to save yourself some trouble,  you can check it out of Subversion from</p>
<pre>svn co svn://jamessocol.com/better-search-widget/tags/1.1.0 ./better-search-widget</pre>
<p>(Run that in your <code>wp-content/plugins</code> directory.) Subversion will make it easiest to upgrade later.</p>
<h3>Roadmap</h3>
<p>Soon, though probably not today, I will be releasing Better Search Widget 2, which will take advantage of the new Widget API in WordPress 2.8. This will add support for multiple instances of the widget, but will require at least WordPress 2.8. You should upgrade, anyway.</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/wp-better-search-widget-1-1-232/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Responsible SQL: How to Authenticate Users</title>
		<link>http://coffeeonthekeyboard.com/responsible-sql-how-to-authenticate-144/</link>
		<comments>http://coffeeonthekeyboard.com/responsible-sql-how-to-authenticate-144/#comments</comments>
		<pubDate>Sun, 09 Nov 2008 17:16:58 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[attack]]></category>
		<category><![CDATA[Back-end]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[injection]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=144</guid>
		<description><![CDATA[Most SQL-injection articles set a horrible example for young programmers. Here is a very typical &#8220;bad example&#8221; of why you need to escape user data before it goes into SQL queries: (ed. The symbol « is a line break that’s not in the real code.) $username = $_POST&#91;&#8216;username&#8217;&#93;; // username=admin $password = $_POST&#91;&#8216;password&#8217;&#93;; // password=&#8217; [...]]]></description>
			<content:encoded><![CDATA[<p>Most SQL-injection articles set a horrible example for young programmers.</p>
<p>Here is a very typical &#8220;bad example&#8221; of why you need to escape user data before it goes into SQL queries:</p>
<p>(ed. The symbol « is a line break that’s not in the real code.)</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$username</span> = <span class="re0">$_POST</span><span class="br0">&#91;</span><span class="st0">&#8216;username&#8217;</span><span class="br0">&#93;</span>; <span class="co1">// username=admin</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$password</span> = <span class="re0">$_POST</span><span class="br0">&#91;</span><span class="st0">&#8216;password&#8217;</span><span class="br0">&#93;</span>; <span class="co1">// password=&#8217; OR 1=1; &#8212; &#8216;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$user</span> = <span class="re0">$db</span>-&gt;<span class="me1">query</span><span class="br0">&#40;</span><span class="st0">&quot;SELECT * FROM users WHERE «</span></div>
</li>
<li class="li2">
<div class="de2"><span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; username=&#8217;$username&#8217; AND «</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; password=&#8217;$password&#8217; LIMIT 1;&quot;</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>The point, of course, is that you must sanitize your user input, or else this person would run this query:</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$user</span> = <span class="re0">$db</span>-&gt;<span class="me1">query</span><span class="br0">&#40;</span><span class="st0">&quot;SELECT * FROM users WHERE «</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; username=&#8217;admin&#8217; AND «</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; password = &#8221; OR 1=1; &#8212; &#8216; LIMIT 1;&quot;</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>Which grants the sneaky user all your admin privileges. Other versions have nefarious users dropping your users or articles tables.</p>
<p>The problem is: this is the wrong way to authenticate users. These examples are written for beginners to understand the importance of sanitizing input, but they also provide a model to those beginners for how user authentication works. And it&#8217;s a very bad model.</p>
<p>This is a long one, more after the break.<span id="more-144"></span></p>
<p>The only upside to authenticating this way is that you don&#8217;t expose any information on failure, that is, if I&#8217;m trying to hijack someone&#8217;s account, I can&#8217;t tell the difference between an invalid user name and a valid user name with a bad password. That&#8217;s good, but there are good reasons not to do this at the database level.</p>
<p>The &#8220;correct&#8221; way is not much more complex. Basically:</p>
<ol>
<li>Look up the record with the <strong>username</strong> only.</li>
<li>Get the (hashed) password out of the database.</li>
<li>Hash the submitted password.</li>
<li>Compare the two hashes.</li>
</ol>
<p>This is really not very hard to implement. In PHP:</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="coMULTI">/**</span></div>
</li>
<li class="li1">
<div class="de1"><span class="coMULTI">&nbsp;* Check a password against the database</span></div>
</li>
<li class="li1">
<div class="de1"><span class="coMULTI">&nbsp;*</span></div>
</li>
<li class="li1">
<div class="de1"><span class="coMULTI">&nbsp;* @<a href="http://twitter.com/param">param</a> string $username The username to check</span></div>
</li>
<li class="li2">
<div class="de2"><span class="coMULTI">&nbsp;* @<a href="http://twitter.com/param">param</a> string $password The (supposed) password</span></div>
</li>
<li class="li1">
<div class="de1"><span class="coMULTI">&nbsp;* @<a href="http://twitter.com/return">return</a> int 0=success, 1=bad username, 2=bad password</span></div>
</li>
<li class="li1">
<div class="de1"><span class="coMULTI">&nbsp;*/</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">function</span> check_password <span class="br0">&#40;</span> <span class="re0">$username</span>, <span class="re0">$password</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$db</span> = <span class="kw2">new</span> mysqli<span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// we need to talk to the DB</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">// the real_escape_string() function is much better</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">// than add_slashes() for escaping MySQL database input</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$_username</span> = <span class="re0">$db</span>-&gt;<span class="me1">real_escape_string</span><span class="br0">&#40;</span><span class="re0">$username</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="co1">// I try to make my SQL queries as easy to read</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">// as possible. (Not always very easy.)</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$result</span> = <span class="re0">$db</span>-&gt;<span class="me1">query</span><span class="br0">&#40;</span><span class="st0">&quot;SELECT password &quot;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span class="st0">&quot;FROM users &quot;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span class="st0">&quot;WHERE username = &#8216;{$_username}&#8217; &quot;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span class="st0">&quot;LIMIT 1;&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">// we&#8217;re assuming the query ran correctly</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">// if we can&#8217;t return a row, then there&#8217;s no user with</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="co1">// that name</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> !<span class="re0">$user</span> = <span class="re0">$result</span>-&gt;<span class="me1">fetch_assoc</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">1</span>; <span class="co1">// return code for bad username</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="co1">// now, assuming the password was hashed with crypt()</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$user</span><span class="br0">&#91;</span><span class="st0">&#8216;password&#8217;</span><span class="br0">&#93;</span> != «</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/crypt"><span class="kw3">crypt</span></a><span class="br0">&#40;</span><span class="re0">$password</span>, <span class="re0">$user</span><span class="br0">&#91;</span><span class="st0">&#8216;password&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">2</span>; <span class="co1">// return code for bad password</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">0</span>; <span class="co1">// return code for success</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>What&#8217;s going on here? Basically, we&#8217;re looking up the user by the username. If we don&#8217;t find a user, we throw out an error. If we do find a user, we re-encrypt the password they supplied, and check it against the encrypted password we already have. If they don&#8217;t match, we throw out an error. If they do, the user is allowed to log in.</p>
<p>There are two key differences between this method and the method so often espoused by tutorial writers:</p>
<ol>
<li>This method stores an encrypted password instead of plain text.</li>
<li>This method differentiates between bad usernames and bad passwords.</li>
</ol>
<p>#1 should be obvious. Never store an unencrypted password. It&#8217;s extremely dangerous: if someone ever gets a look at the table, they can just read the users&#8217; passwords—which may well be the same as their bank password (no it shouldn&#8217;t be, but it probably is). And it&#8217;s unnecessary. Every server-side language implements the MD5 hash, which is weak but works. Better options (like PHP&#8217;s <a onclick="window.open(this.href,'newwindow'); return false;" href="http://www.php.net/crypt">crypt()</a>) can use algorithms like Triple-DES, SHA1, Blowfish, or at least MD5 with a random salt.</p>
<p>But wait, #2, I said it was better <em>not</em> to distinguish between a bad username and a bad password, right? Well&#8230; yes, to the end user. In either case, I should display a message like &#8220;Bad username or password&#8221; to the person who tried to log in.</p>
<p>Internally, however, I want to know what happened. Is someone targetting known users, or just trying random combinations? How did they find real usernames? Where should I be improving security?</p>
<p>You&#8217;re also minimizing the number of user-submitted strings that get sent to the database. There are fewer opportunities for you to accidently allows an injection attack. If you have a policy on username syntax, you can keep yourself even safer by not talking to the database if the username is bad:</p>
<p>(I&#8217;ve omitted logging or real error-handling here. In a live version, I would probably wrap most of this in a <code><a onclick="window.open(this.href,'newwindow'); return false;" href="http://us2.php.net/manual/en/language.exceptions.php">try</a></code> block, throw one of three types of exceptions, and do some logging in the <code>catch</code> block.)</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">&lt;?php</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// Usernames must start with a letter, and contain</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// only letters, numbers, underscores and dots, but</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co1">// must not end with a dot or underscore.</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$user_regex</span> = <span class="st0">&#8216;/[a-zA-Z][a-zA-Z0-9_<span class="es0">\.</span>]*[a-zA-Z0-9]/&#8217;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/preg_match"><span class="kw3">preg_match</span></a><span class="br0">&#40;</span><span class="re0">$user_regex</span>,<span class="re0">$username</span><span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">// the username matches our allowed syntax</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$auth</span> = check_password<span class="br0">&#40;</span><span class="re0">$username</span>, <span class="re0">$password</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$auth</span> === <span class="nu0">0</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="co1">// the do_login() function is an exercise</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="co1">// to the reader</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; do_login<span class="br0">&#40;</span><span class="re0">$username</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// the username was bad, or the username/password</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co1">// was wrong</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// die() is an overly simplistic choice, here.</span></div>
</li>
<li class="li1">
<div class="de1"><a href="http://www.php.net/die"><span class="kw3">die</span></a><span class="br0">&#40;</span><span class="st0">&quot;Bad username or password.&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">?&gt;</span></div>
</li>
</ol>
</div>
<p>Obviously we still escape the username, to make damn sure, but this gives us another place to get information. Did someone actually enter <code>'; DROP TABLE users; --</code> into our login form, or did they just mistype their password.</p>
<p>I&#8217;m going to end with a request: if you&#8217;re about to write a tutorial for beginners, please be aware of what you&#8217;re modeling in your examples. If you&#8217;re doing something you would never do, for the sake of simplicity or because it&#8217;s not the focus of the tutorial, point that out. Link to another tutorial or at least mention that it&#8217;s a bad way to do something.</p>
<p>Don&#8217;t send a quiet message that wrong is OK.</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/responsible-sql-how-to-authenticate-144/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Connecting PHP, IIS 6, and SQL Server 2005</title>
		<link>http://coffeeonthekeyboard.com/connecting-php-iis-6-and-sql-server-2005-129/</link>
		<comments>http://coffeeonthekeyboard.com/connecting-php-iis-6-and-sql-server-2005-129/#comments</comments>
		<pubDate>Thu, 23 Oct 2008 16:33:20 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Back-end]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[iis]]></category>
		<category><![CDATA[microsoft]]></category>
		<category><![CDATA[pdo]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[sql server]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=129</guid>
		<description><![CDATA[I know I will be accosted for this, but at work we needed to run PHP on IIS 6 (fairly simple) and connect it to a remote database server running SQL Server 2005 (not terrible, once I gave up the Microsoft way). Yeah yeah, do it in ASP.NET, I know. While I like C# as [...]]]></description>
			<content:encoded><![CDATA[<p>I know I will be accosted for this, but at work we needed to run PHP on IIS 6 (<a href="http://www.peterguy.com/php/install_IIS6.html">fairly simple</a>) and connect it to a remote database server running SQL Server 2005 (not terrible, once I gave up the Microsoft way).</p>
<p>Yeah yeah, do it in ASP.NET, I know. While I like C# as a language, I kind of hate ASP.NET as a framework, so what are you gonna do? Java was an option but the start-up time was too long for this project.</p>
<p>My first Google search for &#8220;PHP SQL Server 2005&#8243; turned up the Microsoft <a href="http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx">SQL Server 2005 Driver for PHP</a>. &#8220;Well great!&#8221; I thought. It&#8217;s just a PHP extension, very easy to install on Windows. But I didn&#8217;t know the horrid depths into which I was about to sink.</p>
<p>The Microsoft driver comes with an example application and database. The application assumes you are connecting to a local database. There is scant information about remote databases.</p>
<p>The driver defines this function:</p>
<pre>sqlsrv_connect($host[, $connectionOptions[, ...]]);</pre>
<p>The example application tells you to set <code>$host</code> to <var>(local)</var>. Supposedly this works. However, after scouring the internet for several days, and trying every permutation of hostname, Windows networking name, port, IP address, white space, and several other variables that shouldn&#8217;t have been in there, I&#8217;ve decided it doesn&#8217;t talk to remote servers nicely.</p>
<p><a href="http://us.php.net/manual/en/book.pdo.php">PDO</a>&#8216;s ODBC driver, on the other hand, and a quick visit to <a href="http://www.connectionstrings.com/">www.connectionstrings.com</a>, worked wonderfully.</p>
<p>Here is how I needed to create the PDO object. I hope this is useful for someone else:</p>
<p>(ed. The symbol « is a line break that&#8217;s not in the real code.)</p>
<pre>$host     = '1.2.3.4';
$port     = '1433';
$database = 'MyDatabase';
$user     = 'MyDatabaseUser';
$password = 'MyDatabasePassword';

$dsn = "odbc:DRIVER={SQL Server}; «
 SERVER=$server,$port;DATABASE=$database";

try {
  // connect
  $conn = new PDO($dsn,$user,$password);
} catch (PDOException $e) {
  // fancy error handling
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/connecting-php-iis-6-and-sql-server-2005-129/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Help Me Scale</title>
		<link>http://coffeeonthekeyboard.com/help-me-scale-97/</link>
		<comments>http://coffeeonthekeyboard.com/help-me-scale-97/#comments</comments>
		<pubDate>Fri, 06 Jun 2008 14:58:38 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Back-end]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[db]]></category>
		<category><![CDATA[load]]></category>
		<category><![CDATA[microblog]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[query]]></category>
		<category><![CDATA[scalability]]></category>
		<category><![CDATA[social messaging]]></category>
		<category><![CDATA[subquery]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/help-me-scale-97/</guid>
		<description><![CDATA[I&#8217;ve been reading Eran Hammer-Lahav&#8217;s intelligent posts on microblog scalability, and now I&#8217;m concerned about my own &#8220;microblog&#8221; site, Picofiction. Similar to social networks, social updates, social messaging, social&#8230; Like many social web sites—amongst our weaponry&#8230;—Picofiction lets you &#8220;follow&#8221; your favorite authors, displaying all their posts along with yours. I handle this very naïvely: everything [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been reading Eran Hammer-Lahav&#8217;s <a href="http://www.hueniverse.com/hueniverse/2008/04/scaling-a-micro.html">intelligent</a> <a href="http://www.hueniverse.com/hueniverse/2008/03/scaling-a-micro.html">posts on</a> <a href="http://www.hueniverse.com/hueniverse/2008/03/on-scaling-a-mi.html">microblog scalability</a>, and now I&#8217;m concerned about my own &#8220;microblog&#8221; site, <a href="http://picofiction.com/">Picofiction</a>.</p>
<p>Similar to social networks, social updates, social messaging, social&#8230; Like many social web sites—amongst our weaponry&#8230;—Picofiction lets you &#8220;follow&#8221; your favorite authors, displaying all their posts along with yours.</p>
<p>I handle this very naïvely: everything is offloaded to the database. There are three tables involved here, one of users, one of posts, and one of follower/followee bindings.</p>
<p>Here&#8217;s the basic structure of this query:</p>
<pre>SELECT post_id, post_body, post_date, post_type,
  user_name AS author_name, user_id AS author_id
FROM posts
LEFT JOIN users
ON posts.author_id = users.user_id
WHERE author_id = '<var>CURRENT_USER</var>'
OR author_id IN (
  (SELECT followed_id
   FROM followers
   WHERE following_id = '<var>CURRENT_USER</var>')
  )
ORDER BY post_date DESC
LIMIT <var>PAGE_START</var>,20;</pre>
<p>Here&#8217;s where I need help: this works great on a single database, but it does not scale horizontally.</p>
<p>Since this horizontal scalability is such a hot topic right now, I&#8217;m asking for ideas. I&#8217;d like to put in the infrastructure <em>before</em> there is a need for it.</p>
<p>Eran points out that caching is not as simple a solution as we&#8217;d like to think. What do you cache? How do you keep caches in sync?</p>
<p>Does anyone have experience with MySQL Cluster Servers? It seems like the best way of scaling is to make the process as <a href="http://en.wikipedia.org/wiki/Amdahl%27s_law">parallelizable</a> as possible. The database then handles the parallelization, so the less I can do in the program the better, right?</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/help-me-scale-97/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to: Upgrade or Recompile PHP on RHEL5 (Outdated)</title>
		<link>http://coffeeonthekeyboard.com/how-to-upgrade-or-recompile-php-on-rhel5-59/</link>
		<comments>http://coffeeonthekeyboard.com/how-to-upgrade-or-recompile-php-on-rhel5-59/#comments</comments>
		<pubDate>Sat, 03 Nov 2007 17:00:00 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[recompile]]></category>
		<category><![CDATA[red hat]]></category>
		<category><![CDATA[servers]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/how-to-upgrade-or-recompile-php-on-rhel5-59/</guid>
		<description><![CDATA[Update: This post is nearly two years old, and this is not how I would recommend upgrading PHP on RHEL, yet it continues to get traffic. If I can get my hands on a copy of RHEL, I&#8217;ll update this (or I might try using Fedora just to compare). Upgrading PHP on RHEL 5 is [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update: </strong><em>This post is nearly two years old, and this is <strong>not</strong> how I would recommend upgrading PHP on RHEL, yet it continues to get traffic. If I can get my hands on a copy of RHEL, I&#8217;ll update this (or I might try using Fedora just to compare).</em></p>
<p>Upgrading PHP on RHEL 5 is difficult. Having done it on several servers, I&#8217;ve gotten it down to a 15 to 20 step process. It takes a while, but it&#8217;s straightforward. I thought I&#8217;d share, because help was sparse and noncontiguous at best.</p>
<p class="image right"><img src="/blog/images/rhel.png" alt="RedHat Enterprise Linux: Hard to upgrade PHP." width="96" height="31" /></p>
<p>RedHat Enterprise Linux 5 comes with PHP 5.1.6 and, as of this writing, this is the highest version available on yum. If you want to upgrade to 5.2.4, or even recompile 5.1.6 with a custom configuration, you&#8217;ll need to resolve several dependencies, first.</p>
<p class="note">Unless otherwise specified, whenever I run <code>./configure</code>, I always include <code>--enable-shared</code> and <code>--enable-static</code>.</p>
<p>The first step is to make sure you have a working APXS script installed. None of the servers on which I&#8217;ve done this had it. I installed Apache 2.2.4 over the default install, since it was the latest version. Be sure to enable APXS with <code>--enable-so</code>. Be careful configuring Apache, as it likes to install itself in <code>/usr/local/apache2/</code> instead of <code>/etc/httpd/</code>, which you may prefer.</p>
<p>Now we start resolving the dependencies. I&#8217;d start with <strong>libtool</strong> and <strong>libiconv</strong>. The former you should be able to install via yum. The latter you may have to download, and after you configure it, from the source directory copy <code>m4/iconv.m4</code> to <code>/usr/local/share/aclocal/iconv.m4</code>.</p>
<p>Use yum to make sure <code>mysql-devel</code> is installed, you&#8217;ll need it to link to mysql.</p>
<p>Then I&#8217;d do the image manipulation software, since it&#8217;s fairly easy. Use yum to install <code>libjpeg</code>, <code>libpng</code> and <code>freetype</code>. You can then use yum to make sure both <code>gd</code> and <code>gd-devel</code> are installed.</p>
<p>I installed <code>libmcrypt</code>, <code>libmhash</code>, and <code>ming</code> at this point. I&#8217;d say it&#8217;s a good time to get any of these more particular dependencies out of the way. I also installed Tidy, which you need to check out from their CVS repository. You can run <code>build/gnuauto/setup.sh</code> from the Tidy source directory to create the autoconf files.</p>
<p>Now we get to the crux of the matter: configuring PHP. All the major dependencies should have been taken care of. If you have other PHP options you&#8217;ll need, make sure those prerequisites are installed, as well. Run the configure script in the PHP source directory with everything you need enabled. I find it helpful to create a script like <code>php.config</code> with the following format:</p>
<pre>'./configure' \
'--with-cgi' \
'--with-fastcgi' \
'--with-gd' \
...
'--with-xml' \
"$@"</pre>
<p class="note">You need to include the slashes <code>\</code> at the end of every line. The last line, <code>"$@"</code> makes the script output the output of <code>configure</code>.</p>
<p>If you get an error running <code>make</code>, you may need to edit your <code>Makefile</code>. Find the <code>EXTRA_LIBS</code> section (in vi/vim, type <code>&lt;ctrl-c&gt; /EXTRA_LIBS &lt;return&gt;</code>) and add <code>-liconv</code> to the end of the line. Then try <code>make clean &amp;&amp; make</code> and it should work.</p>
<p>You may or may not have to edit your <code>httpd.conf</code>, after running <code>make install</code> from the PHP source directory, to add the <code>AddType</code> or <code>AddHandler</code> directive for PHP.</p>
<p>That should be it. You can install extensions via PECL or Pear and everything should run. Save the source directory and your <code>php.config</code> (or <code>config.nice</code>) file, and you&#8217;ll be able to recompile at any time, in case you forgot something. (I, for example, forgot to add <code>--with-mysql</code> the first time!)</p>
<p>Let me know if you run into other problems. Most can be solved by typing <code>yum install ###-devel</code> to resolve a dependency, but if not, I&#8217;ve done this enough to be of some help.</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/how-to-upgrade-or-recompile-php-on-rhel5-59/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

